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