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