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 rr
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 
40 	bool CPUID::enableMMX = true;
41 	bool CPUID::enableCMOV = true;
42 	bool CPUID::enableSSE = true;
43 	bool CPUID::enableSSE2 = true;
44 	bool CPUID::enableSSE3 = true;
45 	bool CPUID::enableSSSE3 = true;
46 	bool CPUID::enableSSE4_1 = true;
47 
setEnableMMX(bool enable)48 	void CPUID::setEnableMMX(bool enable)
49 	{
50 		enableMMX = enable;
51 
52 		if(!enableMMX)
53 		{
54 			enableSSE = false;
55 			enableSSE2 = false;
56 			enableSSE3 = false;
57 			enableSSSE3 = false;
58 			enableSSE4_1 = false;
59 		}
60 	}
61 
setEnableCMOV(bool enable)62 	void CPUID::setEnableCMOV(bool enable)
63 	{
64 		enableCMOV = enable;
65 
66 		if(!CMOV)
67 		{
68 			enableSSE = false;
69 			enableSSE2 = false;
70 			enableSSE3 = false;
71 			enableSSSE3 = false;
72 			enableSSE4_1 = false;
73 		}
74 	}
75 
setEnableSSE(bool enable)76 	void CPUID::setEnableSSE(bool enable)
77 	{
78 		enableSSE = enable;
79 
80 		if(enableSSE)
81 		{
82 			enableMMX = true;
83 			enableCMOV = true;
84 		}
85 		else
86 		{
87 			enableSSE2 = false;
88 			enableSSE3 = false;
89 			enableSSSE3 = false;
90 			enableSSE4_1 = false;
91 		}
92 	}
93 
setEnableSSE2(bool enable)94 	void CPUID::setEnableSSE2(bool enable)
95 	{
96 		enableSSE2 = enable;
97 
98 		if(enableSSE2)
99 		{
100 			enableMMX = true;
101 			enableCMOV = true;
102 			enableSSE = true;
103 		}
104 		else
105 		{
106 			enableSSE3 = false;
107 			enableSSSE3 = false;
108 			enableSSE4_1 = false;
109 		}
110 	}
111 
setEnableSSE3(bool enable)112 	void CPUID::setEnableSSE3(bool enable)
113 	{
114 		enableSSE3 = enable;
115 
116 		if(enableSSE3)
117 		{
118 			enableMMX = true;
119 			enableCMOV = true;
120 			enableSSE = true;
121 			enableSSE2 = true;
122 		}
123 		else
124 		{
125 			enableSSSE3 = false;
126 			enableSSE4_1 = false;
127 		}
128 	}
129 
setEnableSSSE3(bool enable)130 	void CPUID::setEnableSSSE3(bool enable)
131 	{
132 		enableSSSE3 = enable;
133 
134 		if(enableSSSE3)
135 		{
136 			enableMMX = true;
137 			enableCMOV = true;
138 			enableSSE = true;
139 			enableSSE2 = true;
140 			enableSSE3 = true;
141 		}
142 		else
143 		{
144 			enableSSE4_1 = false;
145 		}
146 	}
147 
setEnableSSE4_1(bool enable)148 	void CPUID::setEnableSSE4_1(bool enable)
149 	{
150 		enableSSE4_1 = enable;
151 
152 		if(enableSSE4_1)
153 		{
154 			enableMMX = true;
155 			enableCMOV = true;
156 			enableSSE = true;
157 			enableSSE2 = true;
158 			enableSSE3 = true;
159 			enableSSSE3 = true;
160 		}
161 	}
162 
cpuid(int registers[4],int info)163 	static void cpuid(int registers[4], int info)
164 	{
165 		#if defined(__i386__) || defined(__x86_64__)
166 			#if defined(_WIN32)
167 				__cpuid(registers, info);
168 			#else
169 				__asm volatile("cpuid": "=a" (registers[0]), "=b" (registers[1]), "=c" (registers[2]), "=d" (registers[3]): "a" (info));
170 			#endif
171 		#else
172 			registers[0] = 0;
173 			registers[1] = 0;
174 			registers[2] = 0;
175 			registers[3] = 0;
176 		#endif
177 	}
178 
detectMMX()179 	bool CPUID::detectMMX()
180 	{
181 		int registers[4];
182 		cpuid(registers, 1);
183 		return MMX = (registers[3] & 0x00800000) != 0;
184 	}
185 
detectCMOV()186 	bool CPUID::detectCMOV()
187 	{
188 		int registers[4];
189 		cpuid(registers, 1);
190 		return CMOV = (registers[3] & 0x00008000) != 0;
191 	}
192 
detectSSE()193 	bool CPUID::detectSSE()
194 	{
195 		int registers[4];
196 		cpuid(registers, 1);
197 		return SSE = (registers[3] & 0x02000000) != 0;
198 	}
199 
detectSSE2()200 	bool CPUID::detectSSE2()
201 	{
202 		int registers[4];
203 		cpuid(registers, 1);
204 		return SSE2 = (registers[3] & 0x04000000) != 0;
205 	}
206 
detectSSE3()207 	bool CPUID::detectSSE3()
208 	{
209 		int registers[4];
210 		cpuid(registers, 1);
211 		return SSE3 = (registers[2] & 0x00000001) != 0;
212 	}
213 
detectSSSE3()214 	bool CPUID::detectSSSE3()
215 	{
216 		int registers[4];
217 		cpuid(registers, 1);
218 		return SSSE3 = (registers[2] & 0x00000200) != 0;
219 	}
220 
detectSSE4_1()221 	bool CPUID::detectSSE4_1()
222 	{
223 		int registers[4];
224 		cpuid(registers, 1);
225 		return SSE4_1 = (registers[2] & 0x00080000) != 0;
226 	}
227 }
228