Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/tools/source/misc/cpuid.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 */
10
11
#include <tools/cpuid.hxx>
12
#include <cstdint>
13
14
namespace cpuid
15
{
16
namespace
17
{
18
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
19
#include <intrin.h>
20
void getCpuId(uint32_t array[4], uint32_t nInfoType)
21
{
22
    __cpuid(reinterpret_cast<int*>(array), nInfoType);
23
}
24
#elif (defined(__i386__) || defined(__x86_64__))
25
#include <cpuid.h>
26
void getCpuId(uint32_t array[4], uint32_t nInfoType)
27
66
{
28
66
    __cpuid_count(nInfoType, 0, *(array + 0), *(array + 1), *(array + 2), *(array + 3));
29
66
}
30
#else
31
void getCpuId(uint32_t array[4], uint32_t /*nInfoType*/)
32
{
33
    array[0] = array[1] = array[2] = array[3] = 0;
34
}
35
#endif
36
37
// For AVX we need to check if OS has support for ymm registers
38
bool checkAVXSupportInOS()
39
22
{
40
22
    uint32_t xcr0 = 0;
41
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64))
42
    xcr0 = uint32_t(_xgetbv(0));
43
#elif (defined(__i386__) || defined(__x86_64__))
44
    __asm__("xgetbv" : "=a"(xcr0) : "c"(0) : "%edx");
45
22
#endif
46
22
    return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */
47
22
}
48
49
} // end anonymous namespace
50
51
22
#define HYPER_bit (1 << 28)
52
22
#define SSE2_bit (1 << 26)
53
22
#define SSSE3_bit (1 << 9)
54
22
#define SSE41_bit (1 << 19)
55
22
#define SSE42_bit (1 << 20)
56
22
#define XSAVE_bit (1 << 27)
57
22
#define AVX_bit (1 << 28)
58
22
#define AVX2_bit (1 << 5)
59
22
#define AVX512F_bit (1 << 16)
60
61
InstructionSetFlags getCpuInstructionSetFlags()
62
22
{
63
22
    InstructionSetFlags eInstructions = InstructionSetFlags::NONE;
64
65
22
    uint32_t info[] = { 0, 0, 0, 0 };
66
22
    getCpuId(info, 0);
67
22
    int nLevel = info[0];
68
69
22
    if (nLevel >= 1)
70
22
    {
71
22
        uint32_t aCpuInfoArray[] = { 0, 0, 0, 0 };
72
22
        getCpuId(aCpuInfoArray, 1);
73
74
22
        if ((aCpuInfoArray[3] & HYPER_bit) != 0)
75
22
            eInstructions |= InstructionSetFlags::HYPER;
76
77
22
        if ((aCpuInfoArray[3] & SSE2_bit) != 0)
78
22
            eInstructions |= InstructionSetFlags::SSE2;
79
80
22
        if ((aCpuInfoArray[2] & SSSE3_bit) != 0)
81
22
            eInstructions |= InstructionSetFlags::SSSE3;
82
83
22
        if ((aCpuInfoArray[2] & SSE41_bit) != 0)
84
22
            eInstructions |= InstructionSetFlags::SSE41;
85
86
22
        if ((aCpuInfoArray[2] & SSE42_bit) != 0)
87
22
            eInstructions |= InstructionSetFlags::SSE42;
88
89
22
        if (((aCpuInfoArray[2] & AVX_bit) != 0) && ((aCpuInfoArray[2] & XSAVE_bit) != 0))
90
22
        {
91
22
            if (checkAVXSupportInOS())
92
22
            {
93
22
                eInstructions |= InstructionSetFlags::AVX;
94
95
22
                if (nLevel >= 7)
96
22
                {
97
22
                    uint32_t aExtendedInfo[] = { 0, 0, 0, 0 };
98
22
                    getCpuId(aExtendedInfo, 7);
99
100
22
                    if ((aExtendedInfo[1] & AVX2_bit) != 0)
101
22
                        eInstructions |= InstructionSetFlags::AVX2;
102
22
                    if ((aExtendedInfo[1] & AVX512F_bit) != 0)
103
0
                        eInstructions |= InstructionSetFlags::AVX512F;
104
22
                }
105
22
            }
106
22
        }
107
22
    }
108
109
22
    return eInstructions;
110
22
}
111
112
bool isCpuInstructionSetSupported(InstructionSetFlags eInstructions)
113
22
{
114
22
    static InstructionSetFlags eCPUFlags = getCpuInstructionSetFlags();
115
22
    return (eCPUFlags & eInstructions) == eInstructions;
116
22
}
117
118
OUString instructionSetSupportedString()
119
0
{
120
0
    OUString aString;
121
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::SSE2))
122
0
        aString += "SSE2 ";
123
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::SSSE3))
124
0
        aString += "SSSE3 ";
125
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::SSE41))
126
0
        aString += "SSE4.1 ";
127
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::SSE42))
128
0
        aString += "SSE4.2 ";
129
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::AVX))
130
0
        aString += "AVX ";
131
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::AVX2))
132
0
        aString += "AVX2 ";
133
0
    if (isCpuInstructionSetSupported(InstructionSetFlags::AVX512F))
134
0
        aString += "AVX512F ";
135
0
    return aString;
136
0
}
137
138
} // end cpuid
139
140
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */