1 /*
2  * Copyright (C) 2011 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.h"
18 
19 #include "base/casts.h"
20 #include "utils.h"
21 
22 
23 #include "arm/instruction_set_features_arm.h"
24 #include "arm64/instruction_set_features_arm64.h"
25 #include "mips/instruction_set_features_mips.h"
26 #include "mips64/instruction_set_features_mips64.h"
27 #include "x86/instruction_set_features_x86.h"
28 #include "x86_64/instruction_set_features_x86_64.h"
29 
30 namespace art {
31 
FromVariant(InstructionSet isa,const std::string & variant,std::string * error_msg)32 const InstructionSetFeatures* InstructionSetFeatures::FromVariant(InstructionSet isa,
33                                                                   const std::string& variant,
34                                                                   std::string* error_msg) {
35   const InstructionSetFeatures* result;
36   switch (isa) {
37     case kArm:
38     case kThumb2:
39       result = ArmInstructionSetFeatures::FromVariant(variant, error_msg);
40       break;
41     case kArm64:
42       result = Arm64InstructionSetFeatures::FromVariant(variant, error_msg);
43       break;
44     case kMips:
45       result = MipsInstructionSetFeatures::FromVariant(variant, error_msg);
46       break;
47     case kMips64:
48       result = Mips64InstructionSetFeatures::FromVariant(variant, error_msg);
49       break;
50     case kX86:
51       result = X86InstructionSetFeatures::FromVariant(variant, error_msg);
52       break;
53     case kX86_64:
54       result = X86_64InstructionSetFeatures::FromVariant(variant, error_msg);
55       break;
56     default:
57       UNIMPLEMENTED(FATAL) << isa;
58       UNREACHABLE();
59   }
60   CHECK_EQ(result == nullptr, error_msg->size() != 0);
61   return result;
62 }
63 
FromBitmap(InstructionSet isa,uint32_t bitmap)64 const InstructionSetFeatures* InstructionSetFeatures::FromBitmap(InstructionSet isa,
65                                                                  uint32_t bitmap) {
66   const InstructionSetFeatures* result;
67   switch (isa) {
68     case kArm:
69     case kThumb2:
70       result = ArmInstructionSetFeatures::FromBitmap(bitmap);
71       break;
72     case kArm64:
73       result = Arm64InstructionSetFeatures::FromBitmap(bitmap);
74       break;
75     case kMips:
76       result = MipsInstructionSetFeatures::FromBitmap(bitmap);
77       break;
78     case kMips64:
79       result = Mips64InstructionSetFeatures::FromBitmap(bitmap);
80       break;
81     case kX86:
82       result = X86InstructionSetFeatures::FromBitmap(bitmap);
83       break;
84     case kX86_64:
85       result = X86_64InstructionSetFeatures::FromBitmap(bitmap);
86       break;
87     default:
88       UNIMPLEMENTED(FATAL) << isa;
89       UNREACHABLE();
90   }
91   CHECK_EQ(bitmap, result->AsBitmap());
92   return result;
93 }
94 
FromCppDefines()95 const InstructionSetFeatures* InstructionSetFeatures::FromCppDefines() {
96   const InstructionSetFeatures* result;
97   switch (kRuntimeISA) {
98     case kArm:
99     case kThumb2:
100       result = ArmInstructionSetFeatures::FromCppDefines();
101       break;
102     case kArm64:
103       result = Arm64InstructionSetFeatures::FromCppDefines();
104       break;
105     case kMips:
106       result = MipsInstructionSetFeatures::FromCppDefines();
107       break;
108     case kMips64:
109       result = Mips64InstructionSetFeatures::FromCppDefines();
110       break;
111     case kX86:
112       result = X86InstructionSetFeatures::FromCppDefines();
113       break;
114     case kX86_64:
115       result = X86_64InstructionSetFeatures::FromCppDefines();
116       break;
117     default:
118       UNIMPLEMENTED(FATAL) << kRuntimeISA;
119       UNREACHABLE();
120   }
121   return result;
122 }
123 
124 
FromCpuInfo()125 const InstructionSetFeatures* InstructionSetFeatures::FromCpuInfo() {
126   const InstructionSetFeatures* result;
127   switch (kRuntimeISA) {
128     case kArm:
129     case kThumb2:
130       result = ArmInstructionSetFeatures::FromCpuInfo();
131       break;
132     case kArm64:
133       result = Arm64InstructionSetFeatures::FromCpuInfo();
134       break;
135     case kMips:
136       result = MipsInstructionSetFeatures::FromCpuInfo();
137       break;
138     case kMips64:
139       result = Mips64InstructionSetFeatures::FromCpuInfo();
140       break;
141     case kX86:
142       result = X86InstructionSetFeatures::FromCpuInfo();
143       break;
144     case kX86_64:
145       result = X86_64InstructionSetFeatures::FromCpuInfo();
146       break;
147     default:
148       UNIMPLEMENTED(FATAL) << kRuntimeISA;
149       UNREACHABLE();
150   }
151   return result;
152 }
153 
FromHwcap()154 const InstructionSetFeatures* InstructionSetFeatures::FromHwcap() {
155   const InstructionSetFeatures* result;
156   switch (kRuntimeISA) {
157     case kArm:
158     case kThumb2:
159       result = ArmInstructionSetFeatures::FromHwcap();
160       break;
161     case kArm64:
162       result = Arm64InstructionSetFeatures::FromHwcap();
163       break;
164     case kMips:
165       result = MipsInstructionSetFeatures::FromHwcap();
166       break;
167     case kMips64:
168       result = Mips64InstructionSetFeatures::FromHwcap();
169       break;
170     case kX86:
171       result = X86InstructionSetFeatures::FromHwcap();
172       break;
173     case kX86_64:
174       result = X86_64InstructionSetFeatures::FromHwcap();
175       break;
176     default:
177       UNIMPLEMENTED(FATAL) << kRuntimeISA;
178       UNREACHABLE();
179   }
180   return result;
181 }
182 
FromAssembly()183 const InstructionSetFeatures* InstructionSetFeatures::FromAssembly() {
184   const InstructionSetFeatures* result;
185   switch (kRuntimeISA) {
186     case kArm:
187     case kThumb2:
188       result = ArmInstructionSetFeatures::FromAssembly();
189       break;
190     case kArm64:
191       result = Arm64InstructionSetFeatures::FromAssembly();
192       break;
193     case kMips:
194       result = MipsInstructionSetFeatures::FromAssembly();
195       break;
196     case kMips64:
197       result = Mips64InstructionSetFeatures::FromAssembly();
198       break;
199     case kX86:
200       result = X86InstructionSetFeatures::FromAssembly();
201       break;
202     case kX86_64:
203       result = X86_64InstructionSetFeatures::FromAssembly();
204       break;
205     default:
206       UNIMPLEMENTED(FATAL) << kRuntimeISA;
207       UNREACHABLE();
208   }
209   return result;
210 }
211 
AddFeaturesFromString(const std::string & feature_list,std::string * error_msg) const212 const InstructionSetFeatures* InstructionSetFeatures::AddFeaturesFromString(
213     const std::string& feature_list, std::string* error_msg) const {
214   if (feature_list.empty()) {
215     *error_msg = "No instruction set features specified";
216     return nullptr;
217   }
218   std::vector<std::string> features;
219   Split(feature_list, ',', &features);
220   bool smp = smp_;
221   bool use_default = false;  // Have we seen the 'default' feature?
222   bool first = false;  // Is this first feature?
223   for (auto it = features.begin(); it != features.end();) {
224     if (use_default) {
225       *error_msg = "Unexpected instruction set features after 'default'";
226       return nullptr;
227     }
228     std::string feature = Trim(*it);
229     bool erase = false;
230     if (feature == "default") {
231       if (!first) {
232         use_default = true;
233         erase = true;
234       } else {
235         *error_msg = "Unexpected instruction set features before 'default'";
236         return nullptr;
237       }
238     } else if (feature == "smp") {
239       smp = true;
240       erase = true;
241     } else if (feature == "-smp") {
242       smp = false;
243       erase = true;
244     }
245     // Erase the smp feature once processed.
246     if (!erase) {
247       ++it;
248     } else {
249       it = features.erase(it);
250     }
251     first = true;
252   }
253   // Expectation: "default" is standalone, no other flags. But an empty features vector after
254   // processing can also come along if the handled flags (at the moment only smp) are the only
255   // ones in the list. So logically, we check "default -> features.empty."
256   DCHECK(!use_default || features.empty());
257 
258   return AddFeaturesFromSplitString(smp, features, error_msg);
259 }
260 
AsArmInstructionSetFeatures() const261 const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
262   DCHECK_EQ(kArm, GetInstructionSet());
263   return down_cast<const ArmInstructionSetFeatures*>(this);
264 }
265 
AsArm64InstructionSetFeatures() const266 const Arm64InstructionSetFeatures* InstructionSetFeatures::AsArm64InstructionSetFeatures() const {
267   DCHECK_EQ(kArm64, GetInstructionSet());
268   return down_cast<const Arm64InstructionSetFeatures*>(this);
269 }
270 
AsMipsInstructionSetFeatures() const271 const MipsInstructionSetFeatures* InstructionSetFeatures::AsMipsInstructionSetFeatures() const {
272   DCHECK_EQ(kMips, GetInstructionSet());
273   return down_cast<const MipsInstructionSetFeatures*>(this);
274 }
275 
AsMips64InstructionSetFeatures() const276 const Mips64InstructionSetFeatures* InstructionSetFeatures::AsMips64InstructionSetFeatures() const {
277   DCHECK_EQ(kMips64, GetInstructionSet());
278   return down_cast<const Mips64InstructionSetFeatures*>(this);
279 }
280 
AsX86InstructionSetFeatures() const281 const X86InstructionSetFeatures* InstructionSetFeatures::AsX86InstructionSetFeatures() const {
282   DCHECK(kX86 == GetInstructionSet() || kX86_64 == GetInstructionSet());
283   return down_cast<const X86InstructionSetFeatures*>(this);
284 }
285 
AsX86_64InstructionSetFeatures() const286 const X86_64InstructionSetFeatures* InstructionSetFeatures::AsX86_64InstructionSetFeatures() const {
287   DCHECK_EQ(kX86_64, GetInstructionSet());
288   return down_cast<const X86_64InstructionSetFeatures*>(this);
289 }
290 
FindVariantInArray(const char * const variants[],size_t num_variants,const std::string & variant)291 bool InstructionSetFeatures::FindVariantInArray(const char* const variants[], size_t num_variants,
292                                                 const std::string& variant) {
293   const char* const * begin = variants;
294   const char* const * end = begin + num_variants;
295   return std::find(begin, end, variant) != end;
296 }
297 
operator <<(std::ostream & os,const InstructionSetFeatures & rhs)298 std::ostream& operator<<(std::ostream& os, const InstructionSetFeatures& rhs) {
299   os << "ISA: " << rhs.GetInstructionSet() << " Feature string: " << rhs.GetFeatureString();
300   return os;
301 }
302 
303 }  // namespace art
304