unsigned Opc = MI->getOpcode();
switch (Opc) {
default: break;
+ case ARM::LDMIA_RET: {
+ // LDMIA_RET is just a normal LDMIA_UPD instruction that targets PC and as
+ // such has additional code-gen properties and scheduling information.
+ // To emit it, we just construct as normal and set the opcode to LDMIA_UPD.
+ MCInst TmpInst;
+ LowerARMMachineInstrToMCInst(MI, TmpInst, *this);
+ TmpInst.setOpcode(ARM::LDMIA_UPD);
+ OutStreamer.EmitInstruction(TmpInst);
+ return;
+ }
case ARM::t2ADDrSPi:
case ARM::t2ADDrSPi12:
case ARM::t2SUBrSPi:
// FIXME: Should pc be an implicit operand like PICADD, etc?
let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1,
hasExtraDefRegAllocReq = 1, isCodeGenOnly = 1 in
-// FIXME: Should be a pseudo-instruction.
-def LDMIA_RET : AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p,
- reglist:$regs, variable_ops),
- IndexModeUpd, LdStMulFrm, IIC_iLoad_mBr,
- "ldmia${p}\t$Rn!, $regs",
- "$Rn = $wb", []> {
- let Inst{24-23} = 0b01; // Increment After
- let Inst{21} = 1; // Writeback
- let Inst{20} = 1; // Load
-}
+def LDMIA_RET : ARMPseudoInst<(outs GPR:$wb), (ins GPR:$Rn, pred:$p,
+ reglist:$regs, variable_ops),
+ Size4Bytes, IIC_iLoad_mBr, []>,
+ RegConstraint<"$Rn = $wb">;
//===----------------------------------------------------------------------===//
// Move Instructions.
entry:
%0 = tail call i32 @foo(i32 %a) nounwind ; <i32> [#uses=1]
%1 = add nsw i32 %0, 3 ; <i32> [#uses=1]
-; CHECK: ldmia sp!, {r11, pc}
+; CHECK: pop {r11, pc}
; V4: pop
; V4-NEXT: mov pc, lr
ret i32 %1
; was being treated as an instruction count.
; CHECK: push
-; CHECK: ldmia
-; CHECK: ldmia
-; CHECK: ldmia
+; CHECK: pop
+; CHECK: pop
+; CHECK: pop
define i32 @test(i32 %x) {
entry:
; ARM: bl _foo
; ARM: bl _foo
; ARM: bl _foo
-; ARM: ldmia sp!, {r7, pc}
+; ARM: pop {r7, pc}
; THUMB2: t:
; THUMB2: push
bb18: ; preds = %bb1
; CHECK-NOT: bx
-; CHECK: ldmia sp!
+; CHECK: pop
ret void
}
br i1 %4, label %bb1, label %bb3
; CHECK: LBB1_[[RET]]: @ %bb5
-; CHECK: ldmia sp!
+; CHECK: pop
bb5: ; preds = %bb3, %entry
%sum.1.lcssa = phi i32 [ 0, %entry ], [ %sum.0.lcssa, %bb3 ] ; <i32> [#uses=1]
ret i32 %sum.1.lcssa
; CHECK: t:
; CHECK: vpop {d8}
; CHECK-NOT: vpopne
-; CHECK: ldmia sp!, {r7, pc}
+; CHECK: pop {r7, pc}
; CHECK: vpop {d8}
-; CHECK: ldmia sp!, {r7, pc}
+; CHECK: pop {r7, pc}
br i1 undef, label %if.else, label %if.then
if.then: ; preds = %entry
define i32 @t1(i32 %a, i32 %b) {
; CHECK: t1:
-; CHECK: ldmialt sp!, {r7, pc}
+; CHECK: poplt {r7, pc}
entry:
%tmp1 = icmp sgt i32 %a, 10 ; <i1> [#uses=1]
br i1 %tmp1, label %cond_true, label %UnifiedReturnBlock
define void @foo(i32 %X, i32 %Y) {
entry:
; CHECK: cmpne
-; CHECK: ldmiahi sp!
+; CHECK: pophi
%tmp1 = icmp ult i32 %X, 4 ; <i1> [#uses=1]
%tmp4 = icmp eq i32 %Y, 0 ; <i1> [#uses=1]
%tmp7 = or i1 %tmp4, %tmp1 ; <i1> [#uses=1]
define fastcc i32 @CountTree(%struct.quad_struct* %tree) {
; CHECK: cmpeq
; CHECK: moveq
-; CHECK: ldmiaeq sp!
+; CHECK: popeq
entry:
br label %tailrecurse
declare void @abort()
define fastcc void @t(%struct.SString* %word, i8 signext %c) {
-; CHECK: ldmiane sp!
+; CHECK: popne
entry:
%tmp1 = icmp eq %struct.SString* %word, null ; <i1> [#uses=1]
br i1 %tmp1, label %cond_true, label %cond_false
define i32 @t1() {
; CHECK: t1:
-; CHECK: ldmia
+; CHECK: pop
; V4T: t1:
-; V4T: ldmia
+; V4T: pop
%tmp = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 0) ; <i32> [#uses=1]
%tmp3 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 1) ; <i32> [#uses=1]
%tmp4 = tail call i32 @f1( i32 %tmp, i32 %tmp3 ) ; <i32> [#uses=1]
define i32 @t2() {
; CHECK: t2:
-; CHECK: ldmia
+; CHECK: pop
; V4T: t2:
-; V4T: ldmia
+; V4T: pop
%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]
%tmp5 = load i32* getelementptr ([0 x i32]* @X, i32 0, i32 4) ; <i32> [#uses=1]
define i32 @t3() {
; CHECK: t3:
; CHECK: ldmib
-; CHECK: ldmia sp!
+; CHECK: pop
; V4T: t3:
; V4T: ldmib
; V4T: pop