blob: ea5a90d8ee0513e52c0d686d72f8ba92d6854113 [file] [log] [blame]
Ian Rogersd582fa42014-11-05 23:46:43 -08001/*
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
Andreas Gampe46ee31b2016-12-14 10:11:49 -080022#include "android-base/stringprintf.h"
Andreas Gampe9186ced2016-12-12 14:28:21 -080023#include "android-base/strings.h"
24
Ian Rogersd582fa42014-11-05 23:46:43 -080025#include "arch/x86_64/instruction_set_features_x86_64.h"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080026#include "base/logging.h"
Ian Rogersd582fa42014-11-05 23:46:43 -080027
28namespace art {
29
Andreas Gampe46ee31b2016-12-14 10:11:49 -080030using android::base::StringPrintf;
31
Andreas Gampe24a05f42015-04-03 13:46:54 -070032// Feature-support arrays.
33
34static constexpr const char* x86_known_variants[] = {
35 "atom",
Luis Hector Chavezb8bff092017-06-09 12:33:04 -070036 "sandybridge",
Andreas Gampe24a05f42015-04-03 13:46:54 -070037 "silvermont",
38};
39
40static constexpr const char* x86_variants_with_ssse3[] = {
41 "atom",
Luis Hector Chavezb8bff092017-06-09 12:33:04 -070042 "sandybridge",
Andreas Gampe24a05f42015-04-03 13:46:54 -070043 "silvermont",
44};
45
46static constexpr const char* x86_variants_with_sse4_1[] = {
Luis Hector Chavezb8bff092017-06-09 12:33:04 -070047 "sandybridge",
Andreas Gampe24a05f42015-04-03 13:46:54 -070048 "silvermont",
49};
50
51static constexpr const char* x86_variants_with_sse4_2[] = {
Luis Hector Chavezb8bff092017-06-09 12:33:04 -070052 "sandybridge",
Andreas Gampe24a05f42015-04-03 13:46:54 -070053 "silvermont",
54};
55
Aart Bik3f67e692016-01-15 14:35:12 -080056static constexpr const char* x86_variants_with_popcnt[] = {
Luis Hector Chavezb8bff092017-06-09 12:33:04 -070057 "sandybridge",
Aart Bik3f67e692016-01-15 14:35:12 -080058 "silvermont",
59};
60
Andreas Gampe0415b4e2015-01-06 15:17:07 -080061X86FeaturesUniquePtr X86InstructionSetFeatures::Create(bool x86_64,
Andreas Gampe0415b4e2015-01-06 15:17:07 -080062 bool has_SSSE3,
63 bool has_SSE4_1,
64 bool has_SSE4_2,
65 bool has_AVX,
66 bool has_AVX2,
67 bool has_POPCNT) {
68 if (x86_64) {
Serban Constantinescub595b402016-09-23 11:06:03 +010069 return X86FeaturesUniquePtr(new X86_64InstructionSetFeatures(has_SSSE3,
Andreas Gampe0415b4e2015-01-06 15:17:07 -080070 has_SSE4_1,
71 has_SSE4_2,
72 has_AVX,
73 has_AVX2,
74 has_POPCNT));
75 } else {
Serban Constantinescub595b402016-09-23 11:06:03 +010076 return X86FeaturesUniquePtr(new X86InstructionSetFeatures(has_SSSE3,
Andreas Gampe0415b4e2015-01-06 15:17:07 -080077 has_SSE4_1,
78 has_SSE4_2,
79 has_AVX,
80 has_AVX2,
81 has_POPCNT));
82 }
83}
84
85X86FeaturesUniquePtr X86InstructionSetFeatures::FromVariant(
Andreas Gampeca714582015-04-03 19:41:34 -070086 const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED,
Ian Rogersd582fa42014-11-05 23:46:43 -080087 bool x86_64) {
Ian Rogersd582fa42014-11-05 23:46:43 -080088 bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3),
89 variant);
Andreas Gampe24a05f42015-04-03 13:46:54 -070090 bool has_SSE4_1 = FindVariantInArray(x86_variants_with_sse4_1,
91 arraysize(x86_variants_with_sse4_1),
92 variant);
93 bool has_SSE4_2 = FindVariantInArray(x86_variants_with_sse4_2,
94 arraysize(x86_variants_with_sse4_2),
95 variant);
Ian Rogersd582fa42014-11-05 23:46:43 -080096 bool has_AVX = false;
97 bool has_AVX2 = false;
Andreas Gampe24a05f42015-04-03 13:46:54 -070098
Aart Bik3f67e692016-01-15 14:35:12 -080099 bool has_POPCNT = FindVariantInArray(x86_variants_with_popcnt,
100 arraysize(x86_variants_with_popcnt),
101 variant);
102
103 // Verify that variant is known.
Andreas Gampe24a05f42015-04-03 13:46:54 -0700104 bool known_variant = FindVariantInArray(x86_known_variants, arraysize(x86_known_variants),
105 variant);
Ian Rogersd582fa42014-11-05 23:46:43 -0800106 if (!known_variant && variant != "default") {
Ian Rogersd582fa42014-11-05 23:46:43 -0800107 LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant;
108 }
109
Serban Constantinescub595b402016-09-23 11:06:03 +0100110 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
Ian Rogersd582fa42014-11-05 23:46:43 -0800111}
112
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800113X86FeaturesUniquePtr X86InstructionSetFeatures::FromBitmap(uint32_t bitmap, bool x86_64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800114 bool has_SSSE3 = (bitmap & kSsse3Bitfield) != 0;
115 bool has_SSE4_1 = (bitmap & kSse4_1Bitfield) != 0;
116 bool has_SSE4_2 = (bitmap & kSse4_2Bitfield) != 0;
117 bool has_AVX = (bitmap & kAvxBitfield) != 0;
118 bool has_AVX2 = (bitmap & kAvxBitfield) != 0;
Aart Bik3f67e692016-01-15 14:35:12 -0800119 bool has_POPCNT = (bitmap & kPopCntBitfield) != 0;
Serban Constantinescub595b402016-09-23 11:06:03 +0100120 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
Ian Rogersd582fa42014-11-05 23:46:43 -0800121}
122
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800123X86FeaturesUniquePtr X86InstructionSetFeatures::FromCppDefines(bool x86_64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800124#ifndef __SSSE3__
125 const bool has_SSSE3 = false;
126#else
127 const bool has_SSSE3 = true;
128#endif
129
130#ifndef __SSE4_1__
131 const bool has_SSE4_1 = false;
132#else
133 const bool has_SSE4_1 = true;
134#endif
135
136#ifndef __SSE4_2__
137 const bool has_SSE4_2 = false;
138#else
139 const bool has_SSE4_2 = true;
140#endif
141
142#ifndef __AVX__
143 const bool has_AVX = false;
144#else
145 const bool has_AVX = true;
146#endif
147
148#ifndef __AVX2__
149 const bool has_AVX2 = false;
150#else
151 const bool has_AVX2 = true;
152#endif
153
Aart Bik715d06b2016-01-21 15:52:58 -0800154#ifndef __POPCNT__
Aart Bik3f67e692016-01-15 14:35:12 -0800155 const bool has_POPCNT = false;
Aart Bik715d06b2016-01-21 15:52:58 -0800156#else
157 const bool has_POPCNT = true;
158#endif
Aart Bik3f67e692016-01-15 14:35:12 -0800159
Serban Constantinescub595b402016-09-23 11:06:03 +0100160 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
Ian Rogersd582fa42014-11-05 23:46:43 -0800161}
162
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800163X86FeaturesUniquePtr X86InstructionSetFeatures::FromCpuInfo(bool x86_64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800164 // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that
165 // the kernel puts the appropriate feature flags in here. Sometimes it doesn't.
Ian Rogersd582fa42014-11-05 23:46:43 -0800166 bool has_SSSE3 = false;
167 bool has_SSE4_1 = false;
168 bool has_SSE4_2 = false;
169 bool has_AVX = false;
170 bool has_AVX2 = false;
Aart Bik3f67e692016-01-15 14:35:12 -0800171 bool has_POPCNT = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800172
173 std::ifstream in("/proc/cpuinfo");
174 if (!in.fail()) {
175 while (!in.eof()) {
176 std::string line;
177 std::getline(in, line);
178 if (!in.eof()) {
179 LOG(INFO) << "cpuinfo line: " << line;
180 if (line.find("flags") != std::string::npos) {
181 LOG(INFO) << "found flags";
182 if (line.find("ssse3") != std::string::npos) {
183 has_SSSE3 = true;
184 }
185 if (line.find("sse4_1") != std::string::npos) {
186 has_SSE4_1 = true;
187 }
188 if (line.find("sse4_2") != std::string::npos) {
189 has_SSE4_2 = true;
190 }
191 if (line.find("avx") != std::string::npos) {
192 has_AVX = true;
193 }
194 if (line.find("avx2") != std::string::npos) {
195 has_AVX2 = true;
196 }
Aart Bik3f67e692016-01-15 14:35:12 -0800197 if (line.find("popcnt") != std::string::npos) {
198 has_POPCNT = true;
199 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800200 }
201 }
202 }
203 in.close();
204 } else {
205 LOG(ERROR) << "Failed to open /proc/cpuinfo";
206 }
Serban Constantinescub595b402016-09-23 11:06:03 +0100207 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
Ian Rogersd582fa42014-11-05 23:46:43 -0800208}
209
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800210X86FeaturesUniquePtr X86InstructionSetFeatures::FromHwcap(bool x86_64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800211 UNIMPLEMENTED(WARNING);
212 return FromCppDefines(x86_64);
213}
214
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800215X86FeaturesUniquePtr X86InstructionSetFeatures::FromAssembly(bool x86_64) {
Ian Rogersd582fa42014-11-05 23:46:43 -0800216 UNIMPLEMENTED(WARNING);
217 return FromCppDefines(x86_64);
218}
219
220bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const {
221 if (GetInstructionSet() != other->GetInstructionSet()) {
222 return false;
223 }
224 const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
Serban Constantinescub595b402016-09-23 11:06:03 +0100225 return (has_SSSE3_ == other_as_x86->has_SSSE3_) &&
Ian Rogersd582fa42014-11-05 23:46:43 -0800226 (has_SSE4_1_ == other_as_x86->has_SSE4_1_) &&
227 (has_SSE4_2_ == other_as_x86->has_SSE4_2_) &&
228 (has_AVX_ == other_as_x86->has_AVX_) &&
Mark P Mendell17077d82015-12-16 19:15:59 +0000229 (has_AVX2_ == other_as_x86->has_AVX2_) &&
Aart Bik3f67e692016-01-15 14:35:12 -0800230 (has_POPCNT_ == other_as_x86->has_POPCNT_);
Ian Rogersd582fa42014-11-05 23:46:43 -0800231}
232
Aart Bik5354af92017-07-19 11:13:27 -0700233bool X86InstructionSetFeatures::HasAtLeast(const InstructionSetFeatures* other) const {
234 if (GetInstructionSet() != other->GetInstructionSet()) {
235 return false;
236 }
237 const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures();
238 return (has_SSSE3_ || !other_as_x86->has_SSSE3_) &&
239 (has_SSE4_1_ || !other_as_x86->has_SSE4_1_) &&
240 (has_SSE4_2_ || !other_as_x86->has_SSE4_2_) &&
241 (has_AVX_ || !other_as_x86->has_AVX_) &&
242 (has_AVX2_ || !other_as_x86->has_AVX2_) &&
243 (has_POPCNT_ || !other_as_x86->has_POPCNT_);
244}
245
Ian Rogersd582fa42014-11-05 23:46:43 -0800246uint32_t X86InstructionSetFeatures::AsBitmap() const {
Serban Constantinescub595b402016-09-23 11:06:03 +0100247 return (has_SSSE3_ ? kSsse3Bitfield : 0) |
Ian Rogersd582fa42014-11-05 23:46:43 -0800248 (has_SSE4_1_ ? kSse4_1Bitfield : 0) |
249 (has_SSE4_2_ ? kSse4_2Bitfield : 0) |
250 (has_AVX_ ? kAvxBitfield : 0) |
Mark P Mendell17077d82015-12-16 19:15:59 +0000251 (has_AVX2_ ? kAvx2Bitfield : 0) |
Aart Bik3f67e692016-01-15 14:35:12 -0800252 (has_POPCNT_ ? kPopCntBitfield : 0);
Ian Rogersd582fa42014-11-05 23:46:43 -0800253}
254
255std::string X86InstructionSetFeatures::GetFeatureString() const {
256 std::string result;
Ian Rogersd582fa42014-11-05 23:46:43 -0800257 if (has_SSSE3_) {
Serban Constantinescub595b402016-09-23 11:06:03 +0100258 result += "ssse3";
Ian Rogersd582fa42014-11-05 23:46:43 -0800259 } else {
Serban Constantinescub595b402016-09-23 11:06:03 +0100260 result += "-ssse3";
Ian Rogersd582fa42014-11-05 23:46:43 -0800261 }
262 if (has_SSE4_1_) {
263 result += ",sse4.1";
264 } else {
265 result += ",-sse4.1";
266 }
267 if (has_SSE4_2_) {
268 result += ",sse4.2";
269 } else {
270 result += ",-sse4.2";
271 }
272 if (has_AVX_) {
273 result += ",avx";
274 } else {
275 result += ",-avx";
276 }
277 if (has_AVX2_) {
278 result += ",avx2";
279 } else {
280 result += ",-avx2";
281 }
Aart Bik3f67e692016-01-15 14:35:12 -0800282 if (has_POPCNT_) {
283 result += ",popcnt";
284 } else {
285 result += ",-popcnt";
286 }
Ian Rogersd582fa42014-11-05 23:46:43 -0800287 return result;
288}
289
Andreas Gampe0415b4e2015-01-06 15:17:07 -0800290std::unique_ptr<const InstructionSetFeatures> X86InstructionSetFeatures::AddFeaturesFromSplitString(
Serban Constantinescub595b402016-09-23 11:06:03 +0100291 const std::vector<std::string>& features, bool x86_64,
Ian Rogersd582fa42014-11-05 23:46:43 -0800292 std::string* error_msg) const {
293 bool has_SSSE3 = has_SSSE3_;
294 bool has_SSE4_1 = has_SSE4_1_;
295 bool has_SSE4_2 = has_SSE4_2_;
296 bool has_AVX = has_AVX_;
297 bool has_AVX2 = has_AVX2_;
Aart Bik3f67e692016-01-15 14:35:12 -0800298 bool has_POPCNT = has_POPCNT_;
Ian Rogersd582fa42014-11-05 23:46:43 -0800299 for (auto i = features.begin(); i != features.end(); i++) {
Andreas Gampe9186ced2016-12-12 14:28:21 -0800300 std::string feature = android::base::Trim(*i);
Ian Rogersd582fa42014-11-05 23:46:43 -0800301 if (feature == "ssse3") {
302 has_SSSE3 = true;
303 } else if (feature == "-ssse3") {
304 has_SSSE3 = false;
305 } else if (feature == "sse4.1") {
306 has_SSE4_1 = true;
307 } else if (feature == "-sse4.1") {
308 has_SSE4_1 = false;
309 } else if (feature == "sse4.2") {
310 has_SSE4_2 = true;
311 } else if (feature == "-sse4.2") {
312 has_SSE4_2 = false;
313 } else if (feature == "avx") {
314 has_AVX = true;
315 } else if (feature == "-avx") {
316 has_AVX = false;
317 } else if (feature == "avx2") {
318 has_AVX2 = true;
319 } else if (feature == "-avx2") {
320 has_AVX2 = false;
Aart Bik3f67e692016-01-15 14:35:12 -0800321 } else if (feature == "popcnt") {
322 has_POPCNT = true;
323 } else if (feature == "-popcnt") {
324 has_POPCNT = false;
Ian Rogersd582fa42014-11-05 23:46:43 -0800325 } else {
326 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str());
327 return nullptr;
328 }
329 }
Serban Constantinescub595b402016-09-23 11:06:03 +0100330 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT);
Ian Rogersd582fa42014-11-05 23:46:43 -0800331}
332
333} // namespace art