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 "sandybridge", 37 "silvermont", 38 }; 39 40 static constexpr const char* x86_variants_with_ssse3[] = { 41 "atom", 42 "sandybridge", 43 "silvermont", 44 }; 45 46 static constexpr const char* x86_variants_with_sse4_1[] = { 47 "sandybridge", 48 "silvermont", 49 }; 50 51 static constexpr const char* x86_variants_with_sse4_2[] = { 52 "sandybridge", 53 "silvermont", 54 }; 55 56 static constexpr const char* x86_variants_with_popcnt[] = { 57 "sandybridge", 58 "silvermont", 59 }; 60 61 X86FeaturesUniquePtr X86InstructionSetFeatures::Create(bool x86_64, 62 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) { 69 return X86FeaturesUniquePtr(new X86_64InstructionSetFeatures(has_SSSE3, 70 has_SSE4_1, 71 has_SSE4_2, 72 has_AVX, 73 has_AVX2, 74 has_POPCNT)); 75 } else { 76 return X86FeaturesUniquePtr(new X86InstructionSetFeatures(has_SSSE3, 77 has_SSE4_1, 78 has_SSE4_2, 79 has_AVX, 80 has_AVX2, 81 has_POPCNT)); 82 } 83 } 84 85 X86FeaturesUniquePtr X86InstructionSetFeatures::FromVariant( 86 const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED, 87 bool x86_64) { 88 bool has_SSSE3 = FindVariantInArray(x86_variants_with_ssse3, arraysize(x86_variants_with_ssse3), 89 variant); 90 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); 96 bool has_AVX = false; 97 bool has_AVX2 = false; 98 99 bool has_POPCNT = FindVariantInArray(x86_variants_with_popcnt, 100 arraysize(x86_variants_with_popcnt), 101 variant); 102 103 // Verify that variant is known. 104 bool known_variant = FindVariantInArray(x86_known_variants, arraysize(x86_known_variants), 105 variant); 106 if (!known_variant && variant != "default") { 107 LOG(WARNING) << "Unexpected CPU variant for X86 using defaults: " << variant; 108 } 109 110 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT); 111 } 112 113 X86FeaturesUniquePtr X86InstructionSetFeatures::FromBitmap(uint32_t bitmap, bool x86_64) { 114 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; 119 bool has_POPCNT = (bitmap & kPopCntBitfield) != 0; 120 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT); 121 } 122 123 X86FeaturesUniquePtr X86InstructionSetFeatures::FromCppDefines(bool x86_64) { 124 #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 154 #ifndef __POPCNT__ 155 const bool has_POPCNT = false; 156 #else 157 const bool has_POPCNT = true; 158 #endif 159 160 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT); 161 } 162 163 X86FeaturesUniquePtr X86InstructionSetFeatures::FromCpuInfo(bool x86_64) { 164 // 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. 166 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; 171 bool has_POPCNT = false; 172 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 } 197 if (line.find("popcnt") != std::string::npos) { 198 has_POPCNT = true; 199 } 200 } 201 } 202 } 203 in.close(); 204 } else { 205 LOG(ERROR) << "Failed to open /proc/cpuinfo"; 206 } 207 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT); 208 } 209 210 X86FeaturesUniquePtr X86InstructionSetFeatures::FromHwcap(bool x86_64) { 211 UNIMPLEMENTED(WARNING); 212 return FromCppDefines(x86_64); 213 } 214 215 X86FeaturesUniquePtr X86InstructionSetFeatures::FromAssembly(bool x86_64) { 216 UNIMPLEMENTED(WARNING); 217 return FromCppDefines(x86_64); 218 } 219 220 bool X86InstructionSetFeatures::Equals(const InstructionSetFeatures* other) const { 221 if (GetInstructionSet() != other->GetInstructionSet()) { 222 return false; 223 } 224 const X86InstructionSetFeatures* other_as_x86 = other->AsX86InstructionSetFeatures(); 225 return (has_SSSE3_ == other_as_x86->has_SSSE3_) && 226 (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_) && 229 (has_AVX2_ == other_as_x86->has_AVX2_) && 230 (has_POPCNT_ == other_as_x86->has_POPCNT_); 231 } 232 233 uint32_t X86InstructionSetFeatures::AsBitmap() const { 234 return (has_SSSE3_ ? kSsse3Bitfield : 0) | 235 (has_SSE4_1_ ? kSse4_1Bitfield : 0) | 236 (has_SSE4_2_ ? kSse4_2Bitfield : 0) | 237 (has_AVX_ ? kAvxBitfield : 0) | 238 (has_AVX2_ ? kAvx2Bitfield : 0) | 239 (has_POPCNT_ ? kPopCntBitfield : 0); 240 } 241 242 std::string X86InstructionSetFeatures::GetFeatureString() const { 243 std::string result; 244 if (has_SSSE3_) { 245 result += "ssse3"; 246 } else { 247 result += "-ssse3"; 248 } 249 if (has_SSE4_1_) { 250 result += ",sse4.1"; 251 } else { 252 result += ",-sse4.1"; 253 } 254 if (has_SSE4_2_) { 255 result += ",sse4.2"; 256 } else { 257 result += ",-sse4.2"; 258 } 259 if (has_AVX_) { 260 result += ",avx"; 261 } else { 262 result += ",-avx"; 263 } 264 if (has_AVX2_) { 265 result += ",avx2"; 266 } else { 267 result += ",-avx2"; 268 } 269 if (has_POPCNT_) { 270 result += ",popcnt"; 271 } else { 272 result += ",-popcnt"; 273 } 274 return result; 275 } 276 277 std::unique_ptr<const InstructionSetFeatures> X86InstructionSetFeatures::AddFeaturesFromSplitString( 278 const std::vector<std::string>& features, bool x86_64, 279 std::string* error_msg) const { 280 bool has_SSSE3 = has_SSSE3_; 281 bool has_SSE4_1 = has_SSE4_1_; 282 bool has_SSE4_2 = has_SSE4_2_; 283 bool has_AVX = has_AVX_; 284 bool has_AVX2 = has_AVX2_; 285 bool has_POPCNT = has_POPCNT_; 286 for (auto i = features.begin(); i != features.end(); i++) { 287 std::string feature = android::base::Trim(*i); 288 if (feature == "ssse3") { 289 has_SSSE3 = true; 290 } else if (feature == "-ssse3") { 291 has_SSSE3 = false; 292 } else if (feature == "sse4.1") { 293 has_SSE4_1 = true; 294 } else if (feature == "-sse4.1") { 295 has_SSE4_1 = false; 296 } else if (feature == "sse4.2") { 297 has_SSE4_2 = true; 298 } else if (feature == "-sse4.2") { 299 has_SSE4_2 = false; 300 } else if (feature == "avx") { 301 has_AVX = true; 302 } else if (feature == "-avx") { 303 has_AVX = false; 304 } else if (feature == "avx2") { 305 has_AVX2 = true; 306 } else if (feature == "-avx2") { 307 has_AVX2 = false; 308 } else if (feature == "popcnt") { 309 has_POPCNT = true; 310 } else if (feature == "-popcnt") { 311 has_POPCNT = false; 312 } else { 313 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str()); 314 return nullptr; 315 } 316 } 317 return Create(x86_64, has_SSSE3, has_SSE4_1, has_SSE4_2, has_AVX, has_AVX2, has_POPCNT); 318 } 319 320 } // namespace art 321