It turns out most of the thumb2 instructions are not allowed to touch SP. The semantics of such instructions are unpredictable. We have just been lucky that tests have been passing.

This patch takes pain to ensure all the PEI lowering code does the right thing when lowering frame indices, insert code to manipulate stack pointers, etc. It's also custom lowering dynamic stack alloc into pseudo instructions so we can insert the right instructions at scheduling time.

This fixes PR4659 and PR4682.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78361 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/ARM/Thumb2InstrInfo.cpp b/lib/Target/ARM/Thumb2InstrInfo.cpp
index cf2d099..2b329e0 100644
--- a/lib/Target/ARM/Thumb2InstrInfo.cpp
+++ b/lib/Target/ARM/Thumb2InstrInfo.cpp
@@ -65,11 +65,15 @@
 
   if (DestRC == ARM::GPRRegisterClass &&
       SrcRC == ARM::GPRRegisterClass) {
-    AddDefaultCC(AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::t2MOVr),
-                                        DestReg).addReg(SrcReg)));
+    // FIXME: Just use tMOVgpr2gpr since it's shorter?
+    if (SrcReg == ARM::SP || DestReg == ARM::SP)
+      BuildMI(MBB, I, DL, get(ARM::tMOVgpr2gpr), DestReg).addReg(SrcReg);
+    else
+      AddDefaultCC(AddDefaultPred(BuildMI(MBB, I, DL, get(ARM::t2MOVr),
+                                          DestReg).addReg(SrcReg)));
     return true;
   } else if (DestRC == ARM::GPRRegisterClass &&
-      SrcRC == ARM::tGPRRegisterClass) {
+             SrcRC == ARM::tGPRRegisterClass) {
     BuildMI(MBB, I, DL, get(ARM::tMOVtgpr2gpr), DestReg).addReg(SrcReg);
     return true;
   } else if (DestRC == ARM::tGPRRegisterClass &&
@@ -162,26 +166,62 @@
   }
 
   while (NumBytes) {
-    unsigned Opc = isSub ? ARM::t2SUBri : ARM::t2ADDri;
     unsigned ThisVal = NumBytes;
-    if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
-      NumBytes = 0;
-    } else if (ThisVal < 4096) {
-      Opc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
-      NumBytes = 0;
+    unsigned Opc = 0;
+    if (DestReg == ARM::SP && BaseReg != ARM::SP) {
+      // mov sp, rn. Note t2MOVr cannot be used.
+      BuildMI(MBB, MBBI, dl, TII.get(ARM::tMOVgpr2gpr),DestReg).addReg(BaseReg);
+      BaseReg = ARM::SP;
+      continue;
+    }
+
+    if (BaseReg == ARM::SP) {
+      // sub sp, sp, #imm7
+      if (DestReg == ARM::SP && (ThisVal < ((1 << 7)-1) * 4)) {
+        assert((ThisVal & 3) == 0 && "Stack update is not multiple of 4?");
+        Opc = isSub ? ARM::tSUBspi : ARM::tADDspi;
+        // FIXME: Fix Thumb1 immediate encoding.
+        BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
+          .addReg(BaseReg).addImm(ThisVal/4);
+        NumBytes = 0;
+        continue;
+      }
+
+      // sub rd, sp, so_imm
+      Opc = isSub ? ARM::t2SUBrSPi : ARM::t2ADDrSPi;
+      if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
+        NumBytes = 0;
+      } else {
+        // FIXME: Move this to ARMAddressingModes.h?
+        unsigned RotAmt = CountLeadingZeros_32(ThisVal);
+        ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
+        NumBytes &= ~ThisVal;
+        assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
+               "Bit extraction didn't work?");
+      }
     } else {
-      // FIXME: Move this to ARMAddressingModes.h?
-      unsigned RotAmt = CountLeadingZeros_32(ThisVal);
-      ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
-      NumBytes &= ~ThisVal;
-      assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
-             "Bit extraction didn't work?");
+      assert(DestReg != ARM::SP && BaseReg != ARM::SP);
+      Opc = isSub ? ARM::t2SUBri : ARM::t2ADDri;
+      if (ARM_AM::getT2SOImmVal(NumBytes) != -1) {
+        NumBytes = 0;
+      } else if (ThisVal < 4096) {
+        Opc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
+        NumBytes = 0;
+      } else {
+        // FIXME: Move this to ARMAddressingModes.h?
+        unsigned RotAmt = CountLeadingZeros_32(ThisVal);
+        ThisVal = ThisVal & ARM_AM::rotr32(0xff000000U, RotAmt);
+        NumBytes &= ~ThisVal;
+        assert(ARM_AM::getT2SOImmVal(ThisVal) != -1 &&
+               "Bit extraction didn't work?");
+      }
     }
 
     // Build the new ADD / SUB.
-    BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
-      .addReg(BaseReg, RegState::Kill).addImm(ThisVal)
-      .addImm((unsigned)Pred).addReg(PredReg).addReg(0);
+    AddDefaultCC(AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(Opc), DestReg)
+                                .addReg(BaseReg, RegState::Kill)
+                                .addImm(ThisVal)));
+
     BaseReg = DestReg;
   }
 }
@@ -288,7 +328,6 @@
                               unsigned FrameReg, int Offset,
                               const ARMBaseInstrInfo &TII) {
   unsigned Opcode = MI.getOpcode();
-  unsigned NewOpc = Opcode;
   const TargetInstrDesc &Desc = MI.getDesc();
   unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask);
   bool isSub = false;
@@ -299,9 +338,12 @@
   
   if (Opcode == ARM::t2ADDri || Opcode == ARM::t2ADDri12) {
     Offset += MI.getOperand(FrameRegIdx+1).getImm();
+
+    bool isSP = FrameReg == ARM::SP;
     if (Offset == 0) {
       // Turn it into a move.
-      MI.setDesc(TII.get(ARM::t2MOVr));
+      unsigned NewOpc = isSP ? ARM::tMOVgpr2gpr : ARM::t2MOVr;
+      MI.setDesc(TII.get(NewOpc));
       MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
       MI.RemoveOperand(FrameRegIdx+1);
       return 0;
@@ -310,23 +352,23 @@
     if (Offset < 0) {
       Offset = -Offset;
       isSub = true;
-      MI.setDesc(TII.get(ARM::t2SUBri));
+      MI.setDesc(TII.get(isSP ? ARM::t2SUBrSPi : ARM::t2SUBri));
+    } else {
+      MI.setDesc(TII.get(isSP ? ARM::t2ADDrSPi : ARM::t2ADDri));
     }
 
     // Common case: small offset, fits into instruction.
     if (ARM_AM::getT2SOImmVal(Offset) != -1) {
-      NewOpc = isSub ? ARM::t2SUBri : ARM::t2ADDri;
-      if (NewOpc != Opcode)
-        MI.setDesc(TII.get(NewOpc));
       MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
       MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
       return 0;
     }
     // Another common case: imm12.
     if (Offset < 4096) {
-      NewOpc = isSub ? ARM::t2SUBri12 : ARM::t2ADDri12;
-      if (NewOpc != Opcode)
-        MI.setDesc(TII.get(NewOpc));
+      unsigned NewOpc = isSP
+        ? (isSub ? ARM::t2SUBrSPi12 : ARM::t2ADDrSPi12)
+        : (isSub ? ARM::t2SUBri12   : ARM::t2ADDri12);
+      MI.setDesc(TII.get(NewOpc));
       MI.getOperand(FrameRegIdx).ChangeToRegister(FrameReg, false);
       MI.getOperand(FrameRegIdx+1).ChangeToImmediate(Offset);
       return 0;
@@ -346,7 +388,7 @@
   } else {
     // AddrModeT2_so cannot handle any offset. If there is no offset
     // register then we change to an immediate version.
-    NewOpc = Opcode;
+    unsigned NewOpc = Opcode;
     if (AddrMode == ARMII::AddrModeT2_so) {
       unsigned OffsetReg = MI.getOperand(FrameRegIdx+1).getReg();
       if (OffsetReg != 0) {