1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved. 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 "CPUID.hpp" 16 17 #if defined(_WIN32) 18 #ifndef WIN32_LEAN_AND_MEAN 19 #define WIN32_LEAN_AND_MEAN 20 #endif 21 #include <windows.h> 22 #include <intrin.h> 23 #include <float.h> 24 #else 25 #include <unistd.h> 26 #include <sched.h> 27 #include <sys/types.h> 28 #endif 29 30 namespace sw 31 { 32 bool CPUID::MMX = detectMMX(); 33 bool CPUID::CMOV = detectCMOV(); 34 bool CPUID::SSE = detectSSE(); 35 bool CPUID::SSE2 = detectSSE2(); 36 bool CPUID::SSE3 = detectSSE3(); 37 bool CPUID::SSSE3 = detectSSSE3(); 38 bool CPUID::SSE4_1 = detectSSE4_1(); 39 int CPUID::cores = detectCoreCount(); 40 int CPUID::affinity = detectAffinity(); 41 42 bool CPUID::enableMMX = true; 43 bool CPUID::enableCMOV = true; 44 bool CPUID::enableSSE = true; 45 bool CPUID::enableSSE2 = true; 46 bool CPUID::enableSSE3 = true; 47 bool CPUID::enableSSSE3 = true; 48 bool CPUID::enableSSE4_1 = true; 49 50 void CPUID::setEnableMMX(bool enable) 51 { 52 enableMMX = enable; 53 54 if(!enableMMX) 55 { 56 enableSSE = false; 57 enableSSE2 = false; 58 enableSSE3 = false; 59 enableSSSE3 = false; 60 enableSSE4_1 = false; 61 } 62 } 63 64 void CPUID::setEnableCMOV(bool enable) 65 { 66 enableCMOV = enable; 67 68 if(!CMOV) 69 { 70 enableSSE = false; 71 enableSSE2 = false; 72 enableSSE3 = false; 73 enableSSSE3 = false; 74 enableSSE4_1 = false; 75 } 76 } 77 78 void CPUID::setEnableSSE(bool enable) 79 { 80 enableSSE = enable; 81 82 if(enableSSE) 83 { 84 enableMMX = true; 85 enableCMOV = true; 86 } 87 else 88 { 89 enableSSE2 = false; 90 enableSSE3 = false; 91 enableSSSE3 = false; 92 enableSSE4_1 = false; 93 } 94 } 95 96 void CPUID::setEnableSSE2(bool enable) 97 { 98 enableSSE2 = enable; 99 100 if(enableSSE2) 101 { 102 enableMMX = true; 103 enableCMOV = true; 104 enableSSE = true; 105 } 106 else 107 { 108 enableSSE3 = false; 109 enableSSSE3 = false; 110 enableSSE4_1 = false; 111 } 112 } 113 114 void CPUID::setEnableSSE3(bool enable) 115 { 116 enableSSE3 = enable; 117 118 if(enableSSE3) 119 { 120 enableMMX = true; 121 enableCMOV = true; 122 enableSSE = true; 123 enableSSE2 = true; 124 } 125 else 126 { 127 enableSSSE3 = false; 128 enableSSE4_1 = false; 129 } 130 } 131 132 void CPUID::setEnableSSSE3(bool enable) 133 { 134 enableSSSE3 = enable; 135 136 if(enableSSSE3) 137 { 138 enableMMX = true; 139 enableCMOV = true; 140 enableSSE = true; 141 enableSSE2 = true; 142 enableSSE3 = true; 143 } 144 else 145 { 146 enableSSE4_1 = false; 147 } 148 } 149 150 void CPUID::setEnableSSE4_1(bool enable) 151 { 152 enableSSE4_1 = enable; 153 154 if(enableSSE4_1) 155 { 156 enableMMX = true; 157 enableCMOV = true; 158 enableSSE = true; 159 enableSSE2 = true; 160 enableSSE3 = true; 161 enableSSSE3 = true; 162 } 163 } 164 165 static void cpuid(int registers[4], int info) 166 { 167 #if defined(_WIN32) 168 __cpuid(registers, info); 169 #else 170 __asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info)); 171 #endif 172 } 173 174 bool CPUID::detectMMX() 175 { 176 int registers[4]; 177 cpuid(registers, 1); 178 return MMX = (registers[3] & 0x00800000) != 0; 179 } 180 181 bool CPUID::detectCMOV() 182 { 183 int registers[4]; 184 cpuid(registers, 1); 185 return CMOV = (registers[3] & 0x00008000) != 0; 186 } 187 188 bool CPUID::detectSSE() 189 { 190 int registers[4]; 191 cpuid(registers, 1); 192 return SSE = (registers[3] & 0x02000000) != 0; 193 } 194 195 bool CPUID::detectSSE2() 196 { 197 int registers[4]; 198 cpuid(registers, 1); 199 return SSE2 = (registers[3] & 0x04000000) != 0; 200 } 201 202 bool CPUID::detectSSE3() 203 { 204 int registers[4]; 205 cpuid(registers, 1); 206 return SSE3 = (registers[2] & 0x00000001) != 0; 207 } 208 209 bool CPUID::detectSSSE3() 210 { 211 int registers[4]; 212 cpuid(registers, 1); 213 return SSSE3 = (registers[2] & 0x00000200) != 0; 214 } 215 216 bool CPUID::detectSSE4_1() 217 { 218 int registers[4]; 219 cpuid(registers, 1); 220 return SSE4_1 = (registers[2] & 0x00080000) != 0; 221 } 222 223 int CPUID::detectCoreCount() 224 { 225 int cores = 0; 226 227 #if defined(_WIN32) 228 DWORD_PTR processAffinityMask = 1; 229 DWORD_PTR systemAffinityMask = 1; 230 231 GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); 232 233 while(systemAffinityMask) 234 { 235 if(systemAffinityMask & 1) 236 { 237 cores++; 238 } 239 240 systemAffinityMask >>= 1; 241 } 242 #else 243 cores = sysconf(_SC_NPROCESSORS_ONLN); 244 #endif 245 246 if(cores < 1) cores = 1; 247 if(cores > 16) cores = 16; 248 249 return cores; // FIXME: Number of physical cores 250 } 251 252 int CPUID::detectAffinity() 253 { 254 int cores = 0; 255 256 #if defined(_WIN32) 257 DWORD_PTR processAffinityMask = 1; 258 DWORD_PTR systemAffinityMask = 1; 259 260 GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask); 261 262 while(processAffinityMask) 263 { 264 if(processAffinityMask & 1) 265 { 266 cores++; 267 } 268 269 processAffinityMask >>= 1; 270 } 271 #else 272 return detectCoreCount(); // FIXME: Assumes no affinity limitation 273 #endif 274 275 if(cores < 1) cores = 1; 276 if(cores > 16) cores = 16; 277 278 return cores; 279 } 280 281 void CPUID::setFlushToZero(bool enable) 282 { 283 #if defined(_MSC_VER) 284 _controlfp(enable ? _DN_FLUSH : _DN_SAVE, _MCW_DN); 285 #else 286 // Unimplemented 287 #endif 288 } 289 290 void CPUID::setDenormalsAreZero(bool enable) 291 { 292 // Unimplemented 293 } 294 } 295