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 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 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 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 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 227 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromHwcap(bool x86_64) { 228 UNIMPLEMENTED(WARNING); 229 return FromCppDefines(x86_64); 230 } 231 232 const X86InstructionSetFeatures* X86InstructionSetFeatures::FromAssembly(bool x86_64) { 233 UNIMPLEMENTED(WARNING); 234 return FromCppDefines(x86_64); 235 } 236 237 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 252 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 263 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 308 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