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
30namespace art {
31
32const 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
64const 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
95const 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
125const 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
154const 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
183const 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
212const 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
261const ArmInstructionSetFeatures* InstructionSetFeatures::AsArmInstructionSetFeatures() const {
262  DCHECK_EQ(kArm, GetInstructionSet());
263  return down_cast<const ArmInstructionSetFeatures*>(this);
264}
265
266const Arm64InstructionSetFeatures* InstructionSetFeatures::AsArm64InstructionSetFeatures() const {
267  DCHECK_EQ(kArm64, GetInstructionSet());
268  return down_cast<const Arm64InstructionSetFeatures*>(this);
269}
270
271const MipsInstructionSetFeatures* InstructionSetFeatures::AsMipsInstructionSetFeatures() const {
272  DCHECK_EQ(kMips, GetInstructionSet());
273  return down_cast<const MipsInstructionSetFeatures*>(this);
274}
275
276const Mips64InstructionSetFeatures* InstructionSetFeatures::AsMips64InstructionSetFeatures() const {
277  DCHECK_EQ(kMips64, GetInstructionSet());
278  return down_cast<const Mips64InstructionSetFeatures*>(this);
279}
280
281const X86InstructionSetFeatures* InstructionSetFeatures::AsX86InstructionSetFeatures() const {
282  DCHECK(kX86 == GetInstructionSet() || kX86_64 == GetInstructionSet());
283  return down_cast<const X86InstructionSetFeatures*>(this);
284}
285
286const X86_64InstructionSetFeatures* InstructionSetFeatures::AsX86_64InstructionSetFeatures() const {
287  DCHECK_EQ(kX86_64, GetInstructionSet());
288  return down_cast<const X86_64InstructionSetFeatures*>(this);
289}
290
291bool 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
298std::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