mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
Fix the handling of edge cases in ARM shifted operands.
This patch fixes load/store instructions to handle less common cases like "asr #32", "rrx" properly throughout the MC layer. Patch by Chris Lidbury. llvm-svn: 164455
This commit is contained in:
parent
3d9c40c0c8
commit
1c60305666
@ -4444,6 +4444,12 @@ bool ARMAsmParser::parseMemRegOffsetShift(ARM_AM::ShiftOpc &St,
|
||||
((St == ARM_AM::lsl || St == ARM_AM::ror) && Imm > 31) ||
|
||||
((St == ARM_AM::lsr || St == ARM_AM::asr) && Imm > 32))
|
||||
return Error(Loc, "immediate shift value out of range");
|
||||
// If <ShiftTy> #0, turn it into a no_shift.
|
||||
if (Imm == 0)
|
||||
St = ARM_AM::lsl;
|
||||
// For consistency, treat lsr #32 and asr #32 as having immediate value 0.
|
||||
if (Imm == 32)
|
||||
Imm = 0;
|
||||
Amount = Imm;
|
||||
}
|
||||
|
||||
|
@ -1523,6 +1523,8 @@ DecodeAddrMode2IdxInstruction(MCInst &Inst, unsigned Insn,
|
||||
return MCDisassembler::Fail;
|
||||
}
|
||||
unsigned amt = fieldFromInstruction(Insn, 7, 5);
|
||||
if (Opc == ARM_AM::ror && amt == 0)
|
||||
Opc = ARM_AM::rrx;
|
||||
unsigned imm = ARM_AM::getAM2Opc(Op, amt, Opc, idx_mode);
|
||||
|
||||
Inst.addOperand(MCOperand::CreateImm(imm));
|
||||
@ -1564,6 +1566,9 @@ static DecodeStatus DecodeSORegMemOperand(MCInst &Inst, unsigned Val,
|
||||
break;
|
||||
}
|
||||
|
||||
if (ShOp == ARM_AM::ror && imm == 0)
|
||||
ShOp = ARM_AM::rrx;
|
||||
|
||||
if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder)))
|
||||
return MCDisassembler::Fail;
|
||||
if (!Check(S, DecodeGPRRegisterClass(Inst, Rm, Address, Decoder)))
|
||||
|
@ -29,11 +29,27 @@ using namespace llvm;
|
||||
///
|
||||
/// getSORegOffset returns an integer from 0-31, representing '32' as 0.
|
||||
static unsigned translateShiftImm(unsigned imm) {
|
||||
// lsr #32 and asr #32 exist, but should be encoded as a 0.
|
||||
assert((imm & ~0x1f) == 0 && "Invalid shift encoding");
|
||||
|
||||
if (imm == 0)
|
||||
return 32;
|
||||
return imm;
|
||||
}
|
||||
|
||||
/// Prints the shift value with an immediate value.
|
||||
static void printRegImmShift(raw_ostream &O, ARM_AM::ShiftOpc ShOpc,
|
||||
unsigned ShImm) {
|
||||
if (ShOpc == ARM_AM::no_shift || (ShOpc == ARM_AM::lsl && !ShImm))
|
||||
return;
|
||||
O << ", ";
|
||||
|
||||
assert (!(ShOpc == ARM_AM::ror && !ShImm) && "Cannot have ror #0");
|
||||
O << getShiftOpcStr(ShOpc);
|
||||
|
||||
if (ShOpc != ARM_AM::rrx)
|
||||
O << " #" << translateShiftImm(ShImm);
|
||||
}
|
||||
|
||||
ARMInstPrinter::ARMInstPrinter(const MCAsmInfo &MAI,
|
||||
const MCInstrInfo &MII,
|
||||
@ -319,10 +335,8 @@ void ARMInstPrinter::printAM2PreOrOffsetIndexOp(const MCInst *MI, unsigned Op,
|
||||
<< ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO3.getImm()))
|
||||
<< getRegisterName(MO2.getReg());
|
||||
|
||||
if (unsigned ShImm = ARM_AM::getAM2Offset(MO3.getImm()))
|
||||
O << ", "
|
||||
<< ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO3.getImm()))
|
||||
<< " #" << ShImm;
|
||||
printRegImmShift(O, ARM_AM::getAM2ShiftOpc(MO3.getImm()),
|
||||
ARM_AM::getAM2Offset(MO3.getImm()));
|
||||
O << "]";
|
||||
}
|
||||
|
||||
@ -403,10 +417,8 @@ void ARMInstPrinter::printAddrMode2OffsetOperand(const MCInst *MI,
|
||||
O << ARM_AM::getAddrOpcStr(ARM_AM::getAM2Op(MO2.getImm()))
|
||||
<< getRegisterName(MO1.getReg());
|
||||
|
||||
if (unsigned ShImm = ARM_AM::getAM2Offset(MO2.getImm()))
|
||||
O << ", "
|
||||
<< ARM_AM::getShiftOpcStr(ARM_AM::getAM2ShiftOpc(MO2.getImm()))
|
||||
<< " #" << ShImm;
|
||||
printRegImmShift(O, ARM_AM::getAM2ShiftOpc(MO2.getImm()),
|
||||
ARM_AM::getAM2Offset(MO2.getImm()));
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -934,6 +934,10 @@ getLdStSORegOpValue(const MCInst &MI, unsigned OpIdx,
|
||||
ARM_AM::ShiftOpc ShOp = ARM_AM::getAM2ShiftOpc(MO2.getImm());
|
||||
unsigned SBits = getShiftOp(ShOp);
|
||||
|
||||
// While "lsr #32" and "asr #32" exist, they are encoded with a 0 in the shift
|
||||
// amount. However, it would be an easy mistake to make so check here.
|
||||
assert((ShImm & ~0x1f) == 0 && "Out of range shift amount");
|
||||
|
||||
// {16-13} = Rn
|
||||
// {12} = isAdd
|
||||
// {11-0} = shifter
|
||||
|
76
test/MC/ARM/arm-shift-encoding.s
Normal file
76
test/MC/ARM/arm-shift-encoding.s
Normal file
@ -0,0 +1,76 @@
|
||||
@ RUN: llvm-mc -mcpu=cortex-a8 -triple armv7 -show-encoding < %s | FileCheck %s
|
||||
|
||||
ldr r0, [r0, r0]
|
||||
ldr r0, [r0, r0, lsr #32]
|
||||
ldr r0, [r0, r0, lsr #16]
|
||||
ldr r0, [r0, r0, lsl #0]
|
||||
ldr r0, [r0, r0, lsl #16]
|
||||
ldr r0, [r0, r0, asr #32]
|
||||
ldr r0, [r0, r0, asr #16]
|
||||
ldr r0, [r0, r0, rrx]
|
||||
ldr r0, [r0, r0, ror #16]
|
||||
|
||||
@ CHECK: ldr r0, [r0, r0] @ encoding: [0x00,0x00,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, lsr #32] @ encoding: [0x20,0x00,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, lsr #16] @ encoding: [0x20,0x08,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0] @ encoding: [0x00,0x00,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, lsl #16] @ encoding: [0x00,0x08,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, asr #32] @ encoding: [0x40,0x00,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, asr #16] @ encoding: [0x40,0x08,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, rrx] @ encoding: [0x60,0x00,0x90,0xe7]
|
||||
@ CHECK: ldr r0, [r0, r0, ror #16] @ encoding: [0x60,0x08,0x90,0xe7]
|
||||
|
||||
pld [r0, r0]
|
||||
pld [r0, r0, lsr #32]
|
||||
pld [r0, r0, lsr #16]
|
||||
pld [r0, r0, lsl #0]
|
||||
pld [r0, r0, lsl #16]
|
||||
pld [r0, r0, asr #32]
|
||||
pld [r0, r0, asr #16]
|
||||
pld [r0, r0, rrx]
|
||||
pld [r0, r0, ror #16]
|
||||
|
||||
@ CHECK: [r0, r0] @ encoding: [0x00,0xf0,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, lsr #32] @ encoding: [0x20,0xf0,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, lsr #16] @ encoding: [0x20,0xf8,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0] @ encoding: [0x00,0xf0,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, lsl #16] @ encoding: [0x00,0xf8,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, asr #32] @ encoding: [0x40,0xf0,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, asr #16] @ encoding: [0x40,0xf8,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, rrx] @ encoding: [0x60,0xf0,0xd0,0xf7]
|
||||
@ CHECK: [r0, r0, ror #16] @ encoding: [0x60,0xf8,0xd0,0xf7]
|
||||
|
||||
str r0, [r0, r0]
|
||||
str r0, [r0, r0, lsr #32]
|
||||
str r0, [r0, r0, lsr #16]
|
||||
str r0, [r0, r0, lsl #0]
|
||||
str r0, [r0, r0, lsl #16]
|
||||
str r0, [r0, r0, asr #32]
|
||||
str r0, [r0, r0, asr #16]
|
||||
str r0, [r0, r0, rrx]
|
||||
str r0, [r0, r0, ror #16]
|
||||
|
||||
@ CHECK: str r0, [r0, r0] @ encoding: [0x00,0x00,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, lsr #32] @ encoding: [0x20,0x00,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, lsr #16] @ encoding: [0x20,0x08,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0] @ encoding: [0x00,0x00,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, lsl #16] @ encoding: [0x00,0x08,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, asr #32] @ encoding: [0x40,0x00,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, asr #16] @ encoding: [0x40,0x08,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, rrx] @ encoding: [0x60,0x00,0x80,0xe7]
|
||||
@ CHECK: str r0, [r0, r0, ror #16] @ encoding: [0x60,0x08,0x80,0xe7]
|
||||
|
||||
@ Uses printAddrMode2OffsetOperand(), used by LDRBT_POST_IMM LDRBT_POST_REG
|
||||
@ LDRB_POST_IMM LDRB_POST_REG LDRT_POST_IMM LDRT_POST_REG LDR_POST_IMM
|
||||
@ LDR_POST_REG STRBT_POST_IMM STRBT_POST_REG STRB_POST_IMM STRB_POST_REG
|
||||
@ STRT_POST_IMM STRT_POST_REG STR_POST_IMM STR_POST_REG
|
||||
|
||||
ldr r0, [r1], r2, rrx
|
||||
ldr r3, [r4], r5, ror #0
|
||||
str r6, [r7], r8, lsl #0
|
||||
str r9, [r10], r11
|
||||
|
||||
@ CHECK: ldr r0, [r1], r2, rrx @ encoding: [0x62,0x00,0x91,0xe6]
|
||||
@ CHECK: ldr r3, [r4], r5 @ encoding: [0x05,0x30,0x94,0xe6]
|
||||
@ CHECK: str r6, [r7], r8 @ encoding: [0x08,0x60,0x87,0xe6]
|
||||
@ CHECK: str r9, [r10], r11 @ encoding: [0x0b,0x90,0x8a,0xe6]
|
@ -47,7 +47,47 @@
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: adc r4, r5, r6, ror #32
|
||||
|
||||
@ Out of range shift immediate values for load/store.
|
||||
str r1, [r2, r3, lsl #invalid]
|
||||
ldr r4, [r5], r6, lsl #-1
|
||||
pld r4, [r5, r6, lsl #32]
|
||||
str r4, [r5], r6, lsr #-1
|
||||
ldr r4, [r5, r6, lsr #33]
|
||||
pld r4, [r5, r6, asr #-1]
|
||||
str r4, [r5, r6, asr #33]
|
||||
ldr r4, [r5, r6, ror #-1]
|
||||
pld r4, [r5, r6, ror #32]
|
||||
pld r4, [r5, r6, rrx #0]
|
||||
|
||||
@ CHECK-ERRORS: error: shift amount must be an immediate
|
||||
@ CHECK-ERRORS: str r1, [r2, r3, lsl #invalid]
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: ldr r4, [r5], r6, lsl #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: pld r4, [r5, r6, lsl #32]
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: str r4, [r5], r6, lsr #-1
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: ldr r4, [r5, r6, lsr #33]
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: pld r4, [r5, r6, asr #-1]
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: str r4, [r5, r6, asr #33]
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: ldr r4, [r5, r6, ror #-1]
|
||||
@ CHECK-ERRORS: ^
|
||||
@ CHECK-ERRORS: error: immediate shift value out of range
|
||||
@ CHECK-ERRORS: pld r4, [r5, r6, ror #32]
|
||||
@ CHECK-ERRORS: error: ']' expected
|
||||
@ CHECK-ERRORS: pld r4, [r5, r6, rrx #0]
|
||||
|
||||
@ Out of range 16-bit immediate on BKPT
|
||||
bkpt #65536
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user