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_mips.h" 18 19 #include <fstream> 20 #include <sstream> 21 22 #include <android-base/stringprintf.h> 23 #include <android-base/strings.h> 24 25 #include "base/stl_util.h" 26 27 namespace art { 28 29 using android::base::StringPrintf; 30 31 // An enum for the Mips revision. 32 enum class MipsLevel { 33 kBase, 34 kR2, 35 kR5, 36 kR6 37 }; 38 39 #if defined(_MIPS_ARCH_MIPS32R6) 40 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR6; 41 #elif defined(_MIPS_ARCH_MIPS32R5) 42 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR5; 43 #elif defined(_MIPS_ARCH_MIPS32R2) 44 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kR2; 45 #else 46 static constexpr MipsLevel kRuntimeMipsLevel = MipsLevel::kBase; 47 #endif 48 49 static void GetFlagsFromCppDefined(bool* mips_isa_gte2, bool* r6, bool* fpu_32bit, bool* msa) { 50 // Override defaults based on compiler flags. 51 if (kRuntimeMipsLevel >= MipsLevel::kR2) { 52 *mips_isa_gte2 = true; 53 } else { 54 *mips_isa_gte2 = false; 55 } 56 57 if (kRuntimeMipsLevel >= MipsLevel::kR5) { 58 *fpu_32bit = false; 59 *msa = true; 60 } else { 61 *fpu_32bit = true; 62 *msa = false; 63 } 64 65 if (kRuntimeMipsLevel >= MipsLevel::kR6) { 66 *r6 = true; 67 } else { 68 *r6 = false; 69 } 70 } 71 72 MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromVariant( 73 const std::string& variant, std::string* error_msg ATTRIBUTE_UNUSED) { 74 75 // Override defaults based on compiler flags. 76 // This is needed when running ART test where the variant is not defined. 77 bool fpu_32bit; 78 bool mips_isa_gte2; 79 bool r6; 80 bool msa; 81 GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit, &msa); 82 83 // Override defaults based on variant string. 84 // Only care if it is R1, R2, R5 or R6 and we assume all CPUs will have a FP unit. 85 constexpr const char* kMips32Prefix = "mips32r"; 86 const size_t kPrefixLength = strlen(kMips32Prefix); 87 if (variant.compare(0, kPrefixLength, kMips32Prefix, kPrefixLength) == 0 && 88 variant.size() > kPrefixLength) { 89 r6 = (variant[kPrefixLength] >= '6'); 90 fpu_32bit = (variant[kPrefixLength] < '5'); 91 mips_isa_gte2 = (variant[kPrefixLength] >= '2'); 92 msa = (variant[kPrefixLength] >= '5'); 93 } else if (variant == "default") { 94 // Default variant has FPU, is gte2. This is the traditional setting. 95 // 96 // Note, we get FPU bitness and R6-ness from the build (using cpp defines, see above) 97 // and don't override them because many things depend on the "default" variant being 98 // sufficient for most purposes. That is, "default" should work for both R2 and R6. 99 // Use "mips32r#" to get a specific configuration, possibly not matching the runtime 100 // ISA (e.g. for ISA-specific testing of dex2oat internals). 101 mips_isa_gte2 = true; 102 } else { 103 LOG(WARNING) << "Unexpected CPU variant for Mips32 using defaults: " << variant; 104 } 105 106 return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa)); 107 } 108 109 MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromBitmap(uint32_t bitmap) { 110 bool fpu_32bit = (bitmap & kFpu32Bitfield) != 0; 111 bool mips_isa_gte2 = (bitmap & kIsaRevGte2Bitfield) != 0; 112 bool r6 = (bitmap & kR6) != 0; 113 bool msa = (bitmap & kMsaBitfield) != 0; 114 return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa)); 115 } 116 117 MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromCppDefines() { 118 bool fpu_32bit; 119 bool mips_isa_gte2; 120 bool r6; 121 bool msa; 122 GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit, &msa); 123 124 return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa)); 125 } 126 127 MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromCpuInfo() { 128 bool fpu_32bit; 129 bool mips_isa_gte2; 130 bool r6; 131 bool msa; 132 GetFlagsFromCppDefined(&mips_isa_gte2, &r6, &fpu_32bit, &msa); 133 134 msa = false; 135 136 std::ifstream in("/proc/cpuinfo"); 137 if (!in.fail()) { 138 while (!in.eof()) { 139 std::string line; 140 std::getline(in, line); 141 if (!in.eof()) { 142 LOG(INFO) << "cpuinfo line: " << line; 143 if (line.find("ASEs") != std::string::npos) { 144 LOG(INFO) << "found Application Specific Extensions"; 145 if (line.find("msa") != std::string::npos) { 146 msa = true; 147 } 148 } 149 } 150 } 151 in.close(); 152 } else { 153 LOG(ERROR) << "Failed to open /proc/cpuinfo"; 154 } 155 156 return MipsFeaturesUniquePtr(new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa)); 157 } 158 159 MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromHwcap() { 160 UNIMPLEMENTED(WARNING); 161 return FromCppDefines(); 162 } 163 164 MipsFeaturesUniquePtr MipsInstructionSetFeatures::FromAssembly() { 165 UNIMPLEMENTED(WARNING); 166 return FromCppDefines(); 167 } 168 169 bool MipsInstructionSetFeatures::Equals(const InstructionSetFeatures* other) const { 170 if (InstructionSet::kMips != other->GetInstructionSet()) { 171 return false; 172 } 173 const MipsInstructionSetFeatures* other_as_mips = other->AsMipsInstructionSetFeatures(); 174 return (fpu_32bit_ == other_as_mips->fpu_32bit_) && 175 (mips_isa_gte2_ == other_as_mips->mips_isa_gte2_) && 176 (r6_ == other_as_mips->r6_) && 177 (msa_ == other_as_mips->msa_); 178 } 179 180 uint32_t MipsInstructionSetFeatures::AsBitmap() const { 181 return (fpu_32bit_ ? kFpu32Bitfield : 0) | 182 (mips_isa_gte2_ ? kIsaRevGte2Bitfield : 0) | 183 (r6_ ? kR6 : 0) | 184 (msa_ ? kMsaBitfield : 0); 185 } 186 187 std::string MipsInstructionSetFeatures::GetFeatureString() const { 188 std::string result; 189 if (fpu_32bit_) { 190 result += "fpu32"; 191 } else { 192 result += "-fpu32"; 193 } 194 if (mips_isa_gte2_) { 195 result += ",mips2"; 196 } else { 197 result += ",-mips2"; 198 } 199 if (r6_) { 200 result += ",r6"; 201 } // Suppress non-r6. 202 if (msa_) { 203 result += ",msa"; 204 } else { 205 result += ",-msa"; 206 } 207 return result; 208 } 209 210 std::unique_ptr<const InstructionSetFeatures> 211 MipsInstructionSetFeatures::AddFeaturesFromSplitString( 212 const std::vector<std::string>& features, std::string* error_msg) const { 213 bool fpu_32bit = fpu_32bit_; 214 bool mips_isa_gte2 = mips_isa_gte2_; 215 bool r6 = r6_; 216 bool msa = msa_; 217 for (auto i = features.begin(); i != features.end(); i++) { 218 std::string feature = android::base::Trim(*i); 219 if (feature == "fpu32") { 220 fpu_32bit = true; 221 } else if (feature == "-fpu32") { 222 fpu_32bit = false; 223 } else if (feature == "mips2") { 224 mips_isa_gte2 = true; 225 } else if (feature == "-mips2") { 226 mips_isa_gte2 = false; 227 } else if (feature == "r6") { 228 r6 = true; 229 } else if (feature == "-r6") { 230 r6 = false; 231 } else if (feature == "msa") { 232 msa = true; 233 } else if (feature == "-msa") { 234 msa = false; 235 } else { 236 *error_msg = StringPrintf("Unknown instruction set feature: '%s'", feature.c_str()); 237 return nullptr; 238 } 239 } 240 return std::unique_ptr<const InstructionSetFeatures>( 241 new MipsInstructionSetFeatures(fpu_32bit, mips_isa_gte2, r6, msa)); 242 } 243 244 } // namespace art 245