Commit f4d0a7a5 by Karl Schimpf

Add LSL (register, immediate) to ARM integrated assembler.

Also does some clean up on emitType01 methods (making optional argument explicit, and moving rule checks to the lowest level). BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4334 R=jpp@chromium.org Review URL: https://codereview.chromium.org/1456783003 .
parent 3f6b47d5
...@@ -2596,7 +2596,8 @@ void Assembler::MoveRegister(Register rd, Register rm, Condition cond) { ...@@ -2596,7 +2596,8 @@ void Assembler::MoveRegister(Register rd, Register rm, Condition cond) {
} }
} }
#if 0
// Moved to ARM32::AssemblerARM32::lsl()
void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm, void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm,
Condition cond) { Condition cond) {
ASSERT(shift_imm.type() == 1); ASSERT(shift_imm.type() == 1);
...@@ -2604,10 +2605,11 @@ void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm, ...@@ -2604,10 +2605,11 @@ void Assembler::Lsl(Register rd, Register rm, const Operand& shift_imm,
mov(rd, Operand(rm, LSL, shift_imm.encoding()), cond); mov(rd, Operand(rm, LSL, shift_imm.encoding()), cond);
} }
// Moved to ARM32::AssemblerARM32::lsl()
void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) { void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
mov(rd, Operand(rm, LSL, rs), cond); mov(rd, Operand(rm, LSL, rs), cond);
} }
#endif
void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm, void Assembler::Lsr(Register rd, Register rm, const Operand& shift_imm,
......
...@@ -158,7 +158,7 @@ class Operand : public ValueObject { ...@@ -158,7 +158,7 @@ class Operand : public ValueObject {
encoding_ = static_cast<uint32_t>(rm); encoding_ = static_cast<uint32_t>(rm);
} }
// Moved to encodeShiftRotateImm5() // Moved to encodeShiftRotateImm5() in IceAssemblerARM32.cpp
// Data-processing operands - Logical shift/rotate by immediate. // Data-processing operands - Logical shift/rotate by immediate.
Operand(Register rm, Shift shift, uint32_t shift_imm) { Operand(Register rm, Shift shift, uint32_t shift_imm) {
ASSERT(shift_imm < (1 << kShiftImmBits)); ASSERT(shift_imm < (1 << kShiftImmBits));
...@@ -167,8 +167,8 @@ class Operand : public ValueObject { ...@@ -167,8 +167,8 @@ class Operand : public ValueObject {
static_cast<uint32_t>(shift) << kShiftShift | static_cast<uint32_t>(shift) << kShiftShift |
static_cast<uint32_t>(rm); static_cast<uint32_t>(rm);
} }
#endif
// Moved to encodeShiftRotateReg() in IceAssemblerARM32.cpp
// Data-processing operands - Logical shift/rotate by register. // Data-processing operands - Logical shift/rotate by register.
Operand(Register rm, Shift shift, Register rs) { Operand(Register rm, Shift shift, Register rs) {
type_ = 0; type_ = 0;
...@@ -177,7 +177,6 @@ class Operand : public ValueObject { ...@@ -177,7 +177,6 @@ class Operand : public ValueObject {
static_cast<uint32_t>(rm); static_cast<uint32_t>(rm);
} }
#if 0
// Already defined as ARM32::OperandARM32FlexImm::canHoldImm(). // Already defined as ARM32::OperandARM32FlexImm::canHoldImm().
static bool CanHold(uint32_t immediate, Operand* o) { static bool CanHold(uint32_t immediate, Operand* o) {
// Avoid the more expensive test for frequent small immediate values. // Avoid the more expensive test for frequent small immediate values.
...@@ -956,9 +955,13 @@ class Assembler : public ValueObject { ...@@ -956,9 +955,13 @@ class Assembler : public ValueObject {
// Convenience shift instructions. Use mov instruction with shifter operand // Convenience shift instructions. Use mov instruction with shifter operand
// for variants setting the status flags. // for variants setting the status flags.
#if 0
// Moved to ARM32::AssemblerARM32::lsl()
void Lsl(Register rd, Register rm, const Operand& shift_imm, void Lsl(Register rd, Register rm, const Operand& shift_imm,
Condition cond = AL); Condition cond = AL);
// Moved to ARM32::AssemblerARM32::lsl()
void Lsl(Register rd, Register rm, Register rs, Condition cond = AL); void Lsl(Register rd, Register rm, Register rs, Condition cond = AL);
#endif
void Lsr(Register rd, Register rm, const Operand& shift_imm, void Lsr(Register rd, Register rm, const Operand& shift_imm,
Condition cond = AL); Condition cond = AL);
void Lsr(Register rd, Register rm, Register rs, Condition cond = AL); void Lsr(Register rd, Register rm, Register rs, Condition cond = AL);
......
...@@ -100,6 +100,7 @@ static constexpr IValueT kDivRnShift = 0; ...@@ -100,6 +100,7 @@ static constexpr IValueT kDivRnShift = 0;
// Type of instruction encoding (bits 25-27). See ARM section A5.1 // Type of instruction encoding (bits 25-27). See ARM section A5.1
static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000 static constexpr IValueT kInstTypeDataRegister = 0; // i.e. 000
static constexpr IValueT kInstTypeDataRegShift = 0; // i.e. 000
static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001 static constexpr IValueT kInstTypeDataImmediate = 1; // i.e. 001
static constexpr IValueT kInstTypeMemImmediate = 2; // i.e. 010 static constexpr IValueT kInstTypeMemImmediate = 2; // i.e. 010
static constexpr IValueT kInstTypeRegisterShift = 3; // i.e. 011 static constexpr IValueT kInstTypeRegisterShift = 3; // i.e. 011
...@@ -195,6 +196,8 @@ enum DecodedResult { ...@@ -195,6 +196,8 @@ enum DecodedResult {
// kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if // kind, p=1 if pre-indexed addressing, u=1 if offset positive, and w=1 if
// writeback to Rn. // writeback to Rn.
DecodedAsShiftRotateImm5, DecodedAsShiftRotateImm5,
// i.e. 000000000000000000000iiiii0000000 iiii defines Imm5 value to shift.
DecodedAsShiftImm5,
// Value is 32bit integer constant. // Value is 32bit integer constant.
DecodedAsConstI32 DecodedAsConstI32
}; };
...@@ -215,13 +218,23 @@ IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift, ...@@ -215,13 +218,23 @@ IValueT encodeShiftRotateImm5(IValueT Rm, OperandARM32::ShiftKind Shift,
return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm; return (imm5 << kShiftImmShift) | (encodeShift(Shift) << kShiftShift) | Rm;
} }
// Encodes mmmmtt01ssss for data-processing (2nd) operands where mmmm=Rm,
// ssss=Rs, and tt=Shift.
IValueT encodeShiftRotateReg(IValueT Rm, OperandARM32::ShiftKind Shift,
IValueT Rs) {
return (Rs << kRsShift) | (encodeShift(Shift) << kShiftShift) | B4 |
(Rm << kRmShift);
}
DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) { DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) {
if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) { if (const auto *Var = llvm::dyn_cast<Variable>(Opnd)) {
if (Var->hasReg()) { if (Var->hasReg()) {
Value = Var->getRegNum(); Value = Var->getRegNum();
return DecodedAsRegister; return DecodedAsRegister;
} }
} else if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) { return CantDecode;
}
if (const auto *FlexImm = llvm::dyn_cast<OperandARM32FlexImm>(Opnd)) {
const IValueT Immed8 = FlexImm->getImm(); const IValueT Immed8 = FlexImm->getImm();
const IValueT Rotate = FlexImm->getRotateAmt(); const IValueT Rotate = FlexImm->getRotateAmt();
if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits)))) if (!((Rotate < (1 << kRotateBits)) && (Immed8 < (1 << kImmed8Bits))))
...@@ -233,6 +246,12 @@ DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) { ...@@ -233,6 +246,12 @@ DecodedResult decodeOperand(const Operand *Opnd, IValueT &Value) {
Value = Const->getValue(); Value = Const->getValue();
return DecodedAsConstI32; return DecodedAsConstI32;
} }
if (const auto *ShImm = llvm::dyn_cast<OperandARM32ShAmtImm>(Opnd)) {
const IValueT Immed5 = ShImm->getShAmtImm();
assert(Immed5 < (1 << kShiftImmBits));
Value = (Immed5 << kShiftImmShift);
return DecodedAsShiftImm5;
}
return CantDecode; return CantDecode;
} }
...@@ -423,22 +442,33 @@ void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) { ...@@ -423,22 +442,33 @@ void AssemblerARM32::emitTextInst(const std::string &Text, SizeT InstSize) {
} }
void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Type, void AssemblerARM32::emitType01(CondARM32::Cond Cond, IValueT Type,
IValueT Opcode, bool SetCc, IValueT Rn, IValueT Opcode, bool SetFlags, IValueT Rn,
IValueT Rd, IValueT Imm12) { IValueT Rd, IValueT Imm12,
EmitChecks RuleChecks) {
switch (RuleChecks) {
case NoChecks:
break;
case RdIsPcAndSetFlags:
if (((Rd == RegARM32::Encoded_Reg_pc) && SetFlags))
// Conditions of rule violated.
return setNeedsTextFixup();
break;
}
if (!isGPRRegisterDefined(Rd) || !isConditionDefined(Cond)) if (!isGPRRegisterDefined(Rd) || !isConditionDefined(Cond))
return setNeedsTextFixup(); return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) | const IValueT Encoding = (encodeCondition(Cond) << kConditionShift) |
(Type << kTypeShift) | (Opcode << kOpcodeShift) | (Type << kTypeShift) | (Opcode << kOpcodeShift) |
(encodeBool(SetCc) << kSShift) | (Rn << kRnShift) | (encodeBool(SetFlags) << kSShift) |
(Rd << kRdShift) | Imm12; (Rn << kRnShift) | (Rd << kRdShift) | Imm12;
emitInst(Encoding); emitInst(Encoding);
} }
void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd,
const Operand *OpRn, const Operand *OpSrc1, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond, bool SetFlags, CondARM32::Cond Cond,
Type01Checks RuleChecks) { EmitChecks RuleChecks) {
IValueT Rd; IValueT Rd;
if (decodeOperand(OpRd, Rd) != DecodedAsRegister) if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
return setNeedsTextFixup(); return setNeedsTextFixup();
...@@ -450,7 +480,7 @@ void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd, ...@@ -450,7 +480,7 @@ void AssemblerARM32::emitType01(IValueT Opcode, const Operand *OpRd,
void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
const Operand *OpSrc1, bool SetFlags, const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond, Type01Checks RuleChecks) { CondARM32::Cond Cond, EmitChecks RuleChecks) {
switch (RuleChecks) { switch (RuleChecks) {
case NoChecks: case NoChecks:
break; break;
...@@ -474,8 +504,8 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, ...@@ -474,8 +504,8 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
// mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags. // mmmm=Rm, iiiii=Shift, tt=ShiftKind, and s=SetFlags.
constexpr IValueT Imm5 = 0; constexpr IValueT Imm5 = 0;
Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5); Src1Value = encodeShiftRotateImm5(Src1Value, OperandARM32::kNoShift, Imm5);
emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, emitType01(Cond, kInstTypeDataRegister, Opcode, SetFlags, Rn, Rd, Src1Value,
Src1Value); RuleChecks);
return; return;
} }
case DecodedAsConstI32: { case DecodedAsConstI32: {
...@@ -494,7 +524,7 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn, ...@@ -494,7 +524,7 @@ void AssemblerARM32::emitType01(IValueT Opcode, IValueT Rd, IValueT Rn,
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd, emitType01(Cond, kInstTypeDataImmediate, Opcode, SetFlags, Rn, Rd,
Src1Value); Src1Value, RuleChecks);
return; return;
} }
} }
...@@ -577,14 +607,15 @@ void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, ...@@ -577,14 +607,15 @@ void AssemblerARM32::emitDivOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
} }
void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, void AssemblerARM32::emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd,
IValueT Rn, IValueT Rm, IValueT Rs, bool SetCc) { IValueT Rn, IValueT Rm, IValueT Rs,
bool SetFlags) {
if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) || if (!isGPRRegisterDefined(Rd) || !isGPRRegisterDefined(Rn) ||
!isGPRRegisterDefined(Rm) || !isGPRRegisterDefined(Rs) || !isGPRRegisterDefined(Rm) || !isGPRRegisterDefined(Rs) ||
!isConditionDefined(Cond)) !isConditionDefined(Cond))
return setNeedsTextFixup(); return setNeedsTextFixup();
AssemblerBuffer::EnsureCapacity ensured(&Buffer); AssemblerBuffer::EnsureCapacity ensured(&Buffer);
IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) | IValueT Encoding = Opcode | (encodeCondition(Cond) << kConditionShift) |
(encodeBool(SetCc) << kSShift) | (Rn << kRnShift) | (encodeBool(SetFlags) << kSShift) | (Rn << kRnShift) |
(Rd << kRdShift) | (Rs << kRsShift) | B7 | B4 | (Rd << kRdShift) | (Rs << kRsShift) | B7 | B4 |
(Rm << kRmShift); (Rm << kRmShift);
emitInst(Encoding); emitInst(Encoding);
...@@ -631,7 +662,7 @@ void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn, ...@@ -631,7 +662,7 @@ void AssemblerARM32::adc(const Operand *OpRd, const Operand *OpRn,
// cccc0010101snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010101snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Adc = B2 | B0; // 0101 constexpr IValueT Adc = B2 | B0; // 0101
emitType01(Adc, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Adc, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
...@@ -653,7 +684,7 @@ void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn, ...@@ -653,7 +684,7 @@ void AssemblerARM32::add(const Operand *OpRd, const Operand *OpRn,
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Add = B2; // 0100 constexpr IValueT Add = B2; // 0100
emitType01(Add, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Add, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn,
...@@ -671,7 +702,7 @@ void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn, ...@@ -671,7 +702,7 @@ void AssemblerARM32::and_(const Operand *OpRd, const Operand *OpRn,
// cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT And = 0; // 0000 constexpr IValueT And = 0; // 0000
emitType01(And, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(And, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::b(Label *L, CondARM32::Cond Cond) { void AssemblerARM32::b(Label *L, CondARM32::Cond Cond) {
...@@ -704,7 +735,7 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn, ...@@ -704,7 +735,7 @@ void AssemblerARM32::bic(const Operand *OpRd, const Operand *OpRn,
// cccc0011110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rn, nnnn=Rn, // cccc0011110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rn, nnnn=Rn,
// s=SetFlags, and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags, and iiiiiiiiiiii=Src1Value defining RotatedImm8.
IValueT Opcode = B3 | B2 | B1; // i.e. 1110 IValueT Opcode = B3 | B2 | B1; // i.e. 1110
emitType01(Opcode, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Opcode, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::bl(const ConstantRelocatable *Target) { void AssemblerARM32::bl(const ConstantRelocatable *Target) {
...@@ -785,7 +816,7 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn, ...@@ -785,7 +816,7 @@ void AssemblerARM32::eor(const Operand *OpRd, const Operand *OpRn,
// cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010001snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Eor = B0; // 0001 constexpr IValueT Eor = B0; // 0001
emitType01(Eor, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Eor, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
...@@ -868,6 +899,51 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress, ...@@ -868,6 +899,51 @@ void AssemblerARM32::ldr(const Operand *OpRt, const Operand *OpAddress,
} }
} }
void AssemblerARM32::lsl(const Operand *OpRd, const Operand *OpRm,
const Operand *OpSrc1, bool SetFlags,
CondARM32::Cond Cond) {
constexpr IValueT Lsl = B3 | B2 | B0; // 1101
constexpr IValueT Rn = 0; // Rn field is not used.
IValueT Rd;
if (decodeOperand(OpRd, Rd) != DecodedAsRegister)
return setNeedsTextFixup();
IValueT Rm;
if (decodeOperand(OpRm, Rm) != DecodedAsRegister)
return setNeedsTextFixup();
IValueT Value;
switch (decodeOperand(OpSrc1, Value)) {
default:
return setNeedsTextFixup();
case DecodedAsShiftImm5: {
// LSL (immediate) - ARM section A8.8.94, encoding A1:
// lsl{s}<c> <Rd>, <Rm>, #imm5
//
// cccc0001101s0000ddddiiiii000mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
// iiiii=imm5, and mmmm=Rm.
Value = Value | (Rm << kRmShift);
emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd, Value,
RdIsPcAndSetFlags);
return;
}
case DecodedAsRegister: {
// LSL (register) - ARM section A8.8.95, encoding A1:
// lsl{S}<c> <Rd>, <Rm>, <Rs>
//
// cccc0001101s0000ddddssss0001mmmm where cccc=Cond, s=SetFlags, dddd=Rd,
// mmmm=Rm, and ssss=Rs.
IValueT Rs;
if (decodeOperand(OpSrc1, Rs) != DecodedAsRegister)
return setNeedsTextFixup();
if ((Rd == RegARM32::Encoded_Reg_pc) || (Rm == RegARM32::Encoded_Reg_pc) ||
(Rs == RegARM32::Encoded_Reg_pc))
setNeedsTextFixup();
emitType01(Cond, kInstTypeDataRegShift, Lsl, SetFlags, Rn, Rd,
encodeShiftRotateReg(Rm, OperandARM32::kNoShift, Rs), NoChecks);
return;
}
}
}
void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
CondARM32::Cond Cond) { CondARM32::Cond Cond) {
// MOV (register) - ARM section A8.8.104, encoding A1: // MOV (register) - ARM section A8.8.104, encoding A1:
...@@ -888,7 +964,7 @@ void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc, ...@@ -888,7 +964,7 @@ void AssemblerARM32::mov(const Operand *OpRd, const Operand *OpSrc,
constexpr bool SetFlags = false; constexpr bool SetFlags = false;
constexpr IValueT Rn = 0; constexpr IValueT Rn = 0;
constexpr IValueT Mov = B3 | B2 | B0; // 1101. constexpr IValueT Mov = B3 | B2 | B0; // 1101.
emitType01(Mov, Rd, Rn, OpSrc, SetFlags, Cond); emitType01(Mov, Rd, Rn, OpSrc, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16, void AssemblerARM32::emitMovw(IValueT Opcode, IValueT Rd, IValueT Imm16,
...@@ -986,7 +1062,7 @@ void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn, ...@@ -986,7 +1062,7 @@ void AssemblerARM32::sbc(const Operand *OpRd, const Operand *OpRn,
// cccc0010110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010110snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Sbc = B2 | B1; // 0110 constexpr IValueT Sbc = B2 | B1; // 0110
emitType01(Sbc, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Sbc, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn, void AssemblerARM32::sdiv(const Operand *OpRd, const Operand *OpRn,
...@@ -1064,7 +1140,7 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn, ...@@ -1064,7 +1140,7 @@ void AssemblerARM32::orr(const Operand *OpRd, const Operand *OpRn,
// cccc0001100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0001100snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8. // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8.
constexpr IValueT Orr = B3 | B2; // i.e. 1100 constexpr IValueT Orr = B3 | B2; // i.e. 1100
emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Orr, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) { void AssemblerARM32::pop(const Operand *OpRt, CondARM32::Cond Cond) {
...@@ -1218,7 +1294,7 @@ void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn, ...@@ -1218,7 +1294,7 @@ void AssemblerARM32::sub(const Operand *OpRd, const Operand *OpRn,
// cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn, // cccc0010010snnnnddddiiiiiiiiiiii where cccc=Cond, dddd=Rd, nnnn=Rn,
// s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8 // s=SetFlags and iiiiiiiiiiii=Src1Value defining RotatedImm8
constexpr IValueT Sub = B1; // 0010 constexpr IValueT Sub = B1; // 0010
emitType01(Sub, OpRd, OpRn, OpSrc1, SetFlags, Cond); emitType01(Sub, OpRd, OpRn, OpSrc1, SetFlags, Cond, RdIsPcAndSetFlags);
} }
void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1, void AssemblerARM32::tst(const Operand *OpRn, const Operand *OpSrc1,
......
...@@ -223,6 +223,9 @@ public: ...@@ -223,6 +223,9 @@ public:
ldr(OpRt, OpAddress, Cond, TInfo); ldr(OpRt, OpAddress, Cond, TInfo);
} }
void lsl(const Operand *OpRd, const Operand *OpRn, const Operand *OpSrc1,
bool SetFlags, CondARM32::Cond Cond);
void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void mov(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond); void movw(const Operand *OpRd, const Operand *OpSrc, CondARM32::Cond Cond);
...@@ -312,28 +315,27 @@ private: ...@@ -312,28 +315,27 @@ private:
void emitInst(IValueT Value) { Buffer.emit<IValueT>(Value); } void emitInst(IValueT Value) { Buffer.emit<IValueT>(Value); }
// List of possible checks to apply when calling emitType01() (below).
enum EmitChecks { NoChecks, RdIsPcAndSetFlags };
// Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=Type, // Pattern cccctttoooosnnnnddddiiiiiiiiiiii where cccc=Cond, ttt=Type,
// oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM section A5.2.3). // s=SetFlags, oooo=Opcode, nnnn=Rn, dddd=Rd, iiiiiiiiiiii=imm12 (See ARM
// section A5.2.3).
void emitType01(CondARM32::Cond Cond, IValueT Type, IValueT Opcode, void emitType01(CondARM32::Cond Cond, IValueT Type, IValueT Opcode,
bool SetCc, IValueT Rn, IValueT Rd, IValueT imm12); bool SetFlags, IValueT Rn, IValueT Rd, IValueT imm12,
EmitChecks RuleChecks);
// List of possible checks to apply when calling emitType01() (below).
enum Type01Checks {
NoChecks,
RdIsPcAndSetFlags,
};
// Converts appropriate representation on a data operation, and then calls // Converts appropriate representation on a data operation, and then calls
// emitType01 above. // emitType01 above.
void emitType01(IValueT Opcode, const Operand *OpRd, const Operand *OpRn, void emitType01(IValueT Opcode, const Operand *OpRd, const Operand *OpRn,
const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond,
Type01Checks RuleChecks = RdIsPcAndSetFlags); EmitChecks RuleChecks);
// Same as above, but the value for Rd and Rn have already been converted // Same as above, but the value for Rd and Rn have already been converted
// into instruction values. // into instruction values.
void emitType01(IValueT Opcode, IValueT OpRd, IValueT OpRn, void emitType01(IValueT Opcode, IValueT OpRd, IValueT OpRn,
const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond, const Operand *OpSrc1, bool SetFlags, CondARM32::Cond Cond,
Type01Checks RuleChecks = RdIsPcAndSetFlags); EmitChecks RuleChecks);
void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link); void emitType05(CondARM32::Cond COnd, int32_t Offset, bool Link);
...@@ -356,9 +358,9 @@ private: ...@@ -356,9 +358,9 @@ private:
IValueT Rm); IValueT Rm);
// Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn, // Pattern ccccxxxxxxxfnnnnddddssss1001mmmm where cccc=Cond, dddd=Rd, nnnn=Rn,
// mmmm=Rm, ssss=Rs, f=SetCc, and xxxxxxx=Opcode. // mmmm=Rm, ssss=Rs, f=SetFlags and xxxxxxx=Opcode.
void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn, void emitMulOp(CondARM32::Cond Cond, IValueT Opcode, IValueT Rd, IValueT Rn,
IValueT Rm, IValueT Rs, bool SetCc); IValueT Rm, IValueT Rs, bool SetFlags);
// Implements various forms of Unsigned extend value, using pattern // Implements various forms of Unsigned extend value, using pattern
// ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode, // ccccxxxxxxxxnnnnddddrr000111mmmm where cccc=Cond, xxxxxxxx<<20=Opcode,
......
...@@ -485,6 +485,13 @@ template <> void InstARM32Eor::emitIAS(const Cfg *Func) const { ...@@ -485,6 +485,13 @@ template <> void InstARM32Eor::emitIAS(const Cfg *Func) const {
emitUsingTextFixup(Func); emitUsingTextFixup(Func);
} }
template <> void InstARM32Lsl::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->lsl(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
if (Asm->needsTextFixup())
emitUsingTextFixup(Func);
}
template <> void InstARM32Orr::emitIAS(const Cfg *Func) const { template <> void InstARM32Orr::emitIAS(const Cfg *Func) const {
auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>(); auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate()); Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
......
; Show that we know how to translate lsl.
; NOTE: We use -O2 to get rid of memory stores.
; REQUIRES: allow_dump
; Compile using standalone assembler.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=ASM
; Show bytes in assembled standalone code.
; RUN: %p2i --filetype=asm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
; Compile using integrated assembler.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --args -O2 \
; RUN: | FileCheck %s --check-prefix=IASM
; Show bytes in assembled integrated code.
; RUN: %p2i --filetype=iasm -i %s --target=arm32 --assemble --disassemble \
; RUN: --args -O2 | FileCheck %s --check-prefix=DIS
define internal i32 @_Z8testUdivhh(i32 %a, i32 %b) {
; ASM-LABEL:_Z8testUdivhh:
; DIS-LABEL:00000000 <_Z8testUdivhh>:
; IASM-LABEL:_Z8testUdivhh:
entry:
; ASM-NEXT:.L_Z8testUdivhh$entry:
; ASM-NEXT: push {lr}
; DIS-NEXT: 0: e52de004
; IASM-NEXT:.L_Z8testUdivhh$entry:
; IASM-NEXT: .byte 0x4
; IASM-NEXT: .byte 0xe0
; IASM-NEXT: .byte 0x2d
; IASM-NEXT: .byte 0xe5
%b.arg_trunc = trunc i32 %b to i8
%a.arg_trunc = trunc i32 %a to i8
%div3 = udiv i8 %a.arg_trunc, %b.arg_trunc
; ASM-NEXT: sub sp, sp, #12
; DIS-NEXT: 4: e24dd00c
; IASM-NEXT: .byte 0xc
; IASM-NEXT: .byte 0xd0
; IASM-NEXT: .byte 0x4d
; IASM-NEXT: .byte 0xe2
; ASM-NEXT: lsls r2, r1, #24
; DIS-NEXT: 8: e1b02c01
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0x2c
; IASM-NEXT: .byte 0xb0
; IASM-NEXT: .byte 0xe1
%div3.ret_ext = zext i8 %div3 to i32
ret i32 %div3.ret_ext
}
define internal i32 @_Z7testShljj(i32 %a, i32 %b) {
; ASM-LABEL:_Z7testShljj:
; DIS-LABEL:00000030 <_Z7testShljj>:
; IASM-LABEL:_Z7testShljj:
entry:
; ASM-NEXT:.L_Z7testShljj$entry:
; IASM-NEXT:.L_Z7testShljj$entry:
%shl = shl i32 %a, %b
; ASM-NEXT: lsl r0, r0, r1
; DIS-NEXT: 30: e1a00110
; IASM-NEXT: .byte 0x10
; IASM-NEXT: .byte 0x1
; IASM-NEXT: .byte 0xa0
; IASM-NEXT: .byte 0xe1
ret i32 %shl
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment