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