mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-11-02 07:17:36 +00:00
Thumb assembly parsing and encoding for LDM instruction.
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
This commit is contained in:
@@ -683,8 +683,8 @@ multiclass thumb_ldst_mult<string asm, InstrItinClass itin,
|
|||||||
InstrItinClass itin_upd, bits<6> T1Enc,
|
InstrItinClass itin_upd, bits<6> T1Enc,
|
||||||
bit L_bit, string baseOpc> {
|
bit L_bit, string baseOpc> {
|
||||||
def IA :
|
def IA :
|
||||||
T1I<(outs), (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops),
|
T1I<(outs), (ins tGPR:$Rn, pred:$p, reglist:$regs, variable_ops),
|
||||||
itin, !strconcat(asm, "ia${p}\t$Rn, $regs"), []>,
|
itin, !strconcat(asm, "${p}\t$Rn, $regs"), []>,
|
||||||
T1Encoding<T1Enc> {
|
T1Encoding<T1Enc> {
|
||||||
bits<3> Rn;
|
bits<3> Rn;
|
||||||
bits<8> regs;
|
bits<8> regs;
|
||||||
@@ -696,7 +696,7 @@ multiclass thumb_ldst_mult<string asm, InstrItinClass itin,
|
|||||||
InstTemplate<AddrModeNone, 0, IndexModeNone, Pseudo, GenericDomain,
|
InstTemplate<AddrModeNone, 0, IndexModeNone, Pseudo, GenericDomain,
|
||||||
"$Rn = $wb", itin_upd>,
|
"$Rn = $wb", itin_upd>,
|
||||||
PseudoInstExpansion<(!cast<Instruction>(!strconcat(baseOpc, "IA"))
|
PseudoInstExpansion<(!cast<Instruction>(!strconcat(baseOpc, "IA"))
|
||||||
GPR:$Rn, pred:$p, reglist:$regs)> {
|
tGPR:$Rn, pred:$p, reglist:$regs)> {
|
||||||
let Size = 2;
|
let Size = 2;
|
||||||
let OutOperandList = (outs GPR:$wb);
|
let OutOperandList = (outs GPR:$wb);
|
||||||
let InOperandList = (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops);
|
let InOperandList = (ins GPR:$Rn, pred:$p, reglist:$regs, variable_ops);
|
||||||
@@ -720,6 +720,11 @@ defm tSTM : thumb_ldst_mult<"stm", IIC_iStore_m, IIC_iStore_mu,
|
|||||||
|
|
||||||
} // neverHasSideEffects
|
} // 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
|
let mayLoad = 1, Uses = [SP], Defs = [SP], hasExtraDefRegAllocReq = 1 in
|
||||||
def tPOP : T1I<(outs), (ins pred:$p, reglist:$regs, variable_ops),
|
def tPOP : T1I<(outs), (ins pred:$p, reglist:$regs, variable_ops),
|
||||||
IIC_iPop,
|
IIC_iPop,
|
||||||
|
|||||||
@@ -2988,6 +2988,29 @@ validateInstruction(MCInst &Inst,
|
|||||||
"bitfield width must be in range [1,32-lsb]");
|
"bitfield width must be in range [1,32-lsb]");
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
|||||||
@@ -155,9 +155,9 @@ void ARMInstPrinter::printInst(const MCInst *MI, raw_ostream &O) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Opcode == ARM::tLDMIA)
|
if (Opcode == ARM::tLDMIA)
|
||||||
O << "\tldmia";
|
O << "\tldm";
|
||||||
else if (Opcode == ARM::tSTMIA)
|
else if (Opcode == ARM::tSTMIA)
|
||||||
O << "\tstmia";
|
O << "\tstm";
|
||||||
else
|
else
|
||||||
llvm_unreachable("Unknown opcode!");
|
llvm_unreachable("Unknown opcode!");
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ define i32 @t1() {
|
|||||||
define i32 @t2() {
|
define i32 @t2() {
|
||||||
; CHECK: t2:
|
; CHECK: t2:
|
||||||
; CHECK: push {r7, lr}
|
; CHECK: push {r7, lr}
|
||||||
; CHECK: ldmia
|
; CHECK: ldm
|
||||||
; CHECK: pop {r7, pc}
|
; CHECK: pop {r7, pc}
|
||||||
%tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 2) ; <i32> [#uses=1]
|
%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]
|
%tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 3) ; <i32> [#uses=1]
|
||||||
|
|||||||
@@ -162,3 +162,15 @@ _func:
|
|||||||
eors r4, r5
|
eors r4, r5
|
||||||
|
|
||||||
@ CHECK: eors r4, r5 @ encoding: [0x6c,0x40]
|
@ 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]
|
||||||
|
|||||||
@@ -39,3 +39,13 @@ error: invalid operand for instruction
|
|||||||
error: invalid operand for instruction
|
error: invalid operand for instruction
|
||||||
bkpt #-1
|
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: ^
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
# CHECK: cmn.w r0, #31
|
# CHECK: cmn.w r0, #31
|
||||||
0x10 0xf1 0x1f 0x0f
|
0x10 0xf1 0x1f 0x0f
|
||||||
|
|
||||||
# CHECK: ldmia r0!, {r1}
|
# CHECK: ldm r0!, {r1}
|
||||||
0x02 0xc8
|
0x02 0xc8
|
||||||
|
|
||||||
# CHECK: ldr r5, #432
|
# CHECK: ldr r5, #432
|
||||||
@@ -112,7 +112,7 @@
|
|||||||
# CHECK: lsleq r1, r0, #28
|
# CHECK: lsleq r1, r0, #28
|
||||||
0x01 0x07
|
0x01 0x07
|
||||||
|
|
||||||
# CHECK: stmiane r0!, {r1, r2, r3}
|
# CHECK: stmne r0!, {r1, r2, r3}
|
||||||
0x0e 0xc0
|
0x0e 0xc0
|
||||||
|
|
||||||
# IT block end
|
# IT block end
|
||||||
@@ -146,13 +146,13 @@
|
|||||||
# CHECK: stmdb.w sp, {r0, r2, r3, r8, r11, lr}
|
# CHECK: stmdb.w sp, {r0, r2, r3, r8, r11, lr}
|
||||||
0x0d 0xe9 0x0d 0x49
|
0x0d 0xe9 0x0d 0x49
|
||||||
|
|
||||||
# CHECK: stmia r5!, {r0, r1, r2, r3, r4}
|
# CHECK: stm r5!, {r0, r1, r2, r3, r4}
|
||||||
0x1f 0xc5
|
0x1f 0xc5
|
||||||
|
|
||||||
# CHECK: ldmia r5, {r0, r1, r2, r3, r4, r5}
|
# CHECK: ldm r5, {r0, r1, r2, r3, r4, r5}
|
||||||
0x3f 0xcd
|
0x3f 0xcd
|
||||||
|
|
||||||
# CHECK: ldmia r5!, {r0, r1, r2, r3, r4}
|
# CHECK: ldm r5!, {r0, r1, r2, r3, r4}
|
||||||
0x1f 0xcd
|
0x1f 0xcd
|
||||||
|
|
||||||
# CHECK: addw r0, pc, #1050
|
# CHECK: addw r0, pc, #1050
|
||||||
|
|||||||
Reference in New Issue
Block a user