mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
[VM] Add ARM64 bitfield instructions
R=rmacnak@google.com Also some minor cleanup in the way we encode ARM instructions. I'll be needing these for 32 bit Smis on ARM64. Bug: Change-Id: I5f515590375a2c6ad11bc6f1a80a4f8e27cd82b4 Reviewed-on: https://dart-review.googlesource.com/20668 Commit-Queue: Erik Corry <erikcorry@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
5591f802ae
commit
1109ffcb6a
8 changed files with 545 additions and 138 deletions
|
@ -295,6 +295,19 @@ class Utils {
|
|||
return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
|
||||
}
|
||||
|
||||
// The lowest n bits are 1, the others are 0.
|
||||
static uword NBitMask(uint32_t n) {
|
||||
ASSERT(n <= kBitsPerWord);
|
||||
if (n == kBitsPerWord) {
|
||||
#if defined(TARGET_ARCH_X64)
|
||||
return 0xffffffffffffffffll;
|
||||
#else
|
||||
return 0xffffffff;
|
||||
#endif
|
||||
}
|
||||
return (1ll << n) - 1;
|
||||
}
|
||||
|
||||
static char* StrError(int err, char* buffer, size_t bufsize);
|
||||
};
|
||||
|
||||
|
|
|
@ -73,11 +73,10 @@ void Assembler::EmitType01(Condition cond,
|
|||
Operand o) {
|
||||
ASSERT(rd != kNoRegister);
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
|
||||
type << kTypeShift |
|
||||
static_cast<int32_t>(opcode) << kOpcodeShift |
|
||||
set_cc << kSShift | static_cast<int32_t>(rn) << kRnShift |
|
||||
static_cast<int32_t>(rd) << kRdShift | o.encoding();
|
||||
int32_t encoding =
|
||||
static_cast<int32_t>(cond) << kConditionShift | type << kTypeShift |
|
||||
static_cast<int32_t>(opcode) << kOpcodeShift | set_cc << kSShift |
|
||||
ArmEncode::Rn(rn) | ArmEncode::Rd(rd) | o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -99,8 +98,8 @@ void Assembler::EmitMemOp(Condition cond,
|
|||
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B26 |
|
||||
(ad.kind() == Address::Immediate ? 0 : B25) |
|
||||
(load ? L : 0) | (byte ? B : 0) |
|
||||
(static_cast<int32_t>(rd) << kRdShift) | ad.encoding();
|
||||
(load ? L : 0) | (byte ? B : 0) | ArmEncode::Rd(rd) |
|
||||
ad.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -111,7 +110,7 @@ void Assembler::EmitMemOpAddressMode3(Condition cond,
|
|||
ASSERT(rd != kNoRegister);
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | mode |
|
||||
(static_cast<int32_t>(rd) << kRdShift) | ad.encoding3();
|
||||
ArmEncode::Rd(rd) | ad.encoding3();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -123,8 +122,7 @@ void Assembler::EmitMultiMemOp(Condition cond,
|
|||
ASSERT(base != kNoRegister);
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B27 |
|
||||
am | (load ? L : 0) |
|
||||
(static_cast<int32_t>(base) << kRnShift) | regs;
|
||||
am | (load ? L : 0) | ArmEncode::Rn(base) | regs;
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -135,11 +133,11 @@ void Assembler::EmitShiftImmediate(Condition cond,
|
|||
Operand o) {
|
||||
ASSERT(cond != kNoCondition);
|
||||
ASSERT(o.type() == 1);
|
||||
int32_t encoding =
|
||||
static_cast<int32_t>(cond) << kConditionShift |
|
||||
static_cast<int32_t>(MOV) << kOpcodeShift |
|
||||
static_cast<int32_t>(rd) << kRdShift | o.encoding() << kShiftImmShift |
|
||||
static_cast<int32_t>(opcode) << kShiftShift | static_cast<int32_t>(rm);
|
||||
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
|
||||
static_cast<int32_t>(MOV) << kOpcodeShift |
|
||||
ArmEncode::Rd(rd) | o.encoding() << kShiftImmShift |
|
||||
static_cast<int32_t>(opcode) << kShiftShift |
|
||||
static_cast<int32_t>(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -152,8 +150,7 @@ void Assembler::EmitShiftRegister(Condition cond,
|
|||
ASSERT(o.type() == 0);
|
||||
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift |
|
||||
static_cast<int32_t>(MOV) << kOpcodeShift |
|
||||
static_cast<int32_t>(rd) << kRdShift |
|
||||
o.encoding() << kShiftRegisterShift |
|
||||
ArmEncode::Rd(rd) | o.encoding() << kShiftRegisterShift |
|
||||
static_cast<int32_t>(opcode) << kShiftShift | B4 |
|
||||
static_cast<int32_t>(rm);
|
||||
Emit(encoding);
|
||||
|
@ -266,25 +263,24 @@ void Assembler::clz(Register rd, Register rm, Condition cond) {
|
|||
ASSERT(rd != PC);
|
||||
ASSERT(rm != PC);
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B24 |
|
||||
B22 | B21 | (0xf << 16) |
|
||||
(static_cast<int32_t>(rd) << kRdShift) | (0xf << 8) | B4 |
|
||||
static_cast<int32_t>(rm);
|
||||
B22 | B21 | (0xf << 16) | ArmEncode::Rd(rd) | (0xf << 8) |
|
||||
B4 | static_cast<int32_t>(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
void Assembler::movw(Register rd, uint16_t imm16, Condition cond) {
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | B25 | B24 |
|
||||
((imm16 >> 12) << 16) |
|
||||
static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
|
||||
((imm16 >> 12) << 16) | ArmEncode::Rd(rd) |
|
||||
(imm16 & 0xfff);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
void Assembler::movt(Register rd, uint16_t imm16, Condition cond) {
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = static_cast<int32_t>(cond) << kConditionShift | B25 | B24 |
|
||||
B22 | ((imm16 >> 12) << 16) |
|
||||
static_cast<int32_t>(rd) << kRdShift | (imm16 & 0xfff);
|
||||
B22 | ((imm16 >> 12) << 16) | ArmEncode::Rd(rd) |
|
||||
(imm16 & 0xfff);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -300,10 +296,8 @@ void Assembler::EmitMulOp(Condition cond,
|
|||
ASSERT(rs != kNoRegister);
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = opcode | (static_cast<int32_t>(cond) << kConditionShift) |
|
||||
(static_cast<int32_t>(rn) << kRnShift) |
|
||||
(static_cast<int32_t>(rd) << kRdShift) |
|
||||
(static_cast<int32_t>(rs) << kRsShift) | B7 | B4 |
|
||||
(static_cast<int32_t>(rm) << kRmShift);
|
||||
ArmEncode::Rn(rn) | ArmEncode::Rd(rd) | ArmEncode::Rs(rs) |
|
||||
B7 | B4 | ArmEncode::Rm(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -722,7 +716,7 @@ void Assembler::EmitMultiVSMemOp(Condition cond,
|
|||
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B27 |
|
||||
B26 | B11 | B9 | am | (load ? L : 0) |
|
||||
(static_cast<int32_t>(base) << kRnShift) |
|
||||
ArmEncode::Rn(base) |
|
||||
((static_cast<int32_t>(start) & 0x1) ? D : 0) |
|
||||
((static_cast<int32_t>(start) >> 1) << 12) | count;
|
||||
Emit(encoding);
|
||||
|
@ -743,7 +737,7 @@ void Assembler::EmitMultiVDMemOp(Condition cond,
|
|||
|
||||
int32_t encoding =
|
||||
(static_cast<int32_t>(cond) << kConditionShift) | B27 | B26 | B11 | B9 |
|
||||
B8 | am | (load ? L : 0) | (static_cast<int32_t>(base) << kRnShift) |
|
||||
B8 | am | (load ? L : 0) | ArmEncode::Rn(base) |
|
||||
((static_cast<int32_t>(start) & 0x10) ? D : 0) |
|
||||
((static_cast<int32_t>(start) & 0xf) << 12) | (count << 1) | armv5te;
|
||||
Emit(encoding);
|
||||
|
@ -1353,8 +1347,7 @@ void Assembler::bx(Register rm, Condition cond) {
|
|||
ASSERT(rm != kNoRegister);
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B24 |
|
||||
B21 | (0xfff << 8) | B4 |
|
||||
(static_cast<int32_t>(rm) << kRmShift);
|
||||
B21 | (0xfff << 8) | B4 | ArmEncode::Rm(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1362,8 +1355,7 @@ void Assembler::blx(Register rm, Condition cond) {
|
|||
ASSERT(rm != kNoRegister);
|
||||
ASSERT(cond != kNoCondition);
|
||||
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) | B24 |
|
||||
B21 | (0xfff << 8) | B5 | B4 |
|
||||
(static_cast<int32_t>(rm) << kRmShift);
|
||||
B21 | (0xfff << 8) | B5 | B4 | ArmEncode::Rm(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
|
|
@ -105,6 +105,29 @@ class Label : public ValueObject {
|
|||
DISALLOW_COPY_AND_ASSIGN(Label);
|
||||
};
|
||||
|
||||
class ArmEncode : public AllStatic {
|
||||
public:
|
||||
static inline uint32_t Rd(Register rd) {
|
||||
ASSERT(rd < 16);
|
||||
return static_cast<uint32_t>(rd) << kRdShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rm(Register rm) {
|
||||
ASSERT(rm < 16);
|
||||
return static_cast<uint32_t>(rm) << kRmShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rn(Register rn) {
|
||||
ASSERT(rn < 16);
|
||||
return static_cast<uint32_t>(rn) << kRnShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rs(Register rs) {
|
||||
ASSERT(rs < 16);
|
||||
return static_cast<uint32_t>(rs) << kRsShift;
|
||||
}
|
||||
};
|
||||
|
||||
// Encodes Addressing Mode 1 - Data-processing operands.
|
||||
class Operand : public ValueObject {
|
||||
public:
|
||||
|
@ -265,7 +288,7 @@ class Address : public ValueObject {
|
|||
} else {
|
||||
encoding_ = am | offset;
|
||||
}
|
||||
encoding_ |= static_cast<uint32_t>(rn) << kRnShift;
|
||||
encoding_ |= ArmEncode::Rn(rn);
|
||||
}
|
||||
|
||||
// There is no register offset mode unless Mode is Offset, in which case the
|
||||
|
@ -284,7 +307,7 @@ class Address : public ValueObject {
|
|||
} else {
|
||||
kind_ = ScaledIndexRegister;
|
||||
}
|
||||
encoding_ = o.encoding() | am | (static_cast<uint32_t>(rn) << kRnShift);
|
||||
encoding_ = o.encoding() | am | ArmEncode::Rn(rn);
|
||||
}
|
||||
|
||||
// There is no shifted register mode with a register shift.
|
||||
|
|
|
@ -82,6 +82,44 @@ class Label : public ValueObject {
|
|||
DISALLOW_COPY_AND_ASSIGN(Label);
|
||||
};
|
||||
|
||||
class Arm64Encode : public AllStatic {
|
||||
public:
|
||||
static inline uint32_t Rd(Register rd) {
|
||||
ASSERT(rd <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(rd)) << kRdShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rm(Register rm) {
|
||||
ASSERT(rm <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(rm)) << kRmShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rn(Register rn) {
|
||||
ASSERT(rn <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(rn)) << kRnShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Ra(Register ra) {
|
||||
ASSERT(ra <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(ra)) << kRaShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rs(Register rs) {
|
||||
ASSERT(rs <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(rs)) << kRsShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rt(Register rt) {
|
||||
ASSERT(rt <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(rt)) << kRtShift;
|
||||
}
|
||||
|
||||
static inline uint32_t Rt2(Register rt2) {
|
||||
ASSERT(rt2 <= ZR);
|
||||
return static_cast<uint32_t>(ConcreteRegister(rt2)) << kRt2Shift;
|
||||
}
|
||||
};
|
||||
|
||||
class Address : public ValueObject {
|
||||
public:
|
||||
Address(const Address& other)
|
||||
|
@ -119,20 +157,17 @@ class Address : public ValueObject {
|
|||
OperandSize sz = kDoubleWord) {
|
||||
ASSERT((rn != kNoRegister) && (rn != R31) && (rn != ZR));
|
||||
ASSERT(CanHoldOffset(offset, at, sz));
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const int32_t scale = Log2OperandSizeBytes(sz);
|
||||
if ((at == Offset) && Utils::IsUint(12 + scale, offset) &&
|
||||
(offset == ((offset >> scale) << scale))) {
|
||||
encoding_ = B24 | ((offset >> scale) << kImm12Shift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift);
|
||||
encoding_ =
|
||||
B24 | ((offset >> scale) << kImm12Shift) | Arm64Encode::Rn(rn);
|
||||
} else if ((at == Offset) && Utils::IsInt(9, offset)) {
|
||||
encoding_ = ((offset & 0x1ff) << kImm9Shift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift);
|
||||
encoding_ = ((offset & 0x1ff) << kImm9Shift) | Arm64Encode::Rn(rn);
|
||||
} else if ((at == PreIndex) || (at == PostIndex)) {
|
||||
ASSERT(Utils::IsInt(9, offset));
|
||||
int32_t idx = (at == PostIndex) ? B10 : (B11 | B10);
|
||||
encoding_ = idx | ((offset & 0x1ff) << kImm9Shift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift);
|
||||
encoding_ = idx | ((offset & 0x1ff) << kImm9Shift) | Arm64Encode::Rn(rn);
|
||||
} else {
|
||||
ASSERT((at == PairOffset) || (at == PairPreIndex) ||
|
||||
(at == PairPostIndex));
|
||||
|
@ -154,10 +189,10 @@ class Address : public ValueObject {
|
|||
break;
|
||||
}
|
||||
encoding_ = idx | (((offset >> scale) << kImm7Shift) & kImm7Mask) |
|
||||
(static_cast<int32_t>(crn) << kRnShift);
|
||||
Arm64Encode::Rn(rn);
|
||||
}
|
||||
type_ = at;
|
||||
base_ = crn;
|
||||
base_ = ConcreteRegister(rn);
|
||||
}
|
||||
|
||||
// This addressing mode does not exist.
|
||||
|
@ -226,14 +261,11 @@ class Address : public ValueObject {
|
|||
// Can only scale when ext = UXTX.
|
||||
ASSERT((scale != Scaled) || (ext == UXTX));
|
||||
ASSERT((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
const int32_t s = (scale == Scaled) ? B12 : 0;
|
||||
encoding_ = B21 | B11 | s | (static_cast<int32_t>(crn) << kRnShift) |
|
||||
(static_cast<int32_t>(crm) << kRmShift) |
|
||||
encoding_ = B21 | B11 | s | Arm64Encode::Rn(rn) | Arm64Encode::Rm(rm) |
|
||||
(static_cast<int32_t>(ext) << kExtendTypeShift);
|
||||
type_ = Reg;
|
||||
base_ = crn;
|
||||
base_ = ConcreteRegister(rn);
|
||||
}
|
||||
|
||||
static OperandSize OperandSizeFor(intptr_t cid) {
|
||||
|
@ -338,16 +370,14 @@ class Operand : public ValueObject {
|
|||
|
||||
explicit Operand(Register rm) {
|
||||
ASSERT((rm != R31) && (rm != CSP));
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
encoding_ = (static_cast<int32_t>(crm) << kRmShift);
|
||||
encoding_ = Arm64Encode::Rm(rm);
|
||||
type_ = Shifted;
|
||||
}
|
||||
|
||||
Operand(Register rm, Shift shift, int32_t imm) {
|
||||
ASSERT(Utils::IsUint(6, imm));
|
||||
ASSERT((rm != R31) && (rm != CSP));
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
encoding_ = (imm << kImm6Shift) | (static_cast<int32_t>(crm) << kRmShift) |
|
||||
encoding_ = (imm << kImm6Shift) | Arm64Encode::Rm(rm) |
|
||||
(static_cast<int32_t>(shift) << kShiftTypeShift);
|
||||
type_ = Shifted;
|
||||
}
|
||||
|
@ -358,8 +388,7 @@ class Operand : public ValueObject {
|
|||
Operand(Register rm, Extend extend, int32_t imm) {
|
||||
ASSERT(Utils::IsUint(3, imm));
|
||||
ASSERT((rm != R31) && (rm != CSP));
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
encoding_ = B21 | (static_cast<int32_t>(crm) << kRmShift) |
|
||||
encoding_ = B21 | Arm64Encode::Rm(rm) |
|
||||
(static_cast<int32_t>(extend) << kExtendTypeShift) |
|
||||
((imm & 0x7) << kImm3Shift);
|
||||
type_ = Extended;
|
||||
|
@ -382,7 +411,8 @@ class Operand : public ValueObject {
|
|||
// Encodes the value of an immediate for a logical operation.
|
||||
// Since these values are difficult to craft by hand, instead pass the
|
||||
// logical mask to the function IsImmLogical to get n, imm_s, and
|
||||
// imm_r.
|
||||
// imm_r. Takes s before r like DecodeBitMasks from Appendix G but unlike
|
||||
// the disassembly of the *bfm instructions.
|
||||
Operand(uint8_t n, int8_t imm_s, int8_t imm_r) {
|
||||
ASSERT((n == 1) || (n == 0));
|
||||
ASSERT(Utils::IsUint(6, imm_s) && Utils::IsUint(6, imm_r));
|
||||
|
@ -578,6 +608,127 @@ class Assembler : public ValueObject {
|
|||
// PC relative immediate add. imm is in bytes.
|
||||
void adr(Register rd, const Immediate& imm) { EmitPCRelOp(ADR, rd, imm); }
|
||||
|
||||
// Bitfield operations.
|
||||
// Bitfield move.
|
||||
// If s >= r then Rd[s-r:0] := Rn[s:r], else Rd[bitwidth+s-r:bitwidth-r] :=
|
||||
// Rn[s:0].
|
||||
void bfm(Register rd,
|
||||
Register rn,
|
||||
int r_imm,
|
||||
int s_imm,
|
||||
OperandSize size = kDoubleWord) {
|
||||
EmitBitfieldOp(BFM, rd, rn, r_imm, s_imm, size);
|
||||
}
|
||||
|
||||
// Signed bitfield move.
|
||||
void sbfm(Register rd,
|
||||
Register rn,
|
||||
int r_imm,
|
||||
int s_imm,
|
||||
OperandSize size = kDoubleWord) {
|
||||
EmitBitfieldOp(SBFM, rd, rn, r_imm, s_imm, size);
|
||||
}
|
||||
|
||||
// Unsigned bitfield move.
|
||||
void ubfm(Register rd,
|
||||
Register rn,
|
||||
int r_imm,
|
||||
int s_imm,
|
||||
OperandSize size = kDoubleWord) {
|
||||
EmitBitfieldOp(UBFM, rd, rn, r_imm, s_imm, size);
|
||||
}
|
||||
|
||||
// Bitfield insert. Takes the low width bits and replaces bits in rd with
|
||||
// them, starting at low_bit.
|
||||
void bfi(Register rd,
|
||||
Register rn,
|
||||
int low_bit,
|
||||
int width,
|
||||
OperandSize size = kDoubleWord) {
|
||||
int wordsize = size == kDoubleWord ? 64 : 32;
|
||||
EmitBitfieldOp(BFM, rd, rn, -low_bit & (wordsize - 1), width - 1, size);
|
||||
}
|
||||
|
||||
// Bitfield extract and insert low. Takes width bits, starting at low_bit and
|
||||
// replaces the low width bits of rd with them.
|
||||
void bfxil(Register rd,
|
||||
Register rn,
|
||||
int low_bit,
|
||||
int width,
|
||||
OperandSize size = kDoubleWord) {
|
||||
EmitBitfieldOp(BFM, rd, rn, low_bit, low_bit + width - 1, size);
|
||||
}
|
||||
|
||||
// Signed bitfield insert in zero. Takes the low width bits, sign extends
|
||||
// them and writes them to rd, starting at low_bit, and zeroing bits below
|
||||
// that.
|
||||
void sbfiz(Register rd,
|
||||
Register rn,
|
||||
int low_bit,
|
||||
int width,
|
||||
OperandSize size = kDoubleWord) {
|
||||
int wordsize = size == kDoubleWord ? 64 : 32;
|
||||
EmitBitfieldOp(SBFM, rd, rn, (wordsize - low_bit) & (wordsize - 1),
|
||||
width - 1, size);
|
||||
}
|
||||
|
||||
// Signed bitfield extract. Takes width bits, starting at low_bit, sign
|
||||
// extends them and writes them to rd, starting at the lowest bit.
|
||||
void sbfx(Register rd,
|
||||
Register rn,
|
||||
int low_bit,
|
||||
int width,
|
||||
OperandSize size = kDoubleWord) {
|
||||
EmitBitfieldOp(SBFM, rd, rn, low_bit, low_bit + width - 1, size);
|
||||
}
|
||||
|
||||
// Unsigned bitfield insert in zero. Takes the low width bits and writes
|
||||
// them to rd, starting at low_bit, and zeroing bits above and below.
|
||||
void ubfiz(Register rd,
|
||||
Register rn,
|
||||
int low_bit,
|
||||
int width,
|
||||
OperandSize size = kDoubleWord) {
|
||||
int wordsize = size == kDoubleWord ? 64 : 32;
|
||||
EmitBitfieldOp(UBFM, rd, rn, (width - low_bit) & (wordsize - 1),
|
||||
wordsize - 1, size);
|
||||
}
|
||||
|
||||
// Unsigned bitfield extract. Takes the width bits, starting at low_bit and
|
||||
// writes them to the low bits of rd zeroing bits above.
|
||||
void ubfx(Register rd,
|
||||
Register rn,
|
||||
int low_bit,
|
||||
int width,
|
||||
OperandSize size = kDoubleWord) {
|
||||
EmitBitfieldOp(UBFM, rd, rn, low_bit, low_bit + width - 1, size);
|
||||
}
|
||||
|
||||
// Sign extend byte->64 bit.
|
||||
void sxtb(Register rd, Register rn) {
|
||||
EmitBitfieldOp(SBFM, rd, rn, 0, 7, kDoubleWord);
|
||||
}
|
||||
|
||||
// Sign extend halfword->64 bit.
|
||||
void sxth(Register rd, Register rn) {
|
||||
EmitBitfieldOp(SBFM, rd, rn, 0, 15, kDoubleWord);
|
||||
}
|
||||
|
||||
// Sign extend word->64 bit.
|
||||
void sxtw(Register rd, Register rn) {
|
||||
EmitBitfieldOp(SBFM, rd, rn, 0, 31, kDoubleWord);
|
||||
}
|
||||
|
||||
// Zero/unsigned extend byte->64 bit.
|
||||
void uxtb(Register rd, Register rn) {
|
||||
EmitBitfieldOp(UBFM, rd, rn, 0, 7, kDoubleWord);
|
||||
}
|
||||
|
||||
// Zero/unsigned extend halfword->64 bit.
|
||||
void uxth(Register rd, Register rn) {
|
||||
EmitBitfieldOp(UBFM, rd, rn, 0, 15, kDoubleWord);
|
||||
}
|
||||
|
||||
// Logical immediate operations.
|
||||
void andi(Register rd, Register rn, const Immediate& imm) {
|
||||
Operand imm_op;
|
||||
|
@ -1138,12 +1289,15 @@ class Assembler : public ValueObject {
|
|||
void tst(Register rn, Operand o) { ands(ZR, rn, o); }
|
||||
void tsti(Register rn, const Immediate& imm) { andis(ZR, rn, imm); }
|
||||
|
||||
// We use an alias of add, where ARM recommends an alias of ubfm.
|
||||
void LslImmediate(Register rd, Register rn, int shift) {
|
||||
add(rd, ZR, Operand(rn, LSL, shift));
|
||||
}
|
||||
// We use an alias of add, where ARM recommends an alias of ubfm.
|
||||
void LsrImmediate(Register rd, Register rn, int shift) {
|
||||
add(rd, ZR, Operand(rn, LSR, shift));
|
||||
}
|
||||
// We use an alias of add, where ARM recommends an alias of sbfm.
|
||||
void AsrImmediate(Register rd, Register rn, int shift) {
|
||||
add(rd, ZR, Operand(rn, ASR, shift));
|
||||
}
|
||||
|
@ -1441,16 +1595,11 @@ class Assembler : public ValueObject {
|
|||
Register rm) {
|
||||
ASSERT((rd != R31) && (rn != R31) && (rm != R31));
|
||||
ASSERT((rd != CSP) && (rn != CSP) && (rm != CSP));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t s = set_flags ? B29 : 0;
|
||||
const int32_t op = subtract ? SBC : ADC;
|
||||
const int32_t encoding = op | size | s |
|
||||
(static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift) |
|
||||
(static_cast<int32_t>(crm) << kRmShift);
|
||||
const int32_t encoding = op | size | s | Arm64Encode::Rd(rd) |
|
||||
Arm64Encode::Rn(rn) | Arm64Encode::Rm(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1463,9 +1612,28 @@ class Assembler : public ValueObject {
|
|||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t s = set_flags ? B29 : 0;
|
||||
const int32_t encoding =
|
||||
op | size | s | (static_cast<int32_t>(rd) << kRdShift) |
|
||||
(static_cast<int32_t>(rn) << kRnShift) | o.encoding();
|
||||
const int32_t encoding = op | size | s | Arm64Encode::Rd(rd) |
|
||||
Arm64Encode::Rn(rn) | o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
// Follows the *bfm instructions in taking r before s (unlike the Operand
|
||||
// constructor, which follows DecodeBitMasks from Appendix G).
|
||||
void EmitBitfieldOp(BitfieldOp op,
|
||||
Register rd,
|
||||
Register rn,
|
||||
int r_imm,
|
||||
int s_imm,
|
||||
OperandSize size) {
|
||||
if (size != kDoubleWord) {
|
||||
ASSERT(size == kWord);
|
||||
ASSERT(r_imm < 32 && s_imm < 32);
|
||||
} else {
|
||||
ASSERT(r_imm < 64 && s_imm < 64);
|
||||
}
|
||||
const int32_t instr = op | (size == kDoubleWord ? Bitfield64 : 0);
|
||||
const int32_t encoding = instr | Operand(0, s_imm, r_imm).encoding() |
|
||||
Arm64Encode::Rd(rd) | Arm64Encode::Rn(rn);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1481,11 +1649,8 @@ class Assembler : public ValueObject {
|
|||
ASSERT((op != ANDIS) || (rd != CSP)); // op == ANDIS => rd != CSP.
|
||||
ASSERT(o.type() == Operand::BitfieldImm);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const int32_t encoding =
|
||||
op | size | (static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift) | o.encoding();
|
||||
op | size | Arm64Encode::Rd(rd) | Arm64Encode::Rn(rn) | o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1499,11 +1664,8 @@ class Assembler : public ValueObject {
|
|||
ASSERT((rd != CSP) && (rn != CSP));
|
||||
ASSERT(o.type() == Operand::Shifted);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const int32_t encoding =
|
||||
op | size | (static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift) | o.encoding();
|
||||
op | size | Arm64Encode::Rd(rd) | Arm64Encode::Rn(rn) | o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1516,9 +1678,8 @@ class Assembler : public ValueObject {
|
|||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t s = set_flags ? B29 : 0;
|
||||
const int32_t encoding =
|
||||
op | size | s | (static_cast<int32_t>(rd) << kRdShift) |
|
||||
(static_cast<int32_t>(rn) << kRnShift) | o.encoding();
|
||||
const int32_t encoding = op | size | s | Arm64Encode::Rd(rd) |
|
||||
Arm64Encode::Rn(rn) | o.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1583,11 +1744,9 @@ class Assembler : public ValueObject {
|
|||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
ASSERT(Utils::IsInt(21, imm) && ((imm & 0x3) == 0));
|
||||
ASSERT((rt != CSP) && (rt != R31));
|
||||
const Register crt = ConcreteRegister(rt);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoded_offset = EncodeImm19BranchOffset(imm, 0);
|
||||
const int32_t encoding =
|
||||
op | size | (static_cast<int32_t>(crt) << kRtShift) | encoded_offset;
|
||||
const int32_t encoding = op | size | Arm64Encode::Rt(rt) | encoded_offset;
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1679,8 +1838,7 @@ class Assembler : public ValueObject {
|
|||
|
||||
void EmitUnconditionalBranchRegOp(UnconditionalBranchRegOp op, Register rn) {
|
||||
ASSERT((rn != CSP) && (rn != R31));
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const int32_t encoding = op | (static_cast<int32_t>(crn) << kRnShift);
|
||||
const int32_t encoding = op | Arm64Encode::Rn(rn);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1701,7 +1859,7 @@ class Assembler : public ValueObject {
|
|||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoding =
|
||||
op | size | (static_cast<int32_t>(rd) << kRdShift) |
|
||||
op | size | Arm64Encode::Rd(rd) |
|
||||
(static_cast<int32_t>(hw_idx) << kHWShift) |
|
||||
(static_cast<int32_t>(imm.value() & 0xffff) << kImm16Shift);
|
||||
Emit(encoding);
|
||||
|
@ -1719,10 +1877,8 @@ class Assembler : public ValueObject {
|
|||
ASSERT((rn != kNoRegister) && (rn != ZR));
|
||||
ASSERT((rt != kNoRegister) && (rt != ZR));
|
||||
|
||||
const int32_t encoding =
|
||||
op | size | (static_cast<int32_t>(ConcreteRegister(rs)) << kRsShift) |
|
||||
(static_cast<int32_t>(ConcreteRegister(rn)) << kRnShift) |
|
||||
(static_cast<int32_t>(ConcreteRegister(rt)) << kRtShift);
|
||||
const int32_t encoding = op | size | Arm64Encode::Rs(rs) |
|
||||
Arm64Encode::Rn(rn) | Arm64Encode::Rt(rt);
|
||||
|
||||
Emit(encoding);
|
||||
}
|
||||
|
@ -1731,11 +1887,9 @@ class Assembler : public ValueObject {
|
|||
Register rt,
|
||||
Address a,
|
||||
OperandSize sz) {
|
||||
const Register crt = ConcreteRegister(rt);
|
||||
const int32_t size = Log2OperandSizeBytes(sz);
|
||||
const int32_t encoding = op | ((size & 0x3) << kSzShift) |
|
||||
(static_cast<int32_t>(crt) << kRtShift) |
|
||||
a.encoding();
|
||||
const int32_t encoding =
|
||||
op | ((size & 0x3) << kSzShift) | Arm64Encode::Rt(rt) | a.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1745,10 +1899,8 @@ class Assembler : public ValueObject {
|
|||
OperandSize sz) {
|
||||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
ASSERT((rt != CSP) && (rt != R31));
|
||||
const Register crt = ConcreteRegister(rt);
|
||||
const int32_t size = (sz == kDoubleWord) ? B30 : 0;
|
||||
const int32_t encoding =
|
||||
op | size | (static_cast<int32_t>(crt) << kRtShift) | a.encoding();
|
||||
const int32_t encoding = op | size | Arm64Encode::Rt(rt) | a.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1760,8 +1912,6 @@ class Assembler : public ValueObject {
|
|||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
ASSERT((rt != CSP) && (rt != R31));
|
||||
ASSERT((rt2 != CSP) && (rt2 != R31));
|
||||
const Register crt = ConcreteRegister(rt);
|
||||
const Register crt2 = ConcreteRegister(rt2);
|
||||
int32_t opc = 0;
|
||||
switch (sz) {
|
||||
case kDoubleWord:
|
||||
|
@ -1778,19 +1928,16 @@ class Assembler : public ValueObject {
|
|||
break;
|
||||
}
|
||||
const int32_t encoding =
|
||||
opc | op | (static_cast<int32_t>(crt) << kRtShift) |
|
||||
(static_cast<int32_t>(crt2) << kRt2Shift) | a.encoding();
|
||||
opc | op | Arm64Encode::Rt(rt) | Arm64Encode::Rt2(rt2) | a.encoding();
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
void EmitPCRelOp(PCRelOp op, Register rd, const Immediate& imm) {
|
||||
ASSERT(Utils::IsInt(21, imm.value()));
|
||||
ASSERT((rd != R31) && (rd != CSP));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const int32_t loimm = (imm.value() & 0x3) << 29;
|
||||
const int32_t hiimm = ((imm.value() >> 2) << kImm19Shift) & kImm19Mask;
|
||||
const int32_t encoding =
|
||||
op | loimm | hiimm | (static_cast<int32_t>(crd) << kRdShift);
|
||||
const int32_t encoding = op | loimm | hiimm | Arm64Encode::Rd(rd);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1800,12 +1947,9 @@ class Assembler : public ValueObject {
|
|||
OperandSize sz) {
|
||||
ASSERT((rd != CSP) && (rn != CSP));
|
||||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoding = op | size |
|
||||
(static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift);
|
||||
const int32_t encoding =
|
||||
op | size | Arm64Encode::Rd(rd) | Arm64Encode::Rn(rn);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1816,14 +1960,9 @@ class Assembler : public ValueObject {
|
|||
OperandSize sz) {
|
||||
ASSERT((rd != CSP) && (rn != CSP) && (rm != CSP));
|
||||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoding = op | size |
|
||||
(static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift) |
|
||||
(static_cast<int32_t>(crm) << kRmShift);
|
||||
const int32_t encoding = op | size | Arm64Encode::Rd(rd) |
|
||||
Arm64Encode::Rn(rn) | Arm64Encode::Rm(rm);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1835,16 +1974,10 @@ class Assembler : public ValueObject {
|
|||
OperandSize sz) {
|
||||
ASSERT((rd != CSP) && (rn != CSP) && (rm != CSP) && (ra != CSP));
|
||||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
const Register cra = ConcreteRegister(ra);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoding = op | size |
|
||||
(static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift) |
|
||||
(static_cast<int32_t>(crm) << kRmShift) |
|
||||
(static_cast<int32_t>(cra) << kRaShift);
|
||||
const int32_t encoding = op | size | Arm64Encode::Rd(rd) |
|
||||
Arm64Encode::Rn(rn) | Arm64Encode::Rm(rm) |
|
||||
Arm64Encode::Ra(ra);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
@ -1856,14 +1989,9 @@ class Assembler : public ValueObject {
|
|||
OperandSize sz) {
|
||||
ASSERT((rd != CSP) && (rn != CSP) && (rm != CSP));
|
||||
ASSERT((sz == kDoubleWord) || (sz == kWord) || (sz == kUnsignedWord));
|
||||
const Register crd = ConcreteRegister(rd);
|
||||
const Register crn = ConcreteRegister(rn);
|
||||
const Register crm = ConcreteRegister(rm);
|
||||
const int32_t size = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoding = op | size |
|
||||
(static_cast<int32_t>(crd) << kRdShift) |
|
||||
(static_cast<int32_t>(crn) << kRnShift) |
|
||||
(static_cast<int32_t>(crm) << kRmShift) |
|
||||
const int32_t encoding = op | size | Arm64Encode::Rd(rd) |
|
||||
Arm64Encode::Rn(rn) | Arm64Encode::Rm(rm) |
|
||||
(static_cast<int32_t>(cond) << kSelCondShift);
|
||||
Emit(encoding);
|
||||
}
|
||||
|
@ -1880,8 +2008,8 @@ class Assembler : public ValueObject {
|
|||
OperandSize sz = kDoubleWord) {
|
||||
ASSERT((sz == kDoubleWord) || (sz == kWord));
|
||||
const int32_t sfield = (sz == kDoubleWord) ? B31 : 0;
|
||||
const int32_t encoding = op | (static_cast<int32_t>(rd) << kRdShift) |
|
||||
(static_cast<int32_t>(rn) << kRnShift) | sfield;
|
||||
const int32_t encoding =
|
||||
op | Arm64Encode::Rd(rd) | Arm64Encode::Rn(rn) | sfield;
|
||||
Emit(encoding);
|
||||
}
|
||||
|
||||
|
|
|
@ -1905,6 +1905,146 @@ ASSEMBLER_TEST_RUN(CsnegTrue, test) {
|
|||
EXPECT_EQ(1234, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Ubfx, assembler) {
|
||||
__ LoadImmediate(R1, 0x819);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ ubfx(R0, R1, 4, 8);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Ubfx, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0x81, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sbfx, assembler) {
|
||||
__ LoadImmediate(R1, 0x819);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ sbfx(R0, R1, 4, 8);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Sbfx, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(-0x7f, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Bfi, assembler) {
|
||||
__ LoadImmediate(R1, 0x819);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a);
|
||||
__ bfi(R0, R1, 12, 5);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Bfi, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0x5a5b9a5a, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Bfxil, assembler) {
|
||||
__ LoadImmediate(R1, 0x819);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a);
|
||||
__ bfxil(R0, R1, 4, 8);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Bfxil, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0x5a5a5a81, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sbfiz, assembler) {
|
||||
__ LoadImmediate(R1, 0x819);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ sbfiz(R0, R1, 4, 12);
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Sbfiz, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(-0x7e70, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sxtb, assembler) {
|
||||
__ LoadImmediate(R1, 0xff);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ sxtb(R0, R1);
|
||||
__ LoadImmediate(R2, 0x2a);
|
||||
__ LoadImmediate(R1, 0x5a5a5a5a); // Overwritten.
|
||||
__ sxtb(R1, R2);
|
||||
__ add(R0, R0, Operand(R1));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Sxtb, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0x29, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sxth, assembler) {
|
||||
__ LoadImmediate(R1, 0xffff);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ sxth(R0, R1);
|
||||
__ LoadImmediate(R2, 0x1002a);
|
||||
__ LoadImmediate(R1, 0x5a5a5a5a); // Overwritten.
|
||||
__ sxth(R1, R2);
|
||||
__ add(R0, R0, Operand(R1));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Sxth, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0x29, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Sxtw, assembler) {
|
||||
__ LoadImmediate(R1, 0xffffffffll);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ sxtw(R0, R1);
|
||||
__ LoadImmediate(R2, 0x10000002all);
|
||||
__ LoadImmediate(R1, 0x5a5a5a5a); // Overwritten.
|
||||
__ sxtw(R1, R2);
|
||||
__ add(R0, R0, Operand(R1));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Sxtw, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0x29, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Uxtb, assembler) {
|
||||
__ LoadImmediate(R1, -1);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ uxtb(R0, R1);
|
||||
__ LoadImmediate(R2, 0x12a);
|
||||
__ LoadImmediate(R1, 0x5a5a5a5a); // Overwritten.
|
||||
__ uxtb(R1, R2);
|
||||
__ add(R0, R0, Operand(R1));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Uxtb, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0xff + 0x2a, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_GENERATE(Uxth, assembler) {
|
||||
__ LoadImmediate(R1, -1);
|
||||
__ LoadImmediate(R0, 0x5a5a5a5a); // Overwritten.
|
||||
__ uxth(R0, R1);
|
||||
__ LoadImmediate(R2, 0x1002a);
|
||||
__ LoadImmediate(R1, 0x5a5a5a5a); // Overwritten.
|
||||
__ uxth(R1, R2);
|
||||
__ add(R0, R0, Operand(R1));
|
||||
__ ret();
|
||||
}
|
||||
|
||||
ASSEMBLER_TEST_RUN(Uxth, test) {
|
||||
typedef int64_t (*Int64Return)() DART_UNUSED;
|
||||
EXPECT_EQ(0xffff + 0x2a, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
|
||||
}
|
||||
|
||||
// Floating point move immediate, to/from integer register.
|
||||
ASSEMBLER_TEST_GENERATE(Fmovdi, assembler) {
|
||||
__ LoadDImmediate(V0, 1.0);
|
||||
|
|
|
@ -503,12 +503,25 @@ int ARM64Decoder::FormatOption(Instr* instr, const char* format) {
|
|||
remaining_size_in_buffer(), "0x%" Px64, imm);
|
||||
return ret;
|
||||
} else {
|
||||
ASSERT(STRING_STARTS_WITH(format, "immd"));
|
||||
double dimm =
|
||||
bit_cast<double, int64_t>(Instr::VFPExpandImm(instr->Imm8Field()));
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(), "%f", dimm);
|
||||
return 4;
|
||||
ASSERT(STRING_STARTS_WITH(format, "imm"));
|
||||
if (format[3] == 'd') {
|
||||
double dimm = bit_cast<double, int64_t>(
|
||||
Instr::VFPExpandImm(instr->Imm8Field()));
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(), "%f", dimm);
|
||||
return 4;
|
||||
} else if (format[3] == 'r') {
|
||||
int immr = instr->ImmRField();
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(), "#%d", immr);
|
||||
return 4;
|
||||
} else {
|
||||
ASSERT(format[3] == 's');
|
||||
int imms = instr->ImmSField();
|
||||
buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
||||
remaining_size_in_buffer(), "#%d", imms);
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'm': {
|
||||
|
@ -765,6 +778,47 @@ void ARM64Decoder::DecodeAddSubImm(Instr* instr) {
|
|||
}
|
||||
}
|
||||
|
||||
void ARM64Decoder::DecodeBitfield(Instr* instr) {
|
||||
int op = instr->Bits(29, 2);
|
||||
int r_imm = instr->ImmRField();
|
||||
int s_imm = instr->ImmSField();
|
||||
switch (op) {
|
||||
case 0:
|
||||
if (r_imm == 0) {
|
||||
if (s_imm == 7) {
|
||||
Format(instr, "sxtb 'rd, 'rn");
|
||||
break;
|
||||
} else if (s_imm == 15) {
|
||||
Format(instr, "sxth 'rd, 'rn");
|
||||
break;
|
||||
} else if (s_imm == 31) {
|
||||
Format(instr, "sxtw 'rd, 'rn");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Format(instr, "sbfm'sf 'rd, 'rn, 'immr, 'imms");
|
||||
break;
|
||||
case 1:
|
||||
Format(instr, "bfm'sf 'rd, 'rn, 'immr, 'imms");
|
||||
break;
|
||||
case 2:
|
||||
if (r_imm == 0) {
|
||||
if (s_imm == 7) {
|
||||
Format(instr, "uxtb 'rd, 'rn");
|
||||
break;
|
||||
} else if (s_imm == 15) {
|
||||
Format(instr, "uxth 'rd, 'rn");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Format(instr, "ubfm'sf 'rd, 'rn, 'immr, 'imms");
|
||||
break;
|
||||
default:
|
||||
Unknown(instr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ARM64Decoder::DecodeLogicalImm(Instr* instr) {
|
||||
int op = instr->Bits(29, 2);
|
||||
switch (op) {
|
||||
|
@ -805,6 +859,8 @@ void ARM64Decoder::DecodeDPImmediate(Instr* instr) {
|
|||
DecodeMoveWide(instr);
|
||||
} else if (instr->IsAddSubImmOp()) {
|
||||
DecodeAddSubImm(instr);
|
||||
} else if (instr->IsBitfieldOp()) {
|
||||
DecodeBitfield(instr);
|
||||
} else if (instr->IsLogicalImmOp()) {
|
||||
DecodeLogicalImm(instr);
|
||||
} else if (instr->IsPCRelOp()) {
|
||||
|
|
|
@ -436,6 +436,16 @@ enum AddSubImmOp {
|
|||
SUBI = AddSubImmFixed | B30,
|
||||
};
|
||||
|
||||
// C3.4.2
|
||||
enum BitfieldOp {
|
||||
BitfieldMask = 0x1f800000,
|
||||
BitfieldFixed = 0x13000000,
|
||||
SBFM = BitfieldFixed,
|
||||
BFM = BitfieldFixed | B29,
|
||||
UBFM = BitfieldFixed | B30,
|
||||
Bitfield64 = B31 | B22,
|
||||
};
|
||||
|
||||
// C3.4.4
|
||||
enum LogicalImmOp {
|
||||
LogicalImmMask = 0x1f800000,
|
||||
|
@ -663,6 +673,7 @@ enum FPIntCvtOp {
|
|||
_V(LoadRegLiteral) \
|
||||
_V(LoadStoreExclusive) \
|
||||
_V(AddSubImm) \
|
||||
_V(Bitfield) \
|
||||
_V(LogicalImm) \
|
||||
_V(MoveWide) \
|
||||
_V(PCRel) \
|
||||
|
|
|
@ -1292,6 +1292,48 @@ void Simulator::DecodeAddSubImm(Instr* instr) {
|
|||
}
|
||||
}
|
||||
|
||||
void Simulator::DecodeBitfield(Instr* instr) {
|
||||
int bitwidth = instr->SFField() == 0 ? 32 : 64;
|
||||
unsigned op = instr->Bits(29, 2);
|
||||
ASSERT(op <= 2);
|
||||
bool sign_extend = op == 0;
|
||||
bool zero_extend = op == 2;
|
||||
ASSERT(instr->NField() == instr->SFField());
|
||||
const Register rn = instr->RnField();
|
||||
const Register rd = instr->RdField();
|
||||
int64_t result = get_register(rn, instr->RnMode());
|
||||
int r_bit = instr->ImmRField();
|
||||
int s_bit = instr->ImmSField();
|
||||
result &= Utils::NBitMask(bitwidth);
|
||||
ASSERT(s_bit < bitwidth && r_bit < bitwidth);
|
||||
// See ARM v8 Instruction set overview 5.4.5.
|
||||
// If s >= r then Rd[s-r:0] := Rn[s:r], else Rd[bitwidth+s-r:bitwidth-r] :=
|
||||
// Rn[s:0].
|
||||
uword mask = Utils::NBitMask(s_bit + 1);
|
||||
if (s_bit >= r_bit) {
|
||||
mask >>= r_bit;
|
||||
result >>= r_bit;
|
||||
} else {
|
||||
result <<= bitwidth - r_bit;
|
||||
mask <<= bitwidth - r_bit;
|
||||
}
|
||||
result &= mask;
|
||||
if (sign_extend) {
|
||||
int highest_bit = (s_bit - r_bit) & (bitwidth - 1);
|
||||
int shift = bitwidth - highest_bit - 1;
|
||||
result <<= shift;
|
||||
result = static_cast<word>(result) >> shift;
|
||||
} else if (!zero_extend) {
|
||||
const int64_t rd_val = get_register(rd, instr->RnMode());
|
||||
result |= rd_val & ~mask;
|
||||
}
|
||||
if (bitwidth == 64) {
|
||||
set_register(instr, rd, result, instr->RdMode());
|
||||
} else {
|
||||
set_wregister(rd, result, instr->RdMode());
|
||||
}
|
||||
}
|
||||
|
||||
void Simulator::DecodeLogicalImm(Instr* instr) {
|
||||
const int op = instr->Bits(29, 2);
|
||||
const bool set_flags = op == 3;
|
||||
|
@ -1362,6 +1404,8 @@ void Simulator::DecodeDPImmediate(Instr* instr) {
|
|||
DecodeMoveWide(instr);
|
||||
} else if (instr->IsAddSubImmOp()) {
|
||||
DecodeAddSubImm(instr);
|
||||
} else if (instr->IsBitfieldOp()) {
|
||||
DecodeBitfield(instr);
|
||||
} else if (instr->IsLogicalImmOp()) {
|
||||
DecodeLogicalImm(instr);
|
||||
} else if (instr->IsPCRelOp()) {
|
||||
|
|
Loading…
Reference in a new issue