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