CpuInfo.h#

Fully qualified name: carb/extras/CpuInfo.h

File members: carb/extras/CpuInfo.h

// SPDX-FileCopyrightText: Copyright (c) 2021-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: LicenseRef-NvidiaProprietary
//
// NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
// property and proprietary rights in and to this material, related
// documentation and any modifications thereto. Any use, reproduction,
// disclosure or distribution of this material and related documentation
// without an express license agreement from NVIDIA CORPORATION or
// its affiliates is strictly prohibited.

#pragma once

#include "../Architecture.h"
#include "../Compiler.h"

#include <array>
#include <cstdint>

#if CARB_X86_64
#    if CARB_COMPILER_MSC
extern "C"
{
    void __cpuid(int cpuInfo[4], int function_id);
}

#        pragma intrinsic(__cpuid)
#    elif CARB_COMPILER_GNUC
// for some strange reason, GCC's 'cpuid.h' header does not have an include guard of any
// kind.  This leads to multiple definition errors when the header is included twice in
// a translation unit.  To avoid this, we'll add our own external include guard here.
#        ifndef CARB_CPUID_H_INCLUDED
#            define CARB_CPUID_H_INCLUDED
#            include "cpuid.h"
#        endif
#    else
CARB_UNSUPPORTED_COMPILER();
#    endif
#endif

namespace carb::extras
{
namespace detail
{
#if CARB_X86_64
struct cpuid_output
{
    unsigned eax, ebx, ecx, edx;
};
inline cpuid_output cpuid(unsigned func)
{
#    if CARB_COMPILER_MSC
    int regs[4];
    __cpuid(regs, int(func));
    return { unsigned(regs[0]), unsigned(regs[1]), unsigned(regs[2]), unsigned(regs[3]) };
#    elif CARB_COMPILER_GNUC
    cpuid_output out = {};
    (void)__get_cpuid(func, &out.eax, &out.ebx, &out.ecx, &out.edx);
    return out;
#    else
    CARB_UNSUPPORTED_COMPILER();
#    endif
}
#endif
} // namespace detail

class CpuInfo
{
public:
    CpuInfo()
    {
#if CARB_X86_64
        m_data = detail::cpuid(kInfoType);
#endif
    }

    bool popcntSupported()
    {
#if CARB_X86_64
        return m_data.ecx & (1UL << kPopCountBit);
#else
        return false;
#endif
    }

private:
#if CARB_X86_64
    static constexpr uint32_t kInfoType = 0x00000001;
    static constexpr uint8_t kPopCountBit = 23;
    detail::cpuid_output m_data;
#endif
};
} // namespace carb::extras