Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "base/cpu.h" |
Jan Wilken Dörrie | b5a41c3 | 2020-12-09 18:55:47 | [diff] [blame] | 6 | #include "base/containers/contains.h" |
Richard Townsend | 8cb7ba0b | 2020-11-26 23:23:22 | [diff] [blame] | 7 | #include "base/logging.h" |
Robert Sesek | fd71c38 | 2021-01-14 18:40:52 | [diff] [blame] | 8 | #include "base/strings/string_util.h" |
[email protected] | d1811bc | 2012-03-31 07:08:53 | [diff] [blame] | 9 | #include "build/build_config.h" |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 10 | #include "testing/gtest/include/gtest/gtest.h" |
| 11 | |
| 12 | // Tests whether we can run extended instructions represented by the CPU |
| 13 | // information. This test actually executes some extended instructions (such as |
| 14 | // MMX, SSE, etc.) supported by the CPU and sees we can run them without |
| 15 | // "undefined instruction" exceptions. That is, this test succeeds when this |
| 16 | // test finishes without a crash. |
| 17 | TEST(CPU, RunExtendedInstructions) { |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 18 | // Retrieve the CPU information. |
| 19 | base::CPU cpu; |
Richard Townsend | 8cb7ba0b | 2020-11-26 23:23:22 | [diff] [blame] | 20 | #if defined(ARCH_CPU_X86_FAMILY) |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 21 | |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 22 | ASSERT_TRUE(cpu.has_mmx()); |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 23 | ASSERT_TRUE(cpu.has_sse()); |
| 24 | ASSERT_TRUE(cpu.has_sse2()); |
Victor Costan | 5bb2864 | 2020-11-14 06:42:49 | [diff] [blame] | 25 | ASSERT_TRUE(cpu.has_sse3()); |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 26 | |
fbarchard | 20028e6 | 2015-10-06 17:26:26 | [diff] [blame] | 27 | // GCC and clang instruction test. |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 28 | #if defined(COMPILER_GCC) |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 29 | // Execute an MMX instruction. |
| 30 | __asm__ __volatile__("emms\n" : : : "mm0"); |
| 31 | |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 32 | // Execute an SSE instruction. |
| 33 | __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0"); |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 34 | |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 35 | // Execute an SSE 2 instruction. |
| 36 | __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0"); |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 37 | |
Victor Costan | 5bb2864 | 2020-11-14 06:42:49 | [diff] [blame] | 38 | // Execute an SSE 3 instruction. |
| 39 | __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0"); |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 40 | |
| 41 | if (cpu.has_ssse3()) { |
| 42 | // Execute a Supplimental SSE 3 instruction. |
| 43 | __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0"); |
| 44 | } |
| 45 | |
| 46 | if (cpu.has_sse41()) { |
| 47 | // Execute an SSE 4.1 instruction. |
| 48 | __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0"); |
| 49 | } |
| 50 | |
| 51 | if (cpu.has_sse42()) { |
| 52 | // Execute an SSE 4.2 instruction. |
| 53 | __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax"); |
| 54 | } |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 55 | |
ilevy | b7d2f408 | 2016-10-30 20:46:57 | [diff] [blame] | 56 | if (cpu.has_popcnt()) { |
| 57 | // Execute a POPCNT instruction. |
| 58 | __asm__ __volatile__("popcnt %%eax, %%eax\n" : : : "eax"); |
| 59 | } |
| 60 | |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 61 | if (cpu.has_avx()) { |
| 62 | // Execute an AVX instruction. |
| 63 | __asm__ __volatile__("vzeroupper\n" : : : "xmm0"); |
| 64 | } |
| 65 | |
Ng Zhi An | 03baf5e | 2021-10-04 22:56:52 | [diff] [blame] | 66 | if (cpu.has_fma3()) { |
| 67 | // Execute a FMA3 instruction. |
| 68 | __asm__ __volatile__("vfmadd132ps %%xmm0, %%xmm0, %%xmm0\n" : : : "xmm0"); |
| 69 | } |
| 70 | |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 71 | if (cpu.has_avx2()) { |
| 72 | // Execute an AVX 2 instruction. |
| 73 | __asm__ __volatile__("vpunpcklbw %%ymm0, %%ymm0, %%ymm0\n" : : : "xmm0"); |
| 74 | } |
Stephen Roettger | 6f1a424 | 2022-10-07 10:04:25 | [diff] [blame] | 75 | |
| 76 | if (cpu.has_pku()) { |
| 77 | // rdpkru |
| 78 | uint32_t pkru; |
| 79 | __asm__ __volatile__(".byte 0x0f,0x01,0xee\n" |
| 80 | : "=a"(pkru) |
| 81 | : "c"(0), "d"(0)); |
| 82 | } |
fbarchard | 20028e6 | 2015-10-06 17:26:26 | [diff] [blame] | 83 | // Visual C 32 bit and ClangCL 32/64 bit test. |
| 84 | #elif defined(COMPILER_MSVC) && (defined(ARCH_CPU_32_BITS) || \ |
| 85 | (defined(ARCH_CPU_64_BITS) && defined(__clang__))) |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 86 | |
| 87 | // Execute an MMX instruction. |
| 88 | __asm emms; |
| 89 | |
| 90 | // Execute an SSE instruction. |
| 91 | __asm xorps xmm0, xmm0; |
| 92 | |
| 93 | // Execute an SSE 2 instruction. |
| 94 | __asm psrldq xmm0, 0; |
| 95 | |
Victor Costan | 5bb2864 | 2020-11-14 06:42:49 | [diff] [blame] | 96 | // Execute an SSE 3 instruction. |
| 97 | __asm addsubpd xmm0, xmm0; |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 98 | |
| 99 | if (cpu.has_ssse3()) { |
| 100 | // Execute a Supplimental SSE 3 instruction. |
| 101 | __asm psignb xmm0, xmm0; |
| 102 | } |
| 103 | |
| 104 | if (cpu.has_sse41()) { |
| 105 | // Execute an SSE 4.1 instruction. |
| 106 | __asm pmuldq xmm0, xmm0; |
| 107 | } |
| 108 | |
| 109 | if (cpu.has_sse42()) { |
| 110 | // Execute an SSE 4.2 instruction. |
| 111 | __asm crc32 eax, eax; |
| 112 | } |
| 113 | |
ilevy | b7d2f408 | 2016-10-30 20:46:57 | [diff] [blame] | 114 | if (cpu.has_popcnt()) { |
| 115 | // Execute a POPCNT instruction. |
| 116 | __asm popcnt eax, eax; |
| 117 | } |
| 118 | |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 119 | if (cpu.has_avx()) { |
| 120 | // Execute an AVX instruction. |
| 121 | __asm vzeroupper; |
| 122 | } |
| 123 | |
Ng Zhi An | 03baf5e | 2021-10-04 22:56:52 | [diff] [blame] | 124 | if (cpu.has_fma3()) { |
| 125 | // Execute an AVX instruction. |
| 126 | __asm vfmadd132ps xmm0, xmm0, xmm0; |
| 127 | } |
| 128 | |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 129 | if (cpu.has_avx2()) { |
| 130 | // Execute an AVX 2 instruction. |
| 131 | __asm vpunpcklbw ymm0, ymm0, ymm0 |
| 132 | } |
fbarchard | 0ce41ae | 2015-10-02 03:23:19 | [diff] [blame] | 133 | #endif // defined(COMPILER_GCC) |
| 134 | #endif // defined(ARCH_CPU_X86_FAMILY) |
Richard Townsend | 8cb7ba0b | 2020-11-26 23:23:22 | [diff] [blame] | 135 | |
| 136 | #if defined(ARCH_CPU_ARM64) |
| 137 | // Check that the CPU is correctly reporting support for the Armv8.5-A memory |
| 138 | // tagging extension. The new MTE instructions aren't encoded in NOP space |
| 139 | // like BTI/Pointer Authentication and will crash older cores with a SIGILL if |
| 140 | // used incorrectly. This test demonstrates how it should be done and that |
| 141 | // this approach works. |
| 142 | if (cpu.has_mte()) { |
| 143 | #if !defined(__ARM_FEATURE_MEMORY_TAGGING) |
| 144 | // In this section, we're running on an MTE-compatible core, but we're |
| 145 | // building this file without MTE support. Fail this test to indicate that |
| 146 | // there's a problem with the base/ build configuration. |
| 147 | GTEST_FAIL() |
| 148 | << "MTE support detected (but base/ built without MTE support)"; |
| 149 | #else |
| 150 | char ptr[32]; |
| 151 | uint64_t val; |
| 152 | // Execute a trivial MTE instruction. Normally, MTE should be used via the |
| 153 | // intrinsics documented at |
| 154 | // https://developer.arm.com/documentation/101028/0012/10--Memory-tagging-intrinsics, |
| 155 | // this test uses the irg (Insert Random Tag) instruction directly to make |
| 156 | // sure that it's not optimized out by the compiler. |
| 157 | __asm__ __volatile__("irg %0, %1" : "=r"(val) : "r"(ptr)); |
| 158 | #endif // __ARM_FEATURE_MEMORY_TAGGING |
Richard Townsend | 8cb7ba0b | 2020-11-26 23:23:22 | [diff] [blame] | 159 | } |
| 160 | #endif // ARCH_CPU_ARM64 |
[email protected] | 14cd2e6 | 2011-02-24 09:20:16 | [diff] [blame] | 161 | } |
Lei Zhang | 49c4b2a | 2017-11-03 21:34:23 | [diff] [blame] | 162 | |
| 163 | // For https://crbug.com/249713 |
| 164 | TEST(CPU, BrandAndVendorContainsNoNUL) { |
| 165 | base::CPU cpu; |
Jan Wilken Dörrie | f61e74c | 2019-06-07 08:20:02 | [diff] [blame] | 166 | EXPECT_FALSE(base::Contains(cpu.cpu_brand(), '\0')); |
| 167 | EXPECT_FALSE(base::Contains(cpu.vendor_name(), '\0')); |
Lei Zhang | 49c4b2a | 2017-11-03 21:34:23 | [diff] [blame] | 168 | } |
Gabriel Marin | 8fdd777 | 2019-08-17 00:28:09 | [diff] [blame] | 169 | |
| 170 | #if defined(ARCH_CPU_X86_FAMILY) |
| 171 | // Tests that we compute the correct CPU family and model based on the vendor |
| 172 | // and CPUID signature. |
| 173 | TEST(CPU, X86FamilyAndModel) { |
Lei Zhang | 1b1116c5 | 2021-05-14 22:54:38 | [diff] [blame] | 174 | base::internal::X86ModelInfo info; |
Gabriel Marin | 8fdd777 | 2019-08-17 00:28:09 | [diff] [blame] | 175 | |
| 176 | // Check with an Intel Skylake signature. |
Lei Zhang | 1b1116c5 | 2021-05-14 22:54:38 | [diff] [blame] | 177 | info = base::internal::ComputeX86FamilyAndModel("GenuineIntel", 0x000406e3); |
| 178 | EXPECT_EQ(info.family, 6); |
| 179 | EXPECT_EQ(info.model, 78); |
| 180 | EXPECT_EQ(info.ext_family, 0); |
| 181 | EXPECT_EQ(info.ext_model, 4); |
Gabriel Marin | 8fdd777 | 2019-08-17 00:28:09 | [diff] [blame] | 182 | |
| 183 | // Check with an Intel Airmont signature. |
Lei Zhang | 1b1116c5 | 2021-05-14 22:54:38 | [diff] [blame] | 184 | info = base::internal::ComputeX86FamilyAndModel("GenuineIntel", 0x000406c2); |
| 185 | EXPECT_EQ(info.family, 6); |
| 186 | EXPECT_EQ(info.model, 76); |
| 187 | EXPECT_EQ(info.ext_family, 0); |
| 188 | EXPECT_EQ(info.ext_model, 4); |
Gabriel Marin | 8fdd777 | 2019-08-17 00:28:09 | [diff] [blame] | 189 | |
| 190 | // Check with an Intel Prescott signature. |
Lei Zhang | 1b1116c5 | 2021-05-14 22:54:38 | [diff] [blame] | 191 | info = base::internal::ComputeX86FamilyAndModel("GenuineIntel", 0x00000f31); |
| 192 | EXPECT_EQ(info.family, 15); |
| 193 | EXPECT_EQ(info.model, 3); |
| 194 | EXPECT_EQ(info.ext_family, 0); |
| 195 | EXPECT_EQ(info.ext_model, 0); |
Gabriel Marin | 8fdd777 | 2019-08-17 00:28:09 | [diff] [blame] | 196 | |
| 197 | // Check with an AMD Excavator signature. |
Lei Zhang | 1b1116c5 | 2021-05-14 22:54:38 | [diff] [blame] | 198 | info = base::internal::ComputeX86FamilyAndModel("AuthenticAMD", 0x00670f00); |
| 199 | EXPECT_EQ(info.family, 21); |
| 200 | EXPECT_EQ(info.model, 112); |
| 201 | EXPECT_EQ(info.ext_family, 6); |
| 202 | EXPECT_EQ(info.ext_model, 7); |
Gabriel Marin | 8fdd777 | 2019-08-17 00:28:09 | [diff] [blame] | 203 | } |
| 204 | #endif // defined(ARCH_CPU_X86_FAMILY) |
Robert Sesek | fd71c38 | 2021-01-14 18:40:52 | [diff] [blame] | 205 | |
| 206 | #if defined(ARCH_CPU_ARM_FAMILY) && \ |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 207 | (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)) |
Robert Sesek | fd71c38 | 2021-01-14 18:40:52 | [diff] [blame] | 208 | TEST(CPU, ARMImplementerAndPartNumber) { |
| 209 | base::CPU cpu; |
| 210 | |
| 211 | const std::string& cpu_brand = cpu.cpu_brand(); |
| 212 | |
Robert Sesek | 98815586 | 2021-01-15 18:32:07 | [diff] [blame] | 213 | // Some devices, including on the CQ, do not report a cpu_brand |
| 214 | // https://crbug.com/1166533 and https://crbug.com/1167123. |
Robert Sesek | fd71c38 | 2021-01-14 18:40:52 | [diff] [blame] | 215 | EXPECT_EQ(cpu_brand, base::TrimWhitespaceASCII(cpu_brand, base::TRIM_ALL)); |
| 216 | EXPECT_GT(cpu.implementer(), 0u); |
| 217 | EXPECT_GT(cpu.part_number(), 0u); |
| 218 | } |
Xiaohan Wang | 38e4ebb | 2022-01-19 06:57:43 | [diff] [blame] | 219 | #endif // defined(ARCH_CPU_ARM_FAMILY) && (BUILDFLAG(IS_LINUX) || |
| 220 | // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)) |