140 lines
4.1 KiB
C++
140 lines
4.1 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
*/
|
|
|
|
#include <tools/cpuid.hxx>
|
|
#include <cstdint>
|
|
|
|
namespace cpuid
|
|
{
|
|
namespace
|
|
{
|
|
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
|
|
#include <intrin.h>
|
|
void getCpuId(uint32_t array[4], uint32_t nInfoType)
|
|
{
|
|
__cpuid(reinterpret_cast<int*>(array), nInfoType);
|
|
}
|
|
#elif (defined(__i386__) || defined(__x86_64__))
|
|
#include <cpuid.h>
|
|
void getCpuId(uint32_t array[4], uint32_t nInfoType)
|
|
{
|
|
__cpuid_count(nInfoType, 0, *(array + 0), *(array + 1), *(array + 2), *(array + 3));
|
|
}
|
|
#else
|
|
void getCpuId(uint32_t array[4], uint32_t /*nInfoType*/)
|
|
{
|
|
array[0] = array[1] = array[2] = array[3] = 0;
|
|
}
|
|
#endif
|
|
|
|
// For AVX we need to check if OS has support for ymm registers
|
|
bool checkAVXSupportInOS()
|
|
{
|
|
uint32_t xcr0 = 0;
|
|
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
|
|
xcr0 = uint32_t(_xgetbv(0));
|
|
#elif (defined(__i386__) || defined(__x86_64__))
|
|
__asm__("xgetbv" : "=a"(xcr0) : "c"(0) : "%edx");
|
|
#endif
|
|
return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */
|
|
}
|
|
|
|
} // end anonymous namespace
|
|
|
|
#define HYPER_bit (1 << 28)
|
|
#define SSE2_bit (1 << 26)
|
|
#define SSSE3_bit (1 << 9)
|
|
#define SSE41_bit (1 << 19)
|
|
#define SSE42_bit (1 << 20)
|
|
#define XSAVE_bit (1 << 27)
|
|
#define AVX_bit (1 << 28)
|
|
#define AVX2_bit (1 << 5)
|
|
#define AVX512F_bit (1 << 16)
|
|
|
|
InstructionSetFlags getCpuInstructionSetFlags()
|
|
{
|
|
InstructionSetFlags eInstructions = InstructionSetFlags::NONE;
|
|
|
|
uint32_t info[] = { 0, 0, 0, 0 };
|
|
getCpuId(info, 0);
|
|
int nLevel = info[0];
|
|
|
|
if (nLevel >= 1)
|
|
{
|
|
uint32_t aCpuInfoArray[] = { 0, 0, 0, 0 };
|
|
getCpuId(aCpuInfoArray, 1);
|
|
|
|
if ((aCpuInfoArray[3] & HYPER_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::HYPER;
|
|
|
|
if ((aCpuInfoArray[3] & SSE2_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::SSE2;
|
|
|
|
if ((aCpuInfoArray[2] & SSSE3_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::SSSE3;
|
|
|
|
if ((aCpuInfoArray[2] & SSE41_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::SSE41;
|
|
|
|
if ((aCpuInfoArray[2] & SSE42_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::SSE42;
|
|
|
|
if (((aCpuInfoArray[2] & AVX_bit) != 0) && ((aCpuInfoArray[2] & XSAVE_bit) != 0))
|
|
{
|
|
if (checkAVXSupportInOS())
|
|
{
|
|
eInstructions |= InstructionSetFlags::AVX;
|
|
|
|
if (nLevel >= 7)
|
|
{
|
|
uint32_t aExtendedInfo[] = { 0, 0, 0, 0 };
|
|
getCpuId(aExtendedInfo, 7);
|
|
|
|
if ((aExtendedInfo[1] & AVX2_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::AVX2;
|
|
if ((aExtendedInfo[1] & AVX512F_bit) != 0)
|
|
eInstructions |= InstructionSetFlags::AVX512F;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return eInstructions;
|
|
}
|
|
|
|
bool isCpuInstructionSetSupported(InstructionSetFlags eInstructions)
|
|
{
|
|
static InstructionSetFlags eCPUFlags = getCpuInstructionSetFlags();
|
|
return (eCPUFlags & eInstructions) == eInstructions;
|
|
}
|
|
|
|
OUString instructionSetSupportedString()
|
|
{
|
|
OUString aString;
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::SSE2))
|
|
aString += "SSE2 ";
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::SSSE3))
|
|
aString += "SSSE3 ";
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::SSE41))
|
|
aString += "SSE4.1 ";
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::SSE42))
|
|
aString += "SSE4.2 ";
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::AVX))
|
|
aString += "AVX ";
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::AVX2))
|
|
aString += "AVX2 ";
|
|
if (isCpuInstructionSetSupported(InstructionSetFlags::AVX512F))
|
|
aString += "AVX512F ";
|
|
return aString;
|
|
}
|
|
|
|
} // end cpuid
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|