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