1 // Copyright 2013, ARM Limited 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are met: 6 // 7 // * Redistributions of source code must retain the above copyright notice, 8 // this list of conditions and the following disclaimer. 9 // * Redistributions in binary form must reproduce the above copyright notice, 10 // this list of conditions and the following disclaimer in the documentation 11 // and/or other materials provided with the distribution. 12 // * Neither the name of ARM Limited nor the names of its contributors may be 13 // used to endorse or promote products derived from this software without 14 // specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #ifndef VIXL_A64_INSTRUCTIONS_A64_H_ 28 #define VIXL_A64_INSTRUCTIONS_A64_H_ 29 30 #include "globals-vixl.h" 31 #include "utils-vixl.h" 32 #include "a64/constants-a64.h" 33 34 namespace vixl { 35 // ISA constants. -------------------------------------------------------------- 36 37 typedef uint32_t Instr; 38 const unsigned kInstructionSize = 4; 39 const unsigned kInstructionSizeLog2 = 2; 40 const unsigned kLiteralEntrySize = 4; 41 const unsigned kLiteralEntrySizeLog2 = 2; 42 const unsigned kMaxLoadLiteralRange = 1 * MBytes; 43 44 const unsigned kWRegSize = 32; 45 const unsigned kWRegSizeLog2 = 5; 46 const unsigned kWRegSizeInBytes = kWRegSize / 8; 47 const unsigned kWRegSizeInBytesLog2 = kWRegSizeLog2 - 3; 48 const unsigned kXRegSize = 64; 49 const unsigned kXRegSizeLog2 = 6; 50 const unsigned kXRegSizeInBytes = kXRegSize / 8; 51 const unsigned kXRegSizeInBytesLog2 = kXRegSizeLog2 - 3; 52 const unsigned kSRegSize = 32; 53 const unsigned kSRegSizeLog2 = 5; 54 const unsigned kSRegSizeInBytes = kSRegSize / 8; 55 const unsigned kSRegSizeInBytesLog2 = kSRegSizeLog2 - 3; 56 const unsigned kDRegSize = 64; 57 const unsigned kDRegSizeLog2 = 6; 58 const unsigned kDRegSizeInBytes = kDRegSize / 8; 59 const unsigned kDRegSizeInBytesLog2 = kDRegSizeLog2 - 3; 60 const uint64_t kWRegMask = UINT64_C(0xffffffff); 61 const uint64_t kXRegMask = UINT64_C(0xffffffffffffffff); 62 const uint64_t kSRegMask = UINT64_C(0xffffffff); 63 const uint64_t kDRegMask = UINT64_C(0xffffffffffffffff); 64 const uint64_t kSSignMask = UINT64_C(0x80000000); 65 const uint64_t kDSignMask = UINT64_C(0x8000000000000000); 66 const uint64_t kWSignMask = UINT64_C(0x80000000); 67 const uint64_t kXSignMask = UINT64_C(0x8000000000000000); 68 const uint64_t kByteMask = UINT64_C(0xff); 69 const uint64_t kHalfWordMask = UINT64_C(0xffff); 70 const uint64_t kWordMask = UINT64_C(0xffffffff); 71 const uint64_t kXMaxUInt = UINT64_C(0xffffffffffffffff); 72 const uint64_t kWMaxUInt = UINT64_C(0xffffffff); 73 const int64_t kXMaxInt = INT64_C(0x7fffffffffffffff); 74 const int64_t kXMinInt = INT64_C(0x8000000000000000); 75 const int32_t kWMaxInt = INT32_C(0x7fffffff); 76 const int32_t kWMinInt = INT32_C(0x80000000); 77 const unsigned kLinkRegCode = 30; 78 const unsigned kZeroRegCode = 31; 79 const unsigned kSPRegInternalCode = 63; 80 const unsigned kRegCodeMask = 0x1f; 81 82 // AArch64 floating-point specifics. These match IEEE-754. 83 const unsigned kDoubleMantissaBits = 52; 84 const unsigned kDoubleExponentBits = 11; 85 const unsigned kFloatMantissaBits = 23; 86 const unsigned kFloatExponentBits = 8; 87 88 const float kFP32PositiveInfinity = rawbits_to_float(0x7f800000); 89 const float kFP32NegativeInfinity = rawbits_to_float(0xff800000); 90 const double kFP64PositiveInfinity = 91 rawbits_to_double(UINT64_C(0x7ff0000000000000)); 92 const double kFP64NegativeInfinity = 93 rawbits_to_double(UINT64_C(0xfff0000000000000)); 94 95 // This value is a signalling NaN as both a double and as a float (taking the 96 // least-significant word). 97 static const double kFP64SignallingNaN = 98 rawbits_to_double(UINT64_C(0x7ff000007f800001)); 99 static const float kFP32SignallingNaN = rawbits_to_float(0x7f800001); 100 101 // A similar value, but as a quiet NaN. 102 static const double kFP64QuietNaN = 103 rawbits_to_double(UINT64_C(0x7ff800007fc00001)); 104 static const float kFP32QuietNaN = rawbits_to_float(0x7fc00001); 105 106 // The default NaN values (for FPCR.DN=1). 107 static const double kFP64DefaultNaN = 108 rawbits_to_double(UINT64_C(0x7ff8000000000000)); 109 static const float kFP32DefaultNaN = rawbits_to_float(0x7fc00000); 110 111 112 enum LSDataSize { 113 LSByte = 0, 114 LSHalfword = 1, 115 LSWord = 2, 116 LSDoubleWord = 3 117 }; 118 119 LSDataSize CalcLSPairDataSize(LoadStorePairOp op); 120 121 enum ImmBranchType { 122 UnknownBranchType = 0, 123 CondBranchType = 1, 124 UncondBranchType = 2, 125 CompareBranchType = 3, 126 TestBranchType = 4 127 }; 128 129 enum AddrMode { 130 Offset, 131 PreIndex, 132 PostIndex 133 }; 134 135 enum FPRounding { 136 // The first four values are encodable directly by FPCR<RMode>. 137 FPTieEven = 0x0, 138 FPPositiveInfinity = 0x1, 139 FPNegativeInfinity = 0x2, 140 FPZero = 0x3, 141 142 // The final rounding mode is only available when explicitly specified by the 143 // instruction (such as with fcvta). It cannot be set in FPCR. 144 FPTieAway 145 }; 146 147 enum Reg31Mode { 148 Reg31IsStackPointer, 149 Reg31IsZeroRegister 150 }; 151 152 // Instructions. --------------------------------------------------------------- 153 154 class Instruction { 155 public: InstructionBits()156 inline Instr InstructionBits() const { 157 return *(reinterpret_cast<const Instr*>(this)); 158 } 159 SetInstructionBits(Instr new_instr)160 inline void SetInstructionBits(Instr new_instr) { 161 *(reinterpret_cast<Instr*>(this)) = new_instr; 162 } 163 Bit(int pos)164 inline int Bit(int pos) const { 165 return (InstructionBits() >> pos) & 1; 166 } 167 Bits(int msb,int lsb)168 inline uint32_t Bits(int msb, int lsb) const { 169 return unsigned_bitextract_32(msb, lsb, InstructionBits()); 170 } 171 SignedBits(int msb,int lsb)172 inline int32_t SignedBits(int msb, int lsb) const { 173 int32_t bits = *(reinterpret_cast<const int32_t*>(this)); 174 return signed_bitextract_32(msb, lsb, bits); 175 } 176 Mask(uint32_t mask)177 inline Instr Mask(uint32_t mask) const { 178 return InstructionBits() & mask; 179 } 180 181 #define DEFINE_GETTER(Name, HighBit, LowBit, Func) \ 182 inline int64_t Name() const { return Func(HighBit, LowBit); } INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)183 INSTRUCTION_FIELDS_LIST(DEFINE_GETTER) 184 #undef DEFINE_GETTER 185 186 // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), 187 // formed from ImmPCRelLo and ImmPCRelHi. 188 int ImmPCRel() const { 189 int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo()); 190 int const width = ImmPCRelLo_width + ImmPCRelHi_width; 191 return signed_bitextract_32(width-1, 0, offset); 192 } 193 194 uint64_t ImmLogical(); 195 float ImmFP32(); 196 double ImmFP64(); 197 SizeLSPair()198 inline LSDataSize SizeLSPair() const { 199 return CalcLSPairDataSize( 200 static_cast<LoadStorePairOp>(Mask(LoadStorePairMask))); 201 } 202 203 // Helpers. IsCondBranchImm()204 inline bool IsCondBranchImm() const { 205 return Mask(ConditionalBranchFMask) == ConditionalBranchFixed; 206 } 207 IsUncondBranchImm()208 inline bool IsUncondBranchImm() const { 209 return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed; 210 } 211 IsCompareBranch()212 inline bool IsCompareBranch() const { 213 return Mask(CompareBranchFMask) == CompareBranchFixed; 214 } 215 IsTestBranch()216 inline bool IsTestBranch() const { 217 return Mask(TestBranchFMask) == TestBranchFixed; 218 } 219 IsPCRelAddressing()220 inline bool IsPCRelAddressing() const { 221 return Mask(PCRelAddressingFMask) == PCRelAddressingFixed; 222 } 223 IsLogicalImmediate()224 inline bool IsLogicalImmediate() const { 225 return Mask(LogicalImmediateFMask) == LogicalImmediateFixed; 226 } 227 IsAddSubImmediate()228 inline bool IsAddSubImmediate() const { 229 return Mask(AddSubImmediateFMask) == AddSubImmediateFixed; 230 } 231 IsAddSubExtended()232 inline bool IsAddSubExtended() const { 233 return Mask(AddSubExtendedFMask) == AddSubExtendedFixed; 234 } 235 IsLoadOrStore()236 inline bool IsLoadOrStore() const { 237 return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed; 238 } 239 IsMovn()240 inline bool IsMovn() const { 241 return (Mask(MoveWideImmediateMask) == MOVN_x) || 242 (Mask(MoveWideImmediateMask) == MOVN_w); 243 } 244 245 // Indicate whether Rd can be the stack pointer or the zero register. This 246 // does not check that the instruction actually has an Rd field. RdMode()247 inline Reg31Mode RdMode() const { 248 // The following instructions use sp or wsp as Rd: 249 // Add/sub (immediate) when not setting the flags. 250 // Add/sub (extended) when not setting the flags. 251 // Logical (immediate) when not setting the flags. 252 // Otherwise, r31 is the zero register. 253 if (IsAddSubImmediate() || IsAddSubExtended()) { 254 if (Mask(AddSubSetFlagsBit)) { 255 return Reg31IsZeroRegister; 256 } else { 257 return Reg31IsStackPointer; 258 } 259 } 260 if (IsLogicalImmediate()) { 261 // Of the logical (immediate) instructions, only ANDS (and its aliases) 262 // can set the flags. The others can all write into sp. 263 // Note that some logical operations are not available to 264 // immediate-operand instructions, so we have to combine two masks here. 265 if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) { 266 return Reg31IsZeroRegister; 267 } else { 268 return Reg31IsStackPointer; 269 } 270 } 271 return Reg31IsZeroRegister; 272 } 273 274 // Indicate whether Rn can be the stack pointer or the zero register. This 275 // does not check that the instruction actually has an Rn field. RnMode()276 inline Reg31Mode RnMode() const { 277 // The following instructions use sp or wsp as Rn: 278 // All loads and stores. 279 // Add/sub (immediate). 280 // Add/sub (extended). 281 // Otherwise, r31 is the zero register. 282 if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) { 283 return Reg31IsStackPointer; 284 } 285 return Reg31IsZeroRegister; 286 } 287 BranchType()288 inline ImmBranchType BranchType() const { 289 if (IsCondBranchImm()) { 290 return CondBranchType; 291 } else if (IsUncondBranchImm()) { 292 return UncondBranchType; 293 } else if (IsCompareBranch()) { 294 return CompareBranchType; 295 } else if (IsTestBranch()) { 296 return TestBranchType; 297 } else { 298 return UnknownBranchType; 299 } 300 } 301 302 // Find the target of this instruction. 'this' may be a branch or a 303 // PC-relative addressing instruction. 304 Instruction* ImmPCOffsetTarget(); 305 306 // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or 307 // a PC-relative addressing instruction. 308 void SetImmPCOffsetTarget(Instruction* target); 309 // Patch a literal load instruction to load from 'source'. 310 void SetImmLLiteral(Instruction* source); 311 LiteralAddress()312 inline uint8_t* LiteralAddress() { 313 int offset = ImmLLiteral() << kLiteralEntrySizeLog2; 314 return reinterpret_cast<uint8_t*>(this) + offset; 315 } 316 Literal32()317 inline uint32_t Literal32() { 318 uint32_t literal; 319 memcpy(&literal, LiteralAddress(), sizeof(literal)); 320 321 return literal; 322 } 323 Literal64()324 inline uint64_t Literal64() { 325 uint64_t literal; 326 memcpy(&literal, LiteralAddress(), sizeof(literal)); 327 328 return literal; 329 } 330 LiteralFP32()331 inline float LiteralFP32() { 332 return rawbits_to_float(Literal32()); 333 } 334 LiteralFP64()335 inline double LiteralFP64() { 336 return rawbits_to_double(Literal64()); 337 } 338 NextInstruction()339 inline Instruction* NextInstruction() { 340 return this + kInstructionSize; 341 } 342 InstructionAtOffset(int64_t offset)343 inline Instruction* InstructionAtOffset(int64_t offset) { 344 VIXL_ASSERT(IsWordAligned(this + offset)); 345 return this + offset; 346 } 347 Cast(T src)348 template<typename T> static inline Instruction* Cast(T src) { 349 return reinterpret_cast<Instruction*>(src); 350 } 351 352 private: 353 inline int ImmBranch() const; 354 355 void SetPCRelImmTarget(Instruction* target); 356 void SetBranchImmTarget(Instruction* target); 357 }; 358 } // namespace vixl 359 360 #endif // VIXL_A64_INSTRUCTIONS_A64_H_ 361