1 // Copyright 2019 The libgav1 Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/utils/cpu.h"
16
17 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
18 #include <cpuid.h>
19 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
20 #include <immintrin.h> // _xgetbv
21 #include <intrin.h>
22 #endif
23
24 namespace libgav1 {
25
26 #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || \
27 defined(_M_X64)
28 namespace {
29
30 #if defined(__GNUC__)
CpuId(int leaf,uint32_t info[4])31 void CpuId(int leaf, uint32_t info[4]) {
32 __cpuid_count(leaf, 0 /*ecx=subleaf*/, info[0], info[1], info[2], info[3]);
33 }
34
Xgetbv()35 uint64_t Xgetbv() {
36 const uint32_t ecx = 0; // ecx specifies the extended control register
37 uint32_t eax;
38 uint32_t edx;
39 __asm__ volatile("xgetbv" : "=a"(eax), "=d"(edx) : "c"(ecx));
40 return (static_cast<uint64_t>(edx) << 32) | eax;
41 }
42 #else // _MSC_VER
43 void CpuId(int leaf, uint32_t info[4]) {
44 __cpuidex(reinterpret_cast<int*>(info), leaf, 0 /*ecx=subleaf*/);
45 }
46
47 uint64_t Xgetbv() { return _xgetbv(0); }
48 #endif // __GNUC__
49
50 } // namespace
51
GetCpuInfo()52 uint32_t GetCpuInfo() {
53 uint32_t info[4];
54
55 // Get the highest feature value cpuid supports
56 CpuId(0, info);
57 const int max_cpuid_value = info[0];
58 if (max_cpuid_value < 1) return 0;
59
60 CpuId(1, info);
61 uint32_t features = 0;
62 if ((info[3] & (1 << 26)) != 0) features |= kSSE2;
63 if ((info[2] & (1 << 9)) != 0) features |= kSSSE3;
64 if ((info[2] & (1 << 19)) != 0) features |= kSSE4_1;
65
66 // Bits 27 (OSXSAVE) & 28 (256-bit AVX)
67 if ((info[2] & (3 << 27)) == (3 << 27)) {
68 // XMM state and YMM state enabled by the OS
69 if ((Xgetbv() & 0x6) == 0x6) {
70 features |= kAVX;
71 if (max_cpuid_value >= 7) {
72 CpuId(7, info);
73 if ((info[1] & (1 << 5)) != 0) features |= kAVX2;
74 }
75 }
76 }
77
78 return features;
79 }
80 #else
81 uint32_t GetCpuInfo() { return 0; }
82 #endif // x86 || x86_64
83
84 } // namespace libgav1
85