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 "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