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