Home | History | Annotate | Download | only in x86
      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