454 lines
14 KiB
C++
454 lines
14 KiB
C++
/*
|
|
* 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_
|