Skip to content

Commit

Permalink
Thumb assembly parsing and encoding for LDM instruction.
Browse files Browse the repository at this point in the history
Fix base register type and canonicallize to the "ldm" spelling rather than
"ldmia." Add diagnostics for incorrect writeback token and out-of-range
registers.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137986 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Jim Grosbach committed Aug 18, 2011
1 parent b48ef3a commit 93b3eff
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 11 deletions.
11 changes: 8 additions & 3 deletions lib/Target/ARM/ARMInstrThumb.td
Expand Up @@ -683,8 +683,8 @@ multiclass thumb_ldst_mult<string asm, InstrItinClass itin,
InstrItinClass itin_upd, bits<6> T1Enc,
bit L_bit, string baseOpc> {
def IA :
T1I<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops),
itin, !strconcat(asm, "ia${p}\t$Rn, $regs"), []>,
T1I<(outs), (ins tGPR:$Rn, pred:$p, reglist:$regs, variable_ops),
itin, !strconcat(asm, "${p}\t$Rn, $regs"), []>,
T1Encoding<T1Enc> {
bits<3> Rn;
bits<8> regs;
Expand All @@ -696,7 +696,7 @@ multiclass thumb_ldst_mult<string asm, InstrItinClass itin,
InstTemplate<AddrModeNone, 0, IndexModeNone, Pseudo, GenericDomain,
"$Rn = $wb", itin_upd>,
PseudoInstExpansion<(!cast<Instruction>(!strconcat(baseOpc, "IA"))
GPR:$Rn, pred:$p, reglist:$regs)> {
tGPR:$Rn, pred:$p, reglist:$regs)> {
let Size = 2;
let OutOperandList = (outs GPR:$wb);
let InOperandList = (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops);
Expand All @@ -720,6 +720,11 @@ defm tSTM : thumb_ldst_mult<"stm", IIC_iStore_m, IIC_iStore_mu,

} // neverHasSideEffects

def : InstAlias<"ldm${p} $Rn!, $regs",
(tLDMIA tGPR:$Rn, pred:$p, reglist:$regs)>,
Requires<[IsThumb, IsThumb1Only]>;


let mayLoad = 1, Uses = [SP], Defs = [SP], hasExtraDefRegAllocReq = 1 in
def tPOP : T1I<(outs), (ins pred:$p, reglist:$regs, variable_ops),
IIC_iPop,
Expand Down
23 changes: 23 additions & 0 deletions lib/Target/ARM/AsmParser/ARMAsmParser.cpp
Expand Up @@ -2988,6 +2988,29 @@ validateInstruction(MCInst &Inst,
"bitfield width must be in range [1,32-lsb]");
return false;
}
case ARM::tLDMIA: {
// Thumb LDM instructions are writeback iff the base register is not
// in the register list.
unsigned Rn = Inst.getOperand(0).getReg();
bool doesWriteback = true;
for (unsigned i = 3; i < Inst.getNumOperands(); ++i) {
unsigned Reg = Inst.getOperand(i).getReg();
if (Reg == Rn)
doesWriteback = false;
// Anything other than a low register isn't legal here.
if (getARMRegisterNumbering(Reg) > 7)
return Error(Operands[4]->getStartLoc(),
"registers must be in range r0-r7");
}
// If we should have writeback, then there should be a '!' token.
if (doesWriteback &&
(!static_cast<ARMOperand*>(Operands[3])->isToken() ||
static_cast<ARMOperand*>(Operands[3])->getToken() != "!"))
return Error(Operands[2]->getStartLoc(),
"writeback operator '!' expected");

break;
}
}

return false;
Expand Down
4 changes: 2 additions & 2 deletions lib/Target/ARM/InstPrinter/ARMInstPrinter.cpp
Expand Up @@ -155,9 +155,9 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O) {
}

if (Opcode == ARM::tLDMIA)
O << "\tldmia";
O << "\tldm";
else if (Opcode == ARM::tSTMIA)
O << "\tstmia";
O << "\tstm";
else
llvm_unreachable("Unknown opcode!");

Expand Down
2 changes: 1 addition & 1 deletion test/CodeGen/Thumb2/thumb2-ldm.ll
Expand Up @@ -15,7 +15,7 @@ define i32 @t1() {
define i32 @t2() {
; CHECK: t2:
; CHECK: push {r7, lr}
; CHECK: ldmia
; CHECK: ldm
; CHECK: pop {r7, pc}
%tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2) ; <i32> [#uses=1]
%tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3) ; <i32> [#uses=1]
Expand Down
12 changes: 12 additions & 0 deletions test/MC/ARM/basic-thumb-instructions.s
Expand Up @@ -162,3 +162,15 @@ _func:
eors r4, r5

@ CHECK: eors r4, r5 @ encoding: [0x6c,0x40]


@------------------------------------------------------------------------------
@ LDM
@------------------------------------------------------------------------------
ldm r3, {r0, r1, r2, r3, r4, r5, r6, r7}
ldm r2!, {r1, r3, r4, r5, r7}
ldm r1, {r1}

@ CHECK: ldm r3, {r0, r1, r2, r3, r4, r5, r6, r7} @ encoding: [0xff,0xcb]
@ CHECK: ldm r2!, {r1, r3, r4, r5, r7} @ encoding: [0xba,0xca]
@ CHECK: ldm r1, {r1} @ encoding: [0x02,0xc9]
10 changes: 10 additions & 0 deletions test/MC/ARM/thumb-diagnostics.s
Expand Up @@ -39,3 +39,13 @@ error: invalid operand for instruction
error: invalid operand for instruction
bkpt #-1
^

@ Invalid writeback and register lists for LDM
ldm r2!, {r5, r8}
ldm r2, {r5, r7}
@ CHECK-ERRORS: error: registers must be in range r0-r7
@ CHECK-ERRORS: ldm r2!, {r5, r8}
@ CHECK-ERRORS: ^
@ CHECK-ERRORS: error: writeback operator '!' expected
@ CHECK-ERRORS: ldm r2, {r5, r7}
@ CHECK-ERRORS: ^
10 changes: 5 additions & 5 deletions test/MC/Disassembler/ARM/thumb-tests.txt
Expand Up @@ -27,7 +27,7 @@
# CHECK: cmn.w r0, #31
0x10 0xf1 0x1f 0x0f

# CHECK: ldmia r0!, {r1}
# CHECK: ldm r0!, {r1}
0x02 0xc8

# CHECK: ldr r5, #432
Expand Down Expand Up @@ -112,7 +112,7 @@
# CHECK: lsleq r1, r0, #28
0x01 0x07

# CHECK: stmiane r0!, {r1, r2, r3}
# CHECK: stmne r0!, {r1, r2, r3}
0x0e 0xc0

# IT block end
Expand Down Expand Up @@ -146,13 +146,13 @@
# CHECK: stmdb.w sp, {r0, r2, r3, r8, r11, lr}
0x0d 0xe9 0x0d 0x49

# CHECK: stmia r5!, {r0, r1, r2, r3, r4}
# CHECK: stm r5!, {r0, r1, r2, r3, r4}
0x1f 0xc5

# CHECK: ldmia r5, {r0, r1, r2, r3, r4, r5}
# CHECK: ldm r5, {r0, r1, r2, r3, r4, r5}
0x3f 0xcd

# CHECK: ldmia r5!, {r0, r1, r2, r3, r4}
# CHECK: ldm r5!, {r0, r1, r2, r3, r4}
0x1f 0xcd

# CHECK: addw r0, pc, #1050
Expand Down

0 comments on commit 93b3eff

Please sign in to comment.