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#ifndef ART_RUNTIME_INSTRUCTION_SET_H_
18#define ART_RUNTIME_INSTRUCTION_SET_H_
19
20#include <iosfwd>
21#include <string>
22
23#include "base/logging.h"  // Logging is required for FATAL in the helper functions.
24#include "base/macros.h"
25#include "globals.h"       // For KB.
26
27namespace art {
28
29enum InstructionSet {
30  kNone,
31  kArm,
32  kArm64,
33  kThumb2,
34  kX86,
35  kX86_64,
36  kMips,
37  kMips64
38};
39std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs);
40
41#if defined(__arm__)
42static constexpr InstructionSet kRuntimeISA = kArm;
43#elif defined(__aarch64__)
44static constexpr InstructionSet kRuntimeISA = kArm64;
45#elif defined(__mips__)
46static constexpr InstructionSet kRuntimeISA = kMips;
47#elif defined(__i386__)
48static constexpr InstructionSet kRuntimeISA = kX86;
49#elif defined(__x86_64__)
50static constexpr InstructionSet kRuntimeISA = kX86_64;
51#else
52static constexpr InstructionSet kRuntimeISA = kNone;
53#endif
54
55// Architecture-specific pointer sizes
56static constexpr size_t kArmPointerSize = 4;
57static constexpr size_t kArm64PointerSize = 8;
58static constexpr size_t kMipsPointerSize = 4;
59static constexpr size_t kX86PointerSize = 4;
60static constexpr size_t kX86_64PointerSize = 8;
61
62// ARM instruction alignment. ARM processors require code to be 4-byte aligned,
63// but ARM ELF requires 8..
64static constexpr size_t kArmAlignment = 8;
65
66// ARM64 instruction alignment. This is the recommended alignment for maximum performance.
67static constexpr size_t kArm64Alignment = 16;
68
69// MIPS instruction alignment.  MIPS processors require code to be 4-byte aligned.
70// TODO: Can this be 4?
71static constexpr size_t kMipsAlignment = 8;
72
73// X86 instruction alignment. This is the recommended alignment for maximum performance.
74static constexpr size_t kX86Alignment = 16;
75
76
77const char* GetInstructionSetString(InstructionSet isa);
78
79// Note: Returns kNone when the string cannot be parsed to a known value.
80InstructionSet GetInstructionSetFromString(const char* instruction_set);
81
82static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
83  switch (isa) {
84    case kArm:
85      // Fall-through.
86    case kThumb2:
87      return kArmPointerSize;
88    case kArm64:
89      return kArm64PointerSize;
90    case kX86:
91      return kX86PointerSize;
92    case kX86_64:
93      return kX86_64PointerSize;
94    case kMips:
95      return kMipsPointerSize;
96    case kNone:
97      LOG(FATAL) << "ISA kNone does not have pointer size.";
98      return 0;
99    default:
100      LOG(FATAL) << "Unknown ISA " << isa;
101      return 0;
102  }
103}
104
105size_t GetInstructionSetAlignment(InstructionSet isa);
106
107static inline bool Is64BitInstructionSet(InstructionSet isa) {
108  switch (isa) {
109    case kArm:
110    case kThumb2:
111    case kX86:
112    case kMips:
113      return false;
114
115    case kArm64:
116    case kX86_64:
117      return true;
118
119    case kNone:
120      LOG(FATAL) << "ISA kNone does not have bit width.";
121      return 0;
122    default:
123      LOG(FATAL) << "Unknown ISA " << isa;
124      return 0;
125  }
126}
127
128static inline size_t GetBytesPerGprSpillLocation(InstructionSet isa) {
129  switch (isa) {
130    case kArm:
131      // Fall-through.
132    case kThumb2:
133      return 4;
134    case kArm64:
135      return 8;
136    case kX86:
137      return 4;
138    case kX86_64:
139      return 8;
140    case kMips:
141      return 4;
142    case kNone:
143      LOG(FATAL) << "ISA kNone does not have spills.";
144      return 0;
145    default:
146      LOG(FATAL) << "Unknown ISA " << isa;
147      return 0;
148  }
149}
150
151static inline size_t GetBytesPerFprSpillLocation(InstructionSet isa) {
152  switch (isa) {
153    case kArm:
154      // Fall-through.
155    case kThumb2:
156      return 4;
157    case kArm64:
158      return 8;
159    case kX86:
160      return 8;
161    case kX86_64:
162      return 8;
163    case kMips:
164      return 4;
165    case kNone:
166      LOG(FATAL) << "ISA kNone does not have spills.";
167      return 0;
168    default:
169      LOG(FATAL) << "Unknown ISA " << isa;
170      return 0;
171  }
172}
173
174size_t GetStackOverflowReservedBytes(InstructionSet isa);
175
176enum InstructionFeatures {
177  kHwDiv  = 0x1,              // Supports hardware divide.
178  kHwLpae = 0x2,              // Supports Large Physical Address Extension.
179};
180
181// This is a bitmask of supported features per architecture.
182class PACKED(4) InstructionSetFeatures {
183 public:
184  InstructionSetFeatures() : mask_(0) {}
185  explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {}
186
187  static InstructionSetFeatures GuessInstructionSetFeatures();
188
189  bool HasDivideInstruction() const {
190      return (mask_ & kHwDiv) != 0;
191  }
192
193  void SetHasDivideInstruction(bool v) {
194    mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0);
195  }
196
197  bool HasLpae() const {
198    return (mask_ & kHwLpae) != 0;
199  }
200
201  void SetHasLpae(bool v) {
202    mask_ = (mask_ & ~kHwLpae) | (v ? kHwLpae : 0);
203  }
204
205  std::string GetFeatureString() const;
206
207  // Other features in here.
208
209  bool operator==(const InstructionSetFeatures &peer) const {
210    return mask_ == peer.mask_;
211  }
212
213  bool operator!=(const InstructionSetFeatures &peer) const {
214    return mask_ != peer.mask_;
215  }
216
217  bool operator<=(const InstructionSetFeatures &peer) const {
218    return (mask_ & peer.mask_) == mask_;
219  }
220
221 private:
222  uint32_t mask_;
223};
224
225// The following definitions create return types for two word-sized entities that will be passed
226// in registers so that memory operations for the interface trampolines can be avoided. The entities
227// are the resolved method and the pointer to the code to be invoked.
228//
229// On x86, ARM32 and MIPS, this is given for a *scalar* 64bit value. The definition thus *must* be
230// uint64_t or long long int.
231//
232// On x86_64 and ARM64, structs are decomposed for allocation, so we can create a structs of two
233// size_t-sized values.
234//
235// We need two operations:
236//
237// 1) A flag value that signals failure. The assembly stubs expect the lower part to be "0".
238//    GetTwoWordFailureValue() will return a value that has lower part == 0.
239//
240// 2) A value that combines two word-sized values.
241//    GetTwoWordSuccessValue() constructs this.
242//
243// IMPORTANT: If you use this to transfer object pointers, it is your responsibility to ensure
244//            that the object does not move or the value is updated. Simple use of this is NOT SAFE
245//            when the garbage collector can move objects concurrently. Ensure that required locks
246//            are held when using!
247
248#if defined(__i386__) || defined(__arm__) || defined(__mips__)
249typedef uint64_t TwoWordReturn;
250
251// Encodes method_ptr==nullptr and code_ptr==nullptr
252static inline constexpr TwoWordReturn GetTwoWordFailureValue() {
253  return 0;
254}
255
256// Use the lower 32b for the method pointer and the upper 32b for the code pointer.
257static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
258  uint32_t lo32 = static_cast<uint32_t>(lo);
259  uint64_t hi64 = static_cast<uint64_t>(hi);
260  return ((hi64 << 32) | lo32);
261}
262
263#elif defined(__x86_64__) || defined(__aarch64__)
264struct TwoWordReturn {
265  uintptr_t lo;
266  uintptr_t hi;
267};
268
269// Encodes method_ptr==nullptr. Leaves random value in code pointer.
270static inline TwoWordReturn GetTwoWordFailureValue() {
271  TwoWordReturn ret;
272  ret.lo = 0;
273  return ret;
274}
275
276// Write values into their respective members.
277static inline TwoWordReturn GetTwoWordSuccessValue(uintptr_t hi, uintptr_t lo) {
278  TwoWordReturn ret;
279  ret.lo = lo;
280  ret.hi = hi;
281  return ret;
282}
283#else
284#error "Unsupported architecture"
285#endif
286
287}  // namespace art
288
289#endif  // ART_RUNTIME_INSTRUCTION_SET_H_
290