1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "instruction_set_features_x86.h"
18
19 #include <fstream>
20 #include <sstream>
21
22 #include "arch/x86_64/instruction_set_features_x86_64.h"
23 #include "base/stringprintf.h"
24 #include "utils.h" // For Trim.
25
26 namespace art {
27
28 // Feature-support arrays.
29
30 static constexpr const char* x86_known_variants[] = {
31 "atom",
32 "silvermont",
33 };
34
35 static constexpr const char* x86_variants_with_ssse3[] = {
36 "atom",
37 "silvermont",
38 };
39
40 static constexpr const char* x86_variants_with_sse4_1[] = {
41 "silvermont",
42 };
43
44 static constexpr const char* x86_variants_with_sse4_2[] = {
45 "silvermont",
46 };
47
FromVariant(const std::string & variant,std::string * error_msg ATTRIBUTE_UNUSED,bool x86_64)48 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromVariant(
49 const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED,
50 bool x86_64) {
51 bool smp = true; // Conservative default.
52 bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
53 variant);
54 bool has_SSE4_1 = FindVariantInArray(x86_variants_with_sse4_1,
55 arraysize(x86_variants_with_sse4_1),
56 variant);
57 bool has_SSE4_2 = FindVariantInArray(x86_variants_with_sse4_2,
58 arraysize(x86_variants_with_sse4_2),
59 variant);
60 bool has_AVX = false;
61 bool has_AVX2 = false;
62
63 bool known_variant = FindVariantInArray(x86_known_variants, arraysize(x86_known_variants),
64 variant);
65 if (!known_variant && variant != "default") {
66 LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
67 }
68
69 if (x86_64) {
70 return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
71 has_AVX2);
72 } else {
73 return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
74 has_AVX2);
75 }
76 }
77
FromBitmap(uint32_t bitmap,bool x86_64)78 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromBitmap(uint32_t bitmap,
79 bool x86_64) {
80 bool smp = (bitmap & kSmpBitfield) != 0;
81 bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
82 bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
83 bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
84 bool has_AVX = (bitmap & kAvxBitfield) != 0;
85 bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
86 if (x86_64) {
87 return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
88 } else {
89 return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
90 has_AVX2);
91 }
92 }
93
FromCppDefines(bool x86_64)94 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
95 const bool smp = true;
96
97 #ifndef __SSSE3__
98 const bool has_SSSE3 = false;
99 #else
100 const bool has_SSSE3 = true;
101 #endif
102
103 #ifndef __SSE4_1__
104 const bool has_SSE4_1 = false;
105 #else
106 const bool has_SSE4_1 = true;
107 #endif
108
109 #ifndef __SSE4_2__
110 const bool has_SSE4_2 = false;
111 #else
112 const bool has_SSE4_2 = true;
113 #endif
114
115 #ifndef __AVX__
116 const bool has_AVX = false;
117 #else
118 const bool has_AVX = true;
119 #endif
120
121 #ifndef __AVX2__
122 const bool has_AVX2 = false;
123 #else
124 const bool has_AVX2 = true;
125 #endif
126
127 if (x86_64) {
128 return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
129 } else {
130 return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
131 has_AVX2);
132 }
133 }
134
FromCpuInfo(bool x86_64)135 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
136 // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
137 // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
138 bool smp = false;
139 bool has_SSSE3 = false;
140 bool has_SSE4_1 = false;
141 bool has_SSE4_2 = false;
142 bool has_AVX = false;
143 bool has_AVX2 = false;
144
145 std::ifstream in("/proc/cpuinfo");
146 if (!in.fail()) {
147 while (!in.eof()) {
148 std::string line;
149 std::getline(in, line);
150 if (!in.eof()) {
151 LOG(INFO) << "cpuinfo line: " << line;
152 if (line.find("flags") != std::string::npos) {
153 LOG(INFO) << "found flags";
154 if (line.find("ssse3") != std::string::npos) {
155 has_SSSE3 = true;
156 }
157 if (line.find("sse4_1") != std::string::npos) {
158 has_SSE4_1 = true;
159 }
160 if (line.find("sse4_2") != std::string::npos) {
161 has_SSE4_2 = true;
162 }
163 if (line.find("avx") != std::string::npos) {
164 has_AVX = true;
165 }
166 if (line.find("avx2") != std::string::npos) {
167 has_AVX2 = true;
168 }
169 } else if (line.find("processor") != std::string::npos &&
170 line.find(": 1") != std::string::npos) {
171 smp = true;
172 }
173 }
174 }
175 in.close();
176 } else {
177 LOG(ERROR) << "Failed to open /proc/cpuinfo";
178 }
179 if (x86_64) {
180 return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2);
181 } else {
182 return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
183 has_AVX2);
184 }
185 }
186
FromHwcap(bool x86_64)187 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromHwcap(bool x86_64) {
188 UNIMPLEMENTED(WARNING);
189 return FromCppDefines(x86_64);
190 }
191
FromAssembly(bool x86_64)192 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromAssembly(bool x86_64) {
193 UNIMPLEMENTED(WARNING);
194 return FromCppDefines(x86_64);
195 }
196
Equals(const InstructionSetFeatures * other) const197 bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
198 if (GetInstructionSet() != other->GetInstructionSet()) {
199 return false;
200 }
201 const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
202 return (IsSmp() == other->IsSmp()) &&
203 (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
204 (has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
205 (has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
206 (has_AVX_ == other_as_x86->has_AVX_) &&
207 (has_AVX2_ == other_as_x86->has_AVX2_);
208 }
209
AsBitmap() const210 uint32_t X86InstructionSetFeatures::AsBitmap() const {
211 return (IsSmp() ? kSmpBitfield : 0) |
212 (has_SSSE3_ ? kSsse3Bitfield : 0) |
213 (has_SSE4_1_ ? kSse4_1Bitfield : 0) |
214 (has_SSE4_2_ ? kSse4_2Bitfield : 0) |
215 (has_AVX_ ? kAvxBitfield : 0) |
216 (has_AVX2_ ? kAvx2Bitfield : 0);
217 }
218
GetFeatureString() const219 std::string X86InstructionSetFeatures::GetFeatureString() const {
220 std::string result;
221 if (IsSmp()) {
222 result += "smp";
223 } else {
224 result += "-smp";
225 }
226 if (has_SSSE3_) {
227 result += ",ssse3";
228 } else {
229 result += ",-ssse3";
230 }
231 if (has_SSE4_1_) {
232 result += ",sse4.1";
233 } else {
234 result += ",-sse4.1";
235 }
236 if (has_SSE4_2_) {
237 result += ",sse4.2";
238 } else {
239 result += ",-sse4.2";
240 }
241 if (has_AVX_) {
242 result += ",avx";
243 } else {
244 result += ",-avx";
245 }
246 if (has_AVX2_) {
247 result += ",avx2";
248 } else {
249 result += ",-avx2";
250 }
251 return result;
252 }
253
AddFeaturesFromSplitString(const bool smp,const std::vector<std::string> & features,bool x86_64,std::string * error_msg) const254 const InstructionSetFeatures* X86InstructionSetFeatures::AddFeaturesFromSplitString(
255 const bool smp, const std::vector<std::string>& features, bool x86_64,
256 std::string* error_msg) const {
257 bool has_SSSE3 = has_SSSE3_;
258 bool has_SSE4_1 = has_SSE4_1_;
259 bool has_SSE4_2 = has_SSE4_2_;
260 bool has_AVX = has_AVX_;
261 bool has_AVX2 = has_AVX2_;
262 for (auto i = features.begin(); i != features.end(); i++) {
263 std::string feature = Trim(*i);
264 if (feature == "ssse3") {
265 has_SSSE3 = true;
266 } else if (feature == "-ssse3") {
267 has_SSSE3 = false;
268 } else if (feature == "sse4.1") {
269 has_SSE4_1 = true;
270 } else if (feature == "-sse4.1") {
271 has_SSE4_1 = false;
272 } else if (feature == "sse4.2") {
273 has_SSE4_2 = true;
274 } else if (feature == "-sse4.2") {
275 has_SSE4_2 = false;
276 } else if (feature == "avx") {
277 has_AVX = true;
278 } else if (feature == "-avx") {
279 has_AVX = false;
280 } else if (feature == "avx2") {
281 has_AVX2 = true;
282 } else if (feature == "-avx2") {
283 has_AVX2 = false;
284 } else {
285 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
286 return nullptr;
287 }
288 }
289 if (x86_64) {
290 return new X86_64InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
291 has_AVX2);
292 } else {
293 return new X86InstructionSetFeatures(smp, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX,
294 has_AVX2);
295 }
296 }
297
298 } // namespace art
299