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