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 <android-base/logging.h>
23 #include <android-base/stringprintf.h>
24 #include <android-base/strings.h>
25
26 #include "arch/x86_64/instruction_set_features_x86_64.h"
27
28 namespace art {
29
30 using android::base::StringPrintf;
31
32 // Feature-support arrays.
33
34 static constexpr const char* x86_known_variants[] = {
35 "atom",
36 "sandybridge",
37 "silvermont",
38 "kabylake",
39 };
40
41 static constexpr const char* x86_variants_with_ssse3[] = {
42 "atom",
43 "sandybridge",
44 "silvermont",
45 "kabylake",
46 };
47
48 static constexpr const char* x86_variants_with_sse4_1[] = {
49 "sandybridge",
50 "silvermont",
51 "kabylake",
52 };
53
54 static constexpr const char* x86_variants_with_sse4_2[] = {
55 "sandybridge",
56 "silvermont",
57 "kabylake",
58 };
59
60 static constexpr const char* x86_variants_with_popcnt[] = {
61 "sandybridge",
62 "silvermont",
63 "kabylake",
64 };
65 static constexpr const char* x86_variants_with_avx[] = {
66 "kabylake",
67 };
68
69 static constexpr const char* x86_variants_with_avx2[] = {
70 "kabylake",
71 };
72
Create(bool x86_64,bool has_SSSE3,bool has_SSE4_1,bool has_SSE4_2,bool has_AVX,bool has_AVX2,bool has_POPCNT)73 X86FeaturesUniquePtr X86InstructionSetFeatures::Create(bool x86_64,
74 bool has_SSSE3,
75 bool has_SSE4_1,
76 bool has_SSE4_2,
77 bool has_AVX,
78 bool has_AVX2,
79 bool has_POPCNT) {
80 if (x86_64) {
81 return X86FeaturesUniquePtr(new X86_64InstructionSetFeatures(has_SSSE3,
82 has_SSE4_1,
83 has_SSE4_2,
84 has_AVX,
85 has_AVX2,
86 has_POPCNT));
87 } else {
88 return X86FeaturesUniquePtr(new X86InstructionSetFeatures(has_SSSE3,
89 has_SSE4_1,
90 has_SSE4_2,
91 has_AVX,
92 has_AVX2,
93 has_POPCNT));
94 }
95 }
96
FromVariant(const std::string & variant,std::string * error_msg ATTRIBUTE_UNUSED,bool x86_64)97 X86FeaturesUniquePtr X86InstructionSetFeatures::FromVariant(
98 const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED,
99 bool x86_64) {
100 bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
101 variant);
102 bool has_SSE4_1 = FindVariantInArray(x86_variants_with_sse4_1,
103 arraysize(x86_variants_with_sse4_1),
104 variant);
105 bool has_SSE4_2 = FindVariantInArray(x86_variants_with_sse4_2,
106 arraysize(x86_variants_with_sse4_2),
107 variant);
108 bool has_AVX = FindVariantInArray(x86_variants_with_avx,
109 arraysize(x86_variants_with_avx),
110 variant);
111 bool has_AVX2 = FindVariantInArray(x86_variants_with_avx2,
112 arraysize(x86_variants_with_avx2),
113 variant);
114 bool has_POPCNT = FindVariantInArray(x86_variants_with_popcnt,
115 arraysize(x86_variants_with_popcnt),
116 variant);
117
118 // Verify that variant is known.
119 bool known_variant = FindVariantInArray(x86_known_variants, arraysize(x86_known_variants),
120 variant);
121 if (!known_variant && variant != "default") {
122 LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
123 }
124
125 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
126 }
127
FromBitmap(uint32_t bitmap,bool x86_64)128 X86FeaturesUniquePtr X86InstructionSetFeatures::FromBitmap(uint32_t bitmap, bool x86_64) {
129 bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
130 bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
131 bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
132 bool has_AVX = (bitmap & kAvxBitfield) != 0;
133 bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
134 bool has_POPCNT = (bitmap & kPopCntBitfield) != 0;
135 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
136 }
137
FromCppDefines(bool x86_64)138 X86FeaturesUniquePtr X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
139 #ifndef __SSSE3__
140 const bool has_SSSE3 = false;
141 #else
142 const bool has_SSSE3 = true;
143 #endif
144
145 #ifndef __SSE4_1__
146 const bool has_SSE4_1 = false;
147 #else
148 const bool has_SSE4_1 = true;
149 #endif
150
151 #ifndef __SSE4_2__
152 const bool has_SSE4_2 = false;
153 #else
154 const bool has_SSE4_2 = true;
155 #endif
156
157 #ifndef __AVX__
158 const bool has_AVX = false;
159 #else
160 const bool has_AVX = true;
161 #endif
162
163 #ifndef __AVX2__
164 const bool has_AVX2 = false;
165 #else
166 const bool has_AVX2 = true;
167 #endif
168
169 #ifndef __POPCNT__
170 const bool has_POPCNT = false;
171 #else
172 const bool has_POPCNT = true;
173 #endif
174
175 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
176 }
177
FromCpuInfo(bool x86_64)178 X86FeaturesUniquePtr X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
179 // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
180 // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
181 bool has_SSSE3 = false;
182 bool has_SSE4_1 = false;
183 bool has_SSE4_2 = false;
184 bool has_AVX = false;
185 bool has_AVX2 = false;
186 bool has_POPCNT = false;
187
188 std::ifstream in("/proc/cpuinfo");
189 if (!in.fail()) {
190 while (!in.eof()) {
191 std::string line;
192 std::getline(in, line);
193 if (!in.eof()) {
194 LOG(INFO) << "cpuinfo line: " << line;
195 if (line.find("flags") != std::string::npos) {
196 LOG(INFO) << "found flags";
197 if (line.find("ssse3") != std::string::npos) {
198 has_SSSE3 = true;
199 }
200 if (line.find("sse4_1") != std::string::npos) {
201 has_SSE4_1 = true;
202 }
203 if (line.find("sse4_2") != std::string::npos) {
204 has_SSE4_2 = true;
205 }
206 if (line.find("avx") != std::string::npos) {
207 has_AVX = true;
208 }
209 if (line.find("avx2") != std::string::npos) {
210 has_AVX2 = true;
211 }
212 if (line.find("popcnt") != std::string::npos) {
213 has_POPCNT = true;
214 }
215 }
216 }
217 }
218 in.close();
219 } else {
220 LOG(ERROR) << "Failed to open /proc/cpuinfo";
221 }
222 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
223 }
224
FromHwcap(bool x86_64)225 X86FeaturesUniquePtr X86InstructionSetFeatures::FromHwcap(bool x86_64) {
226 UNIMPLEMENTED(WARNING);
227 return FromCppDefines(x86_64);
228 }
229
FromAssembly(bool x86_64)230 X86FeaturesUniquePtr X86InstructionSetFeatures::FromAssembly(bool x86_64) {
231 UNIMPLEMENTED(WARNING);
232 return FromCppDefines(x86_64);
233 }
234
Equals(const InstructionSetFeatures * other) const235 bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
236 if (GetInstructionSet() != other->GetInstructionSet()) {
237 return false;
238 }
239 const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
240 return (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
241 (has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
242 (has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
243 (has_AVX_ == other_as_x86->has_AVX_) &&
244 (has_AVX2_ == other_as_x86->has_AVX2_) &&
245 (has_POPCNT_ == other_as_x86->has_POPCNT_);
246 }
247
HasAtLeast(const InstructionSetFeatures * other) const248 bool X86InstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const {
249 if (GetInstructionSet() != other->GetInstructionSet()) {
250 return false;
251 }
252 const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
253 return (has_SSSE3_ || !other_as_x86->has_SSSE3_) &&
254 (has_SSE4_1_ || !other_as_x86->has_SSE4_1_) &&
255 (has_SSE4_2_ || !other_as_x86->has_SSE4_2_) &&
256 (has_AVX_ || !other_as_x86->has_AVX_) &&
257 (has_AVX2_ || !other_as_x86->has_AVX2_) &&
258 (has_POPCNT_ || !other_as_x86->has_POPCNT_);
259 }
260
AsBitmap() const261 uint32_t X86InstructionSetFeatures::AsBitmap() const {
262 return (has_SSSE3_ ? kSsse3Bitfield : 0) |
263 (has_SSE4_1_ ? kSse4_1Bitfield : 0) |
264 (has_SSE4_2_ ? kSse4_2Bitfield : 0) |
265 (has_AVX_ ? kAvxBitfield : 0) |
266 (has_AVX2_ ? kAvx2Bitfield : 0) |
267 (has_POPCNT_ ? kPopCntBitfield : 0);
268 }
269
GetFeatureString() const270 std::string X86InstructionSetFeatures::GetFeatureString() const {
271 std::string result;
272 if (has_SSSE3_) {
273 result += "ssse3";
274 } else {
275 result += "-ssse3";
276 }
277 if (has_SSE4_1_) {
278 result += ",sse4.1";
279 } else {
280 result += ",-sse4.1";
281 }
282 if (has_SSE4_2_) {
283 result += ",sse4.2";
284 } else {
285 result += ",-sse4.2";
286 }
287 if (has_AVX_) {
288 result += ",avx";
289 } else {
290 result += ",-avx";
291 }
292 if (has_AVX2_) {
293 result += ",avx2";
294 } else {
295 result += ",-avx2";
296 }
297 if (has_POPCNT_) {
298 result += ",popcnt";
299 } else {
300 result += ",-popcnt";
301 }
302 return result;
303 }
304
AddFeaturesFromSplitString(const std::vector<std::string> & features,bool x86_64,std::string * error_msg) const305 std::unique_ptr<const InstructionSetFeatures> X86InstructionSetFeatures::AddFeaturesFromSplitString(
306 const std::vector<std::string>& features, bool x86_64,
307 std::string* error_msg) const {
308 bool has_SSSE3 = has_SSSE3_;
309 bool has_SSE4_1 = has_SSE4_1_;
310 bool has_SSE4_2 = has_SSE4_2_;
311 bool has_AVX = has_AVX_;
312 bool has_AVX2 = has_AVX2_;
313 bool has_POPCNT = has_POPCNT_;
314 for (const std::string& feature : features) {
315 DCHECK_EQ(android::base::Trim(feature), feature)
316 << "Feature name is not trimmed: '" << feature << "'";
317 if (feature == "ssse3") {
318 has_SSSE3 = true;
319 } else if (feature == "-ssse3") {
320 has_SSSE3 = false;
321 } else if (feature == "sse4.1") {
322 has_SSE4_1 = true;
323 } else if (feature == "-sse4.1") {
324 has_SSE4_1 = false;
325 } else if (feature == "sse4.2") {
326 has_SSE4_2 = true;
327 } else if (feature == "-sse4.2") {
328 has_SSE4_2 = false;
329 } else if (feature == "avx") {
330 has_AVX = true;
331 } else if (feature == "-avx") {
332 has_AVX = false;
333 } else if (feature == "avx2") {
334 has_AVX2 = true;
335 } else if (feature == "-avx2") {
336 has_AVX2 = false;
337 } else if (feature == "popcnt") {
338 has_POPCNT = true;
339 } else if (feature == "-popcnt") {
340 has_POPCNT = false;
341 } else {
342 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
343 return nullptr;
344 }
345 }
346 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
347 }
348
349 } // namespace art
350