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