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 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 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 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 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 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 205 X86FeaturesUniquePtr X86InstructionSetFeatures::FromHwcap(bool x86_64) { 206 UNIMPLEMENTED(WARNING); 207 return FromCppDefines(x86_64); 208 } 209 210 X86FeaturesUniquePtr X86InstructionSetFeatures::FromAssembly(bool x86_64) { 211 UNIMPLEMENTED(WARNING); 212 return FromCppDefines(x86_64); 213 } 214 215 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 228 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 237 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 272 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