ARM stm/ldm instructions require more than one register in the register list.
authorJim Grosbach <grosbach@apple.com>
Thu, 9 Dec 2010 18:31:13 +0000 (18:31 +0000)
committerJim Grosbach <grosbach@apple.com>
Thu, 9 Dec 2010 18:31:13 +0000 (18:31 +0000)
Otherwise, a plain str/ldr should be used instead. Make sure we account for
that in prologue/epilogue code generation.
rdar://8745460

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@121391 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMFrameInfo.cpp
lib/Target/ARM/ARMFrameInfo.h
test/CodeGen/ARM/str_pre-2.ll
test/CodeGen/Thumb2/2010-06-21-TailMergeBug.ll

index e8d8498af7ec909de36137a66001963a5ea3f061..71b60794f32fc5f5a291eddd500eb300af177335 100644 (file)
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ARMFrameInfo.h"
+#include "ARMAddressingModes.h"
 #include "ARMBaseInstrInfo.h"
 #include "ARMMachineFunctionInfo.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
@@ -501,7 +502,7 @@ int ARMFrameInfo::getFrameIndexOffset(const MachineFunction &MF, int FI) const {
 void ARMFrameInfo::emitPushInst(MachineBasicBlock &MBB,
                                 MachineBasicBlock::iterator MI,
                                 const std::vector<CalleeSavedInfo> &CSI,
-                                unsigned Opc, bool NoGap,
+                                unsigned StmOpc, unsigned StrOpc, bool NoGap,
                                 bool(*Func)(unsigned, bool)) const {
   MachineFunction &MF = *MBB.getParent();
   const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
@@ -540,21 +541,37 @@ void ARMFrameInfo::emitPushInst(MachineBasicBlock &MBB,
       Regs.push_back(std::make_pair(Reg, isKill));
     }
 
-    if (!Regs.empty()) {
+    if (Regs.empty())
+      continue;
+    if (Regs.size() > 1 || StrOpc== 0) {
       MachineInstrBuilder MIB =
-        AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(Opc), ARM::SP)
+        AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(StmOpc), ARM::SP)
                        .addReg(ARM::SP));
       for (unsigned i = 0, e = Regs.size(); i < e; ++i)
         MIB.addReg(Regs[i].first, getKillRegState(Regs[i].second));
-      Regs.clear();
+    } else if (Regs.size() == 1) {
+      MachineInstrBuilder MIB = BuildMI(MBB, MI, DL, TII.get(StrOpc),
+                                        ARM::SP)
+        .addReg(Regs[0].first, getKillRegState(Regs[0].second))
+        .addReg(ARM::SP);
+      // ARM mode needs an extra reg0 here due to addrmode2. Will go away once
+      // that refactoring is complete (eventually).
+      if (StrOpc == ARM::STR_PRE) {
+        MIB.addReg(0);
+        MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::sub, 4, ARM_AM::no_shift));
+      } else
+        MIB.addImm(-4);
+      AddDefaultPred(MIB);
     }
+    Regs.clear();
   }
 }
 
 void ARMFrameInfo::emitPopInst(MachineBasicBlock &MBB,
                                MachineBasicBlock::iterator MI,
                                const std::vector<CalleeSavedInfo> &CSI,
-                               unsigned Opc, bool isVarArg, bool NoGap,
+                               unsigned LdmOpc, unsigned LdrOpc,
+                               bool isVarArg, bool NoGap,
                                bool(*Func)(unsigned, bool)) const {
   MachineFunction &MF = *MBB.getParent();
   const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
@@ -572,7 +589,7 @@ void ARMFrameInfo::emitPopInst(MachineBasicBlock &MBB,
 
       if (Reg == ARM::LR && !isVarArg) {
         Reg = ARM::PC;
-        Opc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;
+        LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET;
         // Fold the return instruction into the LDM.
         DeleteRet = true;
       }
@@ -587,17 +604,36 @@ void ARMFrameInfo::emitPopInst(MachineBasicBlock &MBB,
       Regs.push_back(Reg);
     }
 
-    if (!Regs.empty()) {
+    if (Regs.empty())
+      continue;
+    if (Regs.size() > 1 || LdrOpc == 0) {
       MachineInstrBuilder MIB =
-        AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(Opc), ARM::SP)
+        AddDefaultPred(BuildMI(MBB, MI, DL, TII.get(LdmOpc), ARM::SP)
                        .addReg(ARM::SP));
       for (unsigned i = 0, e = Regs.size(); i < e; ++i)
         MIB.addReg(Regs[i], getDefRegState(true));
       if (DeleteRet)
         MI->eraseFromParent();
       MI = MIB;
-      Regs.clear();
+    } else if (Regs.size() == 1) {
+      // If we adjusted the reg to PC from LR above, switch it back here. We
+      // only do that for LDM.
+      if (Regs[0] == ARM::PC)
+        Regs[0] = ARM::LR;
+      MachineInstrBuilder MIB =
+        BuildMI(MBB, MI, DL, TII.get(LdrOpc), Regs[0])
+          .addReg(ARM::SP, RegState::Define)
+          .addReg(ARM::SP);
+      // ARM mode needs an extra reg0 here due to addrmode2. Will go away once
+      // that refactoring is complete (eventually).
+      if (LdrOpc == ARM::LDR_POST) {
+        MIB.addReg(0);
+        MIB.addImm(ARM_AM::getAM2Opc(ARM_AM::add, 4, ARM_AM::no_shift));
+      } else
+        MIB.addImm(4);
+      AddDefaultPred(MIB);
     }
+    Regs.clear();
   }
 }
 
@@ -613,10 +649,11 @@ bool ARMFrameInfo::spillCalleeSavedRegisters(MachineBasicBlock &MBB,
   DebugLoc DL = MI->getDebugLoc();
 
   unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD;
+  unsigned PushOneOpc = AFI->isThumbFunction() ? ARM::t2STR_PRE : ARM::STR_PRE;
   unsigned FltOpc = ARM::VSTMDDB_UPD;
-  emitPushInst(MBB, MI, CSI, PushOpc, false, &isARMArea1Register);
-  emitPushInst(MBB, MI, CSI, PushOpc, false, &isARMArea2Register);
-  emitPushInst(MBB, MI, CSI, FltOpc,  true,  &isARMArea3Register);
+  emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea1Register);
+  emitPushInst(MBB, MI, CSI, PushOpc, PushOneOpc, false, &isARMArea2Register);
+  emitPushInst(MBB, MI, CSI, FltOpc,  0, true,  &isARMArea3Register);
 
   return true;
 }
@@ -634,10 +671,13 @@ bool ARMFrameInfo::restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
   DebugLoc DL = MI->getDebugLoc();
 
   unsigned PopOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_UPD : ARM::LDMIA_UPD;
+  unsigned LdrOpc = AFI->isThumbFunction() ? ARM::t2LDR_POST : ARM::LDR_POST;
   unsigned FltOpc = ARM::VLDMDIA_UPD;
-  emitPopInst(MBB, MI, CSI, FltOpc, isVarArg, true,  &isARMArea3Register);
-  emitPopInst(MBB, MI, CSI, PopOpc, isVarArg, false, &isARMArea2Register);
-  emitPopInst(MBB, MI, CSI, PopOpc, isVarArg, false, &isARMArea1Register);
+  emitPopInst(MBB, MI, CSI, FltOpc, 0, isVarArg, true,  &isARMArea3Register);
+  emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
+              &isARMArea2Register);
+  emitPopInst(MBB, MI, CSI, PopOpc, LdrOpc, isVarArg, false,
+              &isARMArea1Register);
 
   return true;
 }
index 2ff77b4b49f9b1f0f8222707eafa7cd20f83201a..260e5835cbb653668fe6ba5431854d84f72a1d13 100644 (file)
@@ -59,11 +59,12 @@ public:
 
  private:
   void emitPushInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
-                    const std::vector<CalleeSavedInfo> &CSI, unsigned Opc,
-                    bool NoGap, bool(*Func)(unsigned, bool)) const;
+                    const std::vector<CalleeSavedInfo> &CSI, unsigned StmOpc,
+                    unsigned StrOpc, bool NoGap,
+                    bool(*Func)(unsigned, bool)) const;
   void emitPopInst(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
-                   const std::vector<CalleeSavedInfo> &CSI, unsigned Opc,
-                   bool isVarArg, bool NoGap,
+                   const std::vector<CalleeSavedInfo> &CSI, unsigned LdmOpc,
+                   unsigned LdrOpc, bool isVarArg, bool NoGap,
                    bool(*Func)(unsigned, bool)) const;
 };
 
index a79cf9bf7f8605ab7de0f67130c020499f376b70..4f9ba4db4c2b6efc6e3c0cda8c1c81f813a39f3a 100644 (file)
@@ -4,8 +4,8 @@
 
 define i64 @t(i64 %a) nounwind readonly {
 entry:
-; CHECK: push    {lr}
-; CHECK: ldmia   sp!, {pc}
+; CHECK: str lr, [sp, #-4]!
+; CHECK: ldr lr, [sp], #4
        %0 = load i64** @b, align 4
        %1 = load i64* %0, align 4
        %2 = mul i64 %1, %a
index 12b4975d69abf354f0bc4a667a95c168e4ec589b..f91e1c9febe2f4697b65f803af2ece747fa4b538 100644 (file)
@@ -39,7 +39,7 @@ entry:
 ; CHECK: ittt eq
 ; CHECK: moveq r0
 ; CHECK-NOT: LBB0_
-; CHECK: popeq
+; CHECK: ldreq
 ; CHECK: popeq
   switch i32 undef, label %bb7 [
     i32 37, label %bb43