/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_UTILS_ARM_CONSTANTS_ARM_H_ #define ART_COMPILER_UTILS_ARM_CONSTANTS_ARM_H_ #include <stdint.h> #include <iosfwd> #include "arch/arm/registers_arm.h" #include "base/casts.h" #include "base/logging.h" #include "globals.h" namespace art { namespace arm { // Defines constants and accessor classes to assemble, disassemble and // simulate ARM instructions. // // Section references in the code refer to the "ARM Architecture // Reference Manual ARMv7-A and ARMv7-R edition", issue C.b (24 July // 2012). // // Constants for specific fields are defined in their respective named enums. // General constants are in an anonymous enum in class Instr. // 4 bits option for the dmb instruction. // Order and values follows those of the ARM Architecture Reference Manual. enum DmbOptions { SY = 0xf, ST = 0xe, ISH = 0xb, ISHST = 0xa, NSH = 0x7, NSHST = 0x6 }; enum ScaleFactor { TIMES_1 = 0, TIMES_2 = 1, TIMES_4 = 2, TIMES_8 = 3 }; // Values for double-precision floating point registers. enum DRegister { // private marker to avoid generate-operator-out.py from processing. D0 = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7, D8 = 8, D9 = 9, D10 = 10, D11 = 11, D12 = 12, D13 = 13, D14 = 14, D15 = 15, D16 = 16, D17 = 17, D18 = 18, D19 = 19, D20 = 20, D21 = 21, D22 = 22, D23 = 23, D24 = 24, D25 = 25, D26 = 26, D27 = 27, D28 = 28, D29 = 29, D30 = 30, D31 = 31, kNumberOfDRegisters = 32, kNumberOfOverlappingDRegisters = 16, kNoDRegister = -1, }; std::ostream& operator<<(std::ostream& os, const DRegister& rhs); // Values for the condition field as defined in Table A8-1 "Condition // codes" (refer to Section A8.3 "Conditional execution"). enum Condition { // private marker to avoid generate-operator-out.py from processing. kNoCondition = -1, // Meaning (integer) | Meaning (floating-point) // ---------------------------------------+----------------------------------------- EQ = 0, // Equal | Equal NE = 1, // Not equal | Not equal, or unordered CS = 2, // Carry set | Greater than, equal, or unordered CC = 3, // Carry clear | Less than MI = 4, // Minus, negative | Less than PL = 5, // Plus, positive or zero | Greater than, equal, or unordered VS = 6, // Overflow | Unordered (i.e. at least one NaN operand) VC = 7, // No overflow | Not unordered HI = 8, // Unsigned higher | Greater than, or unordered LS = 9, // Unsigned lower or same | Less than or equal GE = 10, // Signed greater than or equal | Greater than or equal LT = 11, // Signed less than | Less than, or unordered GT = 12, // Signed greater than | Greater than LE = 13, // Signed less than or equal | Less than, equal, or unordered AL = 14, // Always (unconditional) | Always (unconditional) kSpecialCondition = 15, // Special condition (refer to Section A8.3 "Conditional execution"). kMaxCondition = 16, HS = CS, // HS (unsigned higher or same) is a synonym for CS. LO = CC // LO (unsigned lower) is a synonym for CC. }; std::ostream& operator<<(std::ostream& os, const Condition& rhs); // Opcodes for Data-processing instructions (instructions with a type 0 and 1) // as defined in section A3.4 enum Opcode { kNoOperand = -1, AND = 0, // Logical AND EOR = 1, // Logical Exclusive OR SUB = 2, // Subtract RSB = 3, // Reverse Subtract ADD = 4, // Add ADC = 5, // Add with Carry SBC = 6, // Subtract with Carry RSC = 7, // Reverse Subtract with Carry TST = 8, // Test TEQ = 9, // Test Equivalence CMP = 10, // Compare CMN = 11, // Compare Negated ORR = 12, // Logical (inclusive) OR MOV = 13, // Move BIC = 14, // Bit Clear MVN = 15, // Move Not ORN = 16, // Logical OR NOT. kMaxOperand = 17 }; std::ostream& operator<<(std::ostream& os, const Opcode& rhs); // Shifter types for Data-processing operands as defined in section A5.1.2. enum Shift { kNoShift = -1, LSL = 0, // Logical shift left LSR = 1, // Logical shift right ASR = 2, // Arithmetic shift right ROR = 3, // Rotate right RRX = 4, // Rotate right with extend. kMaxShift }; std::ostream& operator<<(std::ostream& os, const Shift& rhs); // Constants used for the decoding or encoding of the individual fields of // instructions. Based on the "Figure 3-1 ARM instruction set summary". enum InstructionFields { // private marker to avoid generate-operator-out.py from processing. kConditionShift = 28, kConditionBits = 4, kTypeShift = 25, kTypeBits = 3, kLinkShift = 24, kLinkBits = 1, kUShift = 23, kUBits = 1, kOpcodeShift = 21, kOpcodeBits = 4, kSShift = 20, kSBits = 1, kRnShift = 16, kRnBits = 4, kRdShift = 12, kRdBits = 4, kRsShift = 8, kRsBits = 4, kRmShift = 0, kRmBits = 4, // Immediate instruction fields encoding. kRotateShift = 8, kRotateBits = 4, kImmed8Shift = 0, kImmed8Bits = 8, // Shift instruction register fields encodings. kShiftImmShift = 7, kShiftRegisterShift = 8, kShiftImmBits = 5, kShiftShift = 5, kShiftBits = 2, // Load/store instruction offset field encoding. kOffset12Shift = 0, kOffset12Bits = 12, kOffset12Mask = 0x00000fff, // Mul instruction register fields encodings. kMulRdShift = 16, kMulRdBits = 4, kMulRnShift = 12, kMulRnBits = 4, kBranchOffsetMask = 0x00ffffff }; // Size (in bytes) of registers. const int kRegisterSize = 4; // List of registers used in load/store multiple. typedef uint16_t RegList; // The class Instr enables access to individual fields defined in the ARM // architecture instruction set encoding as described in figure A3-1. // // Example: Test whether the instruction at ptr does set the condition code // bits. // // bool InstructionSetsConditionCodes(uint8_t* ptr) { // Instr* instr = Instr::At(ptr); // int type = instr->TypeField(); // return ((type == 0) || (type == 1)) && instr->HasS(); // } // class Instr { public: enum { kInstrSize = 4, kInstrSizeLog2 = 2, kPCReadOffset = 8 }; bool IsBreakPoint() { return IsBkpt(); } // Get the raw instruction bits. int32_t InstructionBits() const { return *reinterpret_cast<const int32_t*>(this); } // Set the raw instruction bits to value. void SetInstructionBits(int32_t value) { *reinterpret_cast<int32_t*>(this) = value; } // Read one particular bit out of the instruction bits. int Bit(int nr) const { return (InstructionBits() >> nr) & 1; } // Read a bit field out of the instruction bits. int Bits(int shift, int count) const { return (InstructionBits() >> shift) & ((1 << count) - 1); } // Accessors for the different named fields used in the ARM encoding. // The naming of these accessor corresponds to figure A3-1. // Generally applicable fields Condition ConditionField() const { return static_cast<Condition>(Bits(kConditionShift, kConditionBits)); } int TypeField() const { return Bits(kTypeShift, kTypeBits); } Register RnField() const { return static_cast<Register>( Bits(kRnShift, kRnBits)); } Register RdField() const { return static_cast<Register>( Bits(kRdShift, kRdBits)); } // Fields used in Data processing instructions Opcode OpcodeField() const { return static_cast<Opcode>(Bits(kOpcodeShift, kOpcodeBits)); } int SField() const { return Bits(kSShift, kSBits); } // with register Register RmField() const { return static_cast<Register>(Bits(kRmShift, kRmBits)); } Shift ShiftField() const { return static_cast<Shift>( Bits(kShiftShift, kShiftBits)); } int RegShiftField() const { return Bit(4); } Register RsField() const { return static_cast<Register>(Bits(kRsShift, kRsBits)); } int ShiftAmountField() const { return Bits(kShiftImmShift, kShiftImmBits); } // with immediate int RotateField() const { return Bits(kRotateShift, kRotateBits); } int Immed8Field() const { return Bits(kImmed8Shift, kImmed8Bits); } // Fields used in Load/Store instructions int PUField() const { return Bits(23, 2); } int BField() const { return Bit(22); } int WField() const { return Bit(21); } int LField() const { return Bit(20); } // with register uses same fields as Data processing instructions above // with immediate int Offset12Field() const { return Bits(kOffset12Shift, kOffset12Bits); } // multiple int RlistField() const { return Bits(0, 16); } // extra loads and stores int SignField() const { return Bit(6); } int HField() const { return Bit(5); } int ImmedHField() const { return Bits(8, 4); } int ImmedLField() const { return Bits(0, 4); } // Fields used in Branch instructions int LinkField() const { return Bits(kLinkShift, kLinkBits); } int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); } // Fields used in Supervisor Call instructions uint32_t SvcField() const { return Bits(0, 24); } // Field used in Breakpoint instruction uint16_t BkptField() const { return ((Bits(8, 12) << 4) | Bits(0, 4)); } // Field used in 16-bit immediate move instructions uint16_t MovwField() const { return ((Bits(16, 4) << 12) | Bits(0, 12)); } // Field used in VFP float immediate move instruction float ImmFloatField() const { uint32_t imm32 = (Bit(19) << 31) | (((1 << 5) - Bit(18)) << 25) | (Bits(16, 2) << 23) | (Bits(0, 4) << 19); return bit_cast<float, uint32_t>(imm32); } // Field used in VFP double immediate move instruction double ImmDoubleField() const { uint64_t imm64 = (Bit(19)*(1LL << 63)) | (((1LL << 8) - Bit(18)) << 54) | (Bits(16, 2)*(1LL << 52)) | (Bits(0, 4)*(1LL << 48)); return bit_cast<double, uint64_t>(imm64); } // Test for data processing instructions of type 0 or 1. // See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition", // section A5.1 "ARM instruction set encoding". bool IsDataProcessing() const { CHECK_NE(ConditionField(), kSpecialCondition); CHECK_EQ(Bits(26, 2), 0); // Type 0 or 1. return ((Bits(20, 5) & 0x19) != 0x10) && ((Bit(25) == 1) || // Data processing immediate. (Bit(4) == 0) || // Data processing register. (Bit(7) == 0)); // Data processing register-shifted register. } // Tests for special encodings of type 0 instructions (extra loads and stores, // as well as multiplications, synchronization primitives, and miscellaneous). // Can only be called for a type 0 or 1 instruction. bool IsMiscellaneous() const { CHECK_EQ(Bits(26, 2), 0); // Type 0 or 1. return ((Bit(25) == 0) && ((Bits(20, 5) & 0x19) == 0x10) && (Bit(7) == 0)); } bool IsMultiplyOrSyncPrimitive() const { CHECK_EQ(Bits(26, 2), 0); // Type 0 or 1. return ((Bit(25) == 0) && (Bits(4, 4) == 9)); } // Test for Supervisor Call instruction. bool IsSvc() const { return ((InstructionBits() & 0xff000000) == 0xef000000); } // Test for Breakpoint instruction. bool IsBkpt() const { return ((InstructionBits() & 0xfff000f0) == 0xe1200070); } // VFP register fields. SRegister SnField() const { return static_cast<SRegister>((Bits(kRnShift, kRnBits) << 1) + Bit(7)); } SRegister SdField() const { return static_cast<SRegister>((Bits(kRdShift, kRdBits) << 1) + Bit(22)); } SRegister SmField() const { return static_cast<SRegister>((Bits(kRmShift, kRmBits) << 1) + Bit(5)); } DRegister DnField() const { return static_cast<DRegister>(Bits(kRnShift, kRnBits) + (Bit(7) << 4)); } DRegister DdField() const { return static_cast<DRegister>(Bits(kRdShift, kRdBits) + (Bit(22) << 4)); } DRegister DmField() const { return static_cast<DRegister>(Bits(kRmShift, kRmBits) + (Bit(5) << 4)); } // Test for VFP data processing or single transfer instructions of type 7. bool IsVFPDataProcessingOrSingleTransfer() const { CHECK_NE(ConditionField(), kSpecialCondition); CHECK_EQ(TypeField(), 7); return ((Bit(24) == 0) && (Bits(9, 3) == 5)); // Bit(4) == 0: Data Processing // Bit(4) == 1: 8, 16, or 32-bit Transfer between ARM Core and VFP } // Test for VFP 64-bit transfer instructions of type 6. bool IsVFPDoubleTransfer() const { CHECK_NE(ConditionField(), kSpecialCondition); CHECK_EQ(TypeField(), 6); return ((Bits(21, 4) == 2) && (Bits(9, 3) == 5) && ((Bits(4, 4) & 0xd) == 1)); } // Test for VFP load and store instructions of type 6. bool IsVFPLoadStore() const { CHECK_NE(ConditionField(), kSpecialCondition); CHECK_EQ(TypeField(), 6); return ((Bits(20, 5) & 0x12) == 0x10) && (Bits(9, 3) == 5); } // Special accessors that test for existence of a value. bool HasS() const { return SField() == 1; } bool HasB() const { return BField() == 1; } bool HasW() const { return WField() == 1; } bool HasL() const { return LField() == 1; } bool HasSign() const { return SignField() == 1; } bool HasH() const { return HField() == 1; } bool HasLink() const { return LinkField() == 1; } // Instructions are read out of a code stream. The only way to get a // reference to an instruction is to convert a pointer. There is no way // to allocate or create instances of class Instr. // Use the At(pc) function to create references to Instr. static Instr* At(uintptr_t pc) { return reinterpret_cast<Instr*>(pc); } Instr* Next() { return this + kInstrSize; } private: // We need to prevent the creation of instances of class Instr. DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); }; } // namespace arm } // namespace art #endif // ART_COMPILER_UTILS_ARM_CONSTANTS_ARM_H_