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