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 
setEnableMMX(bool enable)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 
setEnableCMOV(bool enable)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 
setEnableSSE(bool enable)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 
setEnableSSE2(bool enable)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 
setEnableSSE3(bool enable)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 
setEnableSSSE3(bool enable)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 
setEnableSSE4_1(bool enable)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 
cpuid(int registers[4],int info)165 static void cpuid(int registers[4], int info)
166 {
167 #if defined(__i386__) || defined(__x86_64__)
168 #	if defined(_WIN32)
169 	__cpuid(registers, info);
170 #	else
171 	__asm volatile("cpuid"
172 	               : "=a"(registers[0]), "=b"(registers[1]), "=c"(registers[2]), "=d"(registers[3])
173 	               : "a"(info));
174 #	endif
175 #else
176 	registers[0] = 0;
177 	registers[1] = 0;
178 	registers[2] = 0;
179 	registers[3] = 0;
180 #endif
181 }
182 
detectMMX()183 bool CPUID::detectMMX()
184 {
185 	int registers[4];
186 	cpuid(registers, 1);
187 	return MMX = (registers[3] & 0x00800000) != 0;
188 }
189 
detectCMOV()190 bool CPUID::detectCMOV()
191 {
192 	int registers[4];
193 	cpuid(registers, 1);
194 	return CMOV = (registers[3] & 0x00008000) != 0;
195 }
196 
detectSSE()197 bool CPUID::detectSSE()
198 {
199 	int registers[4];
200 	cpuid(registers, 1);
201 	return SSE = (registers[3] & 0x02000000) != 0;
202 }
203 
detectSSE2()204 bool CPUID::detectSSE2()
205 {
206 	int registers[4];
207 	cpuid(registers, 1);
208 	return SSE2 = (registers[3] & 0x04000000) != 0;
209 }
210 
detectSSE3()211 bool CPUID::detectSSE3()
212 {
213 	int registers[4];
214 	cpuid(registers, 1);
215 	return SSE3 = (registers[2] & 0x00000001) != 0;
216 }
217 
detectSSSE3()218 bool CPUID::detectSSSE3()
219 {
220 	int registers[4];
221 	cpuid(registers, 1);
222 	return SSSE3 = (registers[2] & 0x00000200) != 0;
223 }
224 
detectSSE4_1()225 bool CPUID::detectSSE4_1()
226 {
227 	int registers[4];
228 	cpuid(registers, 1);
229 	return SSE4_1 = (registers[2] & 0x00080000) != 0;
230 }
231 
detectCoreCount()232 int CPUID::detectCoreCount()
233 {
234 	int cores = 0;
235 
236 #if defined(_WIN32)
237 	DWORD_PTR processAffinityMask = 1;
238 	DWORD_PTR systemAffinityMask = 1;
239 
240 	GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
241 
242 	while(systemAffinityMask)
243 	{
244 		if(systemAffinityMask & 1)
245 		{
246 			cores++;
247 		}
248 
249 		systemAffinityMask >>= 1;
250 	}
251 #else
252 	cores = sysconf(_SC_NPROCESSORS_ONLN);
253 #endif
254 
255 	if(cores < 1) cores = 1;
256 	if(cores > 16) cores = 16;
257 
258 	return cores;  // FIXME: Number of physical cores
259 }
260 
detectAffinity()261 int CPUID::detectAffinity()
262 {
263 	int cores = 0;
264 
265 #if defined(_WIN32)
266 	DWORD_PTR processAffinityMask = 1;
267 	DWORD_PTR systemAffinityMask = 1;
268 
269 	GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
270 
271 	while(processAffinityMask)
272 	{
273 		if(processAffinityMask & 1)
274 		{
275 			cores++;
276 		}
277 
278 		processAffinityMask >>= 1;
279 	}
280 #else
281 	return detectCoreCount();  // FIXME: Assumes no affinity limitation
282 #endif
283 
284 	if(cores < 1) cores = 1;
285 	if(cores > 16) cores = 16;
286 
287 	return cores;
288 }
289 
setFlushToZero(bool enable)290 void CPUID::setFlushToZero(bool enable)
291 {
292 #if defined(_MSC_VER)
293 	_controlfp(enable ? _DN_FLUSH : _DN_SAVE, _MCW_DN);
294 #else
295 	                           // Unimplemented
296 #endif
297 }
298 
setDenormalsAreZero(bool enable)299 void CPUID::setDenormalsAreZero(bool enable)
300 {
301 	// Unimplemented
302 }
303 
304 }  // namespace sw
305