From: Tim Northover Date: Sat, 22 Sep 2012 11:18:12 +0000 (+0000) Subject: Fix the handling of edge cases in ARM shifted operands. X-Git-Tag: android-x86-6.0-r1~179^2~3042 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=93c7c449a1351542fa5a275587187154dbedb8e0;p=android-x86%2Fexternal-llvm.git 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164455 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 3e68a0b865a..bc711dc35f0 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -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 #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; } diff --git a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 57642e1924e..bf0dabb4a0f 100644 --- a/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -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))) diff --git a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp index 8b9109ec986..60f92f82d40 100644 --- a/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp +++ b/lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp @@ -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())); } //===--------------------------------------------------------------------===// diff --git a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp index dde72853540..d0e127a8f33 100644 --- a/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp +++ b/lib/Target/ARM/MCTargetDesc/ARMMCCodeEmitter.cpp @@ -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 diff --git a/test/MC/ARM/arm-shift-encoding.s b/test/MC/ARM/arm-shift-encoding.s new file mode 100644 index 00000000000..c849380ff2b --- /dev/null +++ b/test/MC/ARM/arm-shift-encoding.s @@ -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] diff --git a/test/MC/ARM/diagnostics.s b/test/MC/ARM/diagnostics.s index 499e0550135..ad4d9ab9b5e 100644 --- a/test/MC/ARM/diagnostics.s +++ b/test/MC/ARM/diagnostics.s @@ -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