Generate the DWARF stack frame decode operations in the function prologue for ARM...
authorArtyom Skrobov <Artyom.Skrobov@arm.com>
Fri, 14 Feb 2014 17:19:07 +0000 (17:19 +0000)
committerArtyom Skrobov <Artyom.Skrobov@arm.com>
Fri, 14 Feb 2014 17:19:07 +0000 (17:19 +0000)
Patch by Keith Walker!

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

13 files changed:
lib/CodeGen/AsmPrinter/ARMException.cpp
lib/CodeGen/AsmPrinter/AsmPrinter.cpp
lib/CodeGen/AsmPrinter/DwarfException.h
lib/Target/ARM/ARMFrameLowering.cpp
lib/Target/ARM/Thumb1FrameLowering.cpp
test/CodeGen/ARM/debug-frame-large-stack.ll [new file with mode: 0644]
test/CodeGen/ARM/debug-frame-no-debug.ll [new file with mode: 0644]
test/CodeGen/ARM/debug-frame-vararg.ll [new file with mode: 0644]
test/CodeGen/ARM/debug-frame.ll [new file with mode: 0644]
test/CodeGen/ARM/debug-info-sreg2.ll
test/CodeGen/ARM/indirectbr-2.ll
test/CodeGen/ARM/indirectbr.ll
test/CodeGen/ARM/interrupt-attr.ll

index 6e79bef..403feb4 100644 (file)
@@ -37,7 +37,8 @@
 using namespace llvm;
 
 ARMException::ARMException(AsmPrinter *A)
-  : DwarfException(A) {}
+  : DwarfException(A),
+    shouldEmitCFI(false) {}
 
 ARMException::~ARMException() {}
 
@@ -46,7 +47,11 @@ ARMTargetStreamer &ARMException::getTargetStreamer() {
   return static_cast<ARMTargetStreamer &>(TS);
 }
 
+/// endModule - Emit all exception information that should come after the
+/// content.
 void ARMException::endModule() {
+  if (shouldEmitCFI)
+    Asm->OutStreamer.EmitCFISections(false, true);
 }
 
 /// beginFunction - Gather pre-function exception information. Assumes it's
@@ -56,11 +61,22 @@ void ARMException::beginFunction(const MachineFunction *MF) {
   if (Asm->MF->getFunction()->needsUnwindTableEntry())
     Asm->OutStreamer.EmitLabel(Asm->GetTempSymbol("eh_func_begin",
                                                   Asm->getFunctionNumber()));
+  // See if we need call frame info.
+  AsmPrinter::CFIMoveType MoveType = Asm->needsCFIMoves();
+  assert(MoveType != AsmPrinter::CFI_M_EH &&
+         "non-EH CFI not yet supported in prologue with EHABI lowering");
+  if (MoveType == AsmPrinter::CFI_M_Debug) {
+    shouldEmitCFI = true;
+    Asm->OutStreamer.EmitCFIStartProc(false);
+  }
 }
 
 /// endFunction - Gather and emit post-function exception information.
 ///
 void ARMException::endFunction(const MachineFunction *) {
+  if (shouldEmitCFI)
+    Asm->OutStreamer.EmitCFIEndProc();
+
   ARMTargetStreamer &ATS = getTargetStreamer();
   if (!Asm->MF->getFunction()->needsUnwindTableEntry())
     ATS.emitCantUnwind();
index 2f15c97..63b4bb4 100644 (file)
@@ -697,7 +697,10 @@ bool AsmPrinter::needsSEHMoves() {
 void AsmPrinter::emitPrologLabel(const MachineInstr &MI) {
   const MCSymbol *Label = MI.getOperand(0).getMCSymbol();
 
-  if (MAI->getExceptionHandlingType() != ExceptionHandling::DwarfCFI)
+  ExceptionHandling::ExceptionsType ExceptionHandlingType =
+      MAI->getExceptionHandlingType();
+  if (ExceptionHandlingType != ExceptionHandling::DwarfCFI &&
+      ExceptionHandlingType != ExceptionHandling::ARM)
     return;
 
   if (needsCFIMoves() == CFI_M_None)
index 5a2ee9e..a28eaf0 100644 (file)
@@ -186,6 +186,10 @@ class ARMException : public DwarfException {
   void EmitTypeInfos(unsigned TTypeEncoding);
   ARMTargetStreamer &getTargetStreamer();
 
+  /// shouldEmitCFI - Per-function flag to indicate if frame CFI info
+  /// should be emitted.
+  bool shouldEmitCFI;
+
 public:
   //===--------------------------------------------------------------------===//
   // Main entry points.
index 63f1577..9164178 100644 (file)
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/RegisterScavenging.h"
 #include "llvm/IR/CallingConv.h"
 #include "llvm/IR/Function.h"
+#include "llvm/MC/MCContext.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Target/TargetOptions.h"
 
@@ -129,11 +131,24 @@ static void emitSPUpdate(bool isARM, MachineBasicBlock &MBB,
                        MIFlags, Pred, PredReg);
 }
 
+static int sizeOfSPAdjustment(const MachineInstr *MI) {
+  assert(MI->getOpcode() == ARM::VSTMDDB_UPD);
+  int count = 0;
+  // ARM and Thumb2 push/pop insts have explicit "sp, sp" operands (+
+  // pred) so the list starts at 4.
+  for (int i = MI->getNumOperands() - 1; i >= 4; --i)
+    count += 8;
+  return count;
+}
+
 void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
   MachineBasicBlock &MBB = MF.front();
   MachineBasicBlock::iterator MBBI = MBB.begin();
   MachineFrameInfo  *MFI = MF.getFrameInfo();
   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+  MachineModuleInfo &MMI = MF.getMMI();
+  MCContext &Context = MMI.getContext();
+  const MCRegisterInfo *MRI = Context.getRegisterInfo();
   const ARMBaseRegisterInfo *RegInfo =
     static_cast<const ARMBaseRegisterInfo*>(MF.getTarget().getRegisterInfo());
   const ARMBaseInstrInfo &TII =
@@ -147,6 +162,7 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
   const std::vector<CalleeSavedInfo> &CSI = MFI->getCalleeSavedInfo();
   DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
   unsigned FramePtr = RegInfo->getFrameRegister(MF);
+  int CFAOffset = 0;
 
   // Determine the sizes of each callee-save spill areas and record which frame
   // belongs to which callee-save spill areas.
@@ -160,21 +176,46 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
     return;
 
   // Allocate the vararg register save area. This is not counted in NumBytes.
-  if (ArgRegsSaveSize)
+  if (ArgRegsSaveSize) {
     emitSPUpdate(isARM, MBB, MBBI, dl, TII, -ArgRegsSaveSize,
                  MachineInstr::FrameSetup);
+    MCSymbol *SPLabel = Context.CreateTempSymbol();
+    BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+        .addSym(SPLabel);
+    CFAOffset -= ArgRegsSaveSize;
+    MMI.addFrameInst(
+        MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+  }
 
   if (!AFI->hasStackFrame()) {
-    if (NumBytes != 0)
+    if (NumBytes != 0) {
       emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes,
                    MachineInstr::FrameSetup);
+      MCSymbol *SPLabel = Context.CreateTempSymbol();
+      BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+          .addSym(SPLabel);
+      CFAOffset -= NumBytes;
+      MMI.addFrameInst(MCCFIInstruction::createDefCfaOffset(SPLabel,
+                                                            CFAOffset));
+    }
     return;
   }
 
+  // Determine spill area sizes.
   for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
     unsigned Reg = CSI[i].getReg();
     int FI = CSI[i].getFrameIdx();
     switch (Reg) {
+    case ARM::R8:
+    case ARM::R9:
+    case ARM::R10:
+    case ARM::R11:
+    case ARM::R12:
+      if (STI.isTargetMachO()) {
+        GPRCS2Size += 4;
+        break;
+      }
+      // fallthrough
     case ARM::R0:
     case ARM::R1:
     case ARM::R2:
@@ -188,18 +229,6 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
         FramePtrSpillFI = FI;
       GPRCS1Size += 4;
       break;
-    case ARM::R8:
-    case ARM::R9:
-    case ARM::R10:
-    case ARM::R11:
-    case ARM::R12:
-      if (Reg == FramePtr)
-        FramePtrSpillFI = FI;
-      if (STI.isTargetMachO())
-        GPRCS2Size += 4;
-      else
-        GPRCS1Size += 4;
-      break;
     default:
       // This is a DPR. Exclude the aligned DPRCS2 spills.
       if (Reg == ARM::D8)
@@ -210,9 +239,10 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
   }
 
   // Move past area 1.
-  MachineBasicBlock::iterator LastPush = MBB.end(), FramePtrPush;
+  MachineBasicBlock::iterator LastPush = MBB.end(), GPRCS1Push, GPRCS2Push,
+      DPRCSPush;
   if (GPRCS1Size > 0)
-    FramePtrPush = LastPush = MBBI++;
+    GPRCS1Push = LastPush = MBBI++;
 
   // Determine starting offsets of spill areas.
   bool HasFP = hasFP(MF);
@@ -230,13 +260,12 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
   AFI->setDPRCalleeSavedAreaOffset(DPRCSOffset);
 
   // Move past area 2.
-  if (GPRCS2Size > 0) {
-    LastPush = MBBI++;
-  }
+  if (GPRCS2Size > 0)
+    GPRCS2Push = LastPush = MBBI++;
 
   // Move past area 3.
   if (DPRCSSize > 0) {
-    LastPush = MBBI++;
+    DPRCSPush = MBBI;
     // Since vpush register list cannot have gaps, there may be multiple vpush
     // instructions in the prologue.
     while (MBBI->getOpcode() == ARM::VSTMDDB_UPD)
@@ -254,11 +283,15 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
   } else
     NumBytes = DPRCSOffset;
 
+  unsigned adjustedGPRCS1Size = GPRCS1Size;
   if (NumBytes) {
     // Adjust SP after all the callee-save spills.
     if (tryFoldSPUpdateIntoPushPop(STI, MF, LastPush, NumBytes)) {
-      if (LastPush == FramePtrPush)
+      if (LastPush == GPRCS1Push) {
         FramePtrOffsetInPush += NumBytes;
+        adjustedGPRCS1Size += NumBytes;
+        NumBytes = 0;
+      }
     } else
       emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes,
                    MachineInstr::FrameSetup);
@@ -275,17 +308,142 @@ void ARMFrameLowering::emitPrologue(MachineFunction &MF) const {
       AFI->setShouldRestoreSPFromFP(true);
   }
 
+  if (adjustedGPRCS1Size > 0) {
+    MCSymbol *SPLabel = Context.CreateTempSymbol();
+    BuildMI(MBB, ++GPRCS1Push, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+        .addSym(SPLabel);
+    CFAOffset -= adjustedGPRCS1Size;
+    MMI.addFrameInst(
+        MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+    for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(),
+           E = CSI.end(); I != E; ++I) {
+      unsigned Reg = I->getReg();
+      int FI = I->getFrameIdx();
+      switch (Reg) {
+      case ARM::R8:
+      case ARM::R9:
+      case ARM::R10:
+      case ARM::R11:
+      case ARM::R12:
+        if (STI.isTargetMachO())
+          break;
+        // fallthrough
+      case ARM::R0:
+      case ARM::R1:
+      case ARM::R2:
+      case ARM::R3:
+      case ARM::R4:
+      case ARM::R5:
+      case ARM::R6:
+      case ARM::R7:
+      case ARM::LR:
+        MMI.addFrameInst(MCCFIInstruction::createOffset(SPLabel,
+           MRI->getDwarfRegNum(Reg, true),
+           MFI->getObjectOffset(FI) - ArgRegsSaveSize));
+        break;
+      }
+    }
+  }
+
   // Set FP to point to the stack slot that contains the previous FP.
   // For iOS, FP is R7, which has now been stored in spill area 1.
   // Otherwise, if this is not iOS, all the callee-saved registers go
   // into spill area 1, including the FP in R11.  In either case, it
   // is in area one and the adjustment needs to take place just after
   // that push.
-  if (HasFP)
-    emitRegPlusImmediate(!AFI->isThumbFunction(), MBB, ++FramePtrPush, dl, TII,
+  if (HasFP) {
+    emitRegPlusImmediate(!AFI->isThumbFunction(), MBB, GPRCS1Push, dl, TII,
                          FramePtr, ARM::SP, FramePtrOffsetInPush,
                          MachineInstr::FrameSetup);
+    MCSymbol *SPLabel = Context.CreateTempSymbol();
+    BuildMI(MBB, GPRCS1Push, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+        .addSym(SPLabel);
+    if (FramePtrOffsetInPush) {
+      CFAOffset += FramePtrOffsetInPush;
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfa(SPLabel,
+              MRI->getDwarfRegNum(FramePtr, true), CFAOffset));
+    } else
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfaRegister(SPLabel,
+              MRI->getDwarfRegNum(FramePtr, true)));
+  }
 
+  if (GPRCS2Size > 0) {
+    MCSymbol *SPLabel = Context.CreateTempSymbol();
+    BuildMI(MBB, ++GPRCS2Push, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+        .addSym(SPLabel);
+    if (!HasFP) {
+      CFAOffset -= GPRCS2Size;
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+    }
+    for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(),
+           E = CSI.end(); I != E; ++I) {
+      unsigned Reg = I->getReg();
+      int FI = I->getFrameIdx();
+      switch (Reg) {
+      case ARM::R8:
+      case ARM::R9:
+      case ARM::R10:
+      case ARM::R11:
+      case ARM::R12:
+        if (STI.isTargetMachO()) {
+          unsigned DwarfReg =  MRI->getDwarfRegNum(Reg, true);
+          unsigned Offset = MFI->getObjectOffset(FI) - ArgRegsSaveSize;
+          MMI.addFrameInst(
+              MCCFIInstruction::createOffset(SPLabel, DwarfReg, Offset));
+        }
+        break;
+      }
+    }
+  }
+
+  if (DPRCSSize > 0) {
+    // Since vpush register list cannot have gaps, there may be multiple vpush
+    // instructions in the prologue.
+    MCSymbol *SPLabel = NULL;
+    do {
+      MachineBasicBlock::iterator Push = DPRCSPush++;
+      if (!HasFP) {
+        SPLabel = Context.CreateTempSymbol();
+        BuildMI(MBB, DPRCSPush, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+            .addSym(SPLabel);
+        CFAOffset -= sizeOfSPAdjustment(Push);;
+        MMI.addFrameInst(
+            MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+      }
+    } while (DPRCSPush->getOpcode() == ARM::VSTMDDB_UPD);
+
+    if (!SPLabel) {
+      SPLabel = Context.CreateTempSymbol();
+      BuildMI(MBB, DPRCSPush, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+          .addSym(SPLabel);
+    }
+    for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(),
+           E = CSI.end(); I != E; ++I) {
+      unsigned Reg = I->getReg();
+      int FI = I->getFrameIdx();
+      if ((Reg >= ARM::D0 && Reg <= ARM::D31) &&
+          (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs())) {
+        unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
+        unsigned Offset = MFI->getObjectOffset(FI);
+        MMI.addFrameInst(MCCFIInstruction::createOffset(SPLabel, DwarfReg,
+                                                        Offset));
+      }
+    }
+  }
+
+  if (NumBytes) {
+    if (!HasFP) {
+      MCSymbol *SPLabel = Context.CreateTempSymbol();
+      BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+          .addSym(SPLabel);
+      CFAOffset -= NumBytes;
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+    }
+  }
 
   if (STI.isTargetELF() && hasFP(MF))
     MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() -
index 2a587dd..c2da0b6 100644 (file)
@@ -16,6 +16,7 @@
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 
 using namespace llvm;
@@ -83,6 +84,8 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
   MachineBasicBlock::iterator MBBI = MBB.begin();
   MachineFrameInfo  *MFI = MF.getFrameInfo();
   ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
+  MachineModuleInfo &MMI = MF.getMMI();
+  const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
   const Thumb1RegisterInfo *RegInfo =
     static_cast<const Thumb1RegisterInfo*>(MF.getTarget().getRegisterInfo());
   const Thumb1InstrInfo &TII =
@@ -95,6 +98,7 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
   DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
   unsigned FramePtr = RegInfo->getFrameRegister(MF);
   unsigned BasePtr = RegInfo->getBaseRegister();
+  int CFAOffset = 0;
 
   // Thumb add/sub sp, imm8 instructions implicitly multiply the offset by 4.
   NumBytes = (NumBytes + 3) & ~3;
@@ -105,14 +109,28 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
   unsigned GPRCS1Size = 0, GPRCS2Size = 0, DPRCSSize = 0;
   int FramePtrSpillFI = 0;
 
-  if (ArgRegsSaveSize)
+  if (ArgRegsSaveSize) {
     emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -ArgRegsSaveSize,
                  MachineInstr::FrameSetup);
+    MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol();
+    BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+        .addSym(SPLabel);
+    CFAOffset -= ArgRegsSaveSize;
+    MMI.addFrameInst(
+        MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+  }
 
   if (!AFI->hasStackFrame()) {
-    if (NumBytes != 0)
+    if (NumBytes != 0) {
       emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -NumBytes,
                    MachineInstr::FrameSetup);
+      MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol();
+      BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+          .addSym(SPLabel);
+      CFAOffset -= NumBytes;
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+    }
     return;
   }
 
@@ -120,6 +138,15 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
     unsigned Reg = CSI[i].getReg();
     int FI = CSI[i].getFrameIdx();
     switch (Reg) {
+    case ARM::R8:
+    case ARM::R9:
+    case ARM::R10:
+    case ARM::R11:
+      if (STI.isTargetMachO()) {
+        GPRCS2Size += 4;
+        break;
+      }
+      // fallthrough
     case ARM::R4:
     case ARM::R5:
     case ARM::R6:
@@ -129,17 +156,6 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
         FramePtrSpillFI = FI;
       GPRCS1Size += 4;
       break;
-    case ARM::R8:
-    case ARM::R9:
-    case ARM::R10:
-    case ARM::R11:
-      if (Reg == FramePtr)
-        FramePtrSpillFI = FI;
-      if (STI.isTargetMachO())
-        GPRCS2Size += 4;
-      else
-        GPRCS1Size += 4;
-      break;
     default:
       DPRCSSize += 8;
     }
@@ -165,27 +181,87 @@ void Thumb1FrameLowering::emitPrologue(MachineFunction &MF) const {
   NumBytes = DPRCSOffset;
 
   int FramePtrOffsetInBlock = 0;
+  unsigned adjustedGPRCS1Size = GPRCS1Size;
   if (tryFoldSPUpdateIntoPushPop(STI, MF, prior(MBBI), NumBytes)) {
     FramePtrOffsetInBlock = NumBytes;
+    adjustedGPRCS1Size += NumBytes;
     NumBytes = 0;
   }
 
+  MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol();
+  BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL)).addSym(SPLabel);
+  if (adjustedGPRCS1Size) {
+    CFAOffset -= adjustedGPRCS1Size;
+    MMI.addFrameInst(
+        MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+  }
+  for (std::vector<CalleeSavedInfo>::const_iterator I = CSI.begin(),
+         E = CSI.end(); I != E; ++I) {
+    unsigned Reg = I->getReg();
+    int FI = I->getFrameIdx();
+    switch (Reg) {
+    case ARM::R8:
+    case ARM::R9:
+    case ARM::R10:
+    case ARM::R11:
+    case ARM::R12:
+      if (STI.isTargetMachO())
+        break;
+      // fallthough
+    case ARM::R0:
+    case ARM::R1:
+    case ARM::R2:
+    case ARM::R3:
+    case ARM::R4:
+    case ARM::R5:
+    case ARM::R6:
+    case ARM::R7:
+    case ARM::LR:
+      MMI.addFrameInst(MCCFIInstruction::createOffset(SPLabel,
+         MRI->getDwarfRegNum(Reg, true),
+         MFI->getObjectOffset(FI) - ArgRegsSaveSize));
+      break;
+    }
+  }
+
+
   // Adjust FP so it point to the stack slot that contains the previous FP.
   if (HasFP) {
     FramePtrOffsetInBlock += MFI->getObjectOffset(FramePtrSpillFI) + GPRCS1Size;
     AddDefaultPred(BuildMI(MBB, MBBI, dl, TII.get(ARM::tADDrSPi), FramePtr)
       .addReg(ARM::SP).addImm(FramePtrOffsetInBlock / 4)
       .setMIFlags(MachineInstr::FrameSetup));
+    MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol();
+    BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+        .addSym(SPLabel);
+    if(FramePtrOffsetInBlock) {
+      CFAOffset += FramePtrOffsetInBlock;
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfa(SPLabel,
+              MRI->getDwarfRegNum(FramePtr, true), CFAOffset));
+    } else
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfaRegister(SPLabel,
+              MRI->getDwarfRegNum(FramePtr, true)));
     if (NumBytes > 508)
       // If offset is > 508 then sp cannot be adjusted in a single instruction,
       // try restoring from fp instead.
       AFI->setShouldRestoreSPFromFP(true);
   }
 
-  if (NumBytes)
+  if (NumBytes) {
     // Insert it after all the callee-save spills.
     emitSPUpdate(MBB, MBBI, TII, dl, *RegInfo, -NumBytes,
                  MachineInstr::FrameSetup);
+    if (!HasFP) {
+      MCSymbol *SPLabel = MMI.getContext().CreateTempSymbol();
+      BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::PROLOG_LABEL))
+          .addSym(SPLabel);
+      CFAOffset -= NumBytes;
+      MMI.addFrameInst(
+          MCCFIInstruction::createDefCfaOffset(SPLabel, CFAOffset));
+    }
+  }
 
   if (STI.isTargetELF() && HasFP)
     MFI->setOffsetAdjustment(MFI->getOffsetAdjustment() -
diff --git a/test/CodeGen/ARM/debug-frame-large-stack.ll b/test/CodeGen/ARM/debug-frame-large-stack.ll
new file mode 100644 (file)
index 0000000..e1fc029
--- /dev/null
@@ -0,0 +1,99 @@
+; RUN: llc -filetype=asm -o - < %s -mtriple arm-arm-none-eabi -disable-fp-elim| FileCheck %s --check-prefix=CHECK-ARM
+; RUN: llc -filetype=asm -o - < %s -mtriple arm-arm-none-eabi | FileCheck %s --check-prefix=CHECK-ARM-FP-ELIM
+
+define void @test1() {
+    %tmp = alloca [ 64 x i32 ] , align 4
+    ret void
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!8, !9}
+!llvm.ident = !{!10}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/tmp/large.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"large.c", metadata !"/tmp"}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"test1", metadata !"test1", metadata !"", i32 1, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 0, i1 false, void ()* @test1, null, null, metadata !2, i32 1} ; [ DW_TAG_subprogram ] [line 1] [def] [test1]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [/tmp/large.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{null}
+!8 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!9 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!10 = metadata !{metadata !"clang version 3.5 "}
+!11 = metadata !{i32 2, i32 0, metadata !4, null}
+
+; CHECK-ARM-LABEL: test1:
+; CHECK-ARM: .cfi_startproc
+; CHECK-ARM: sub    sp, sp, #256
+; CHECK-ARM: .cfi_endproc
+
+; CHECK-ARM-FP_ELIM-LABEL: test1:
+; CHECK-ARM-FP_ELIM: .cfi_startproc
+; CHECK-ARM-FP_ELIM: sub    sp, sp, #256
+; CHECK-ARM-FP_ELIM: .cfi_endproc
+
+define void @test2() {
+    %tmp = alloca [ 4168 x i8 ] , align 4
+    ret void
+}
+
+; CHECK-ARM-LABEL: test2:
+; CHECK-ARM: .cfi_startproc
+; CHECK-ARM: push    {r4, r5}
+; CHECK-ARM: .cfi_def_cfa_offset 8
+; CHECK-ARM: .cfi_offset r5, -4
+; CHECK-ARM: .cfi_offset r4, -8
+; CHECK-ARM: sub    sp, sp, #72
+; CHECK-ARM: sub    sp, sp, #4096
+; CHECK-ARM: .cfi_def_cfa_offset 4176
+; CHECK-ARM: .cfi_endproc
+
+; CHECK-ARM-FP_ELIM-LABEL: test2:
+; CHECK-ARM-FP_ELIM: .cfi_startproc
+; CHECK-ARM-FP_ELIM: push    {r4, r5}
+; CHECK-ARM-FP_ELIM: .cfi_def_cfa_offset 8
+; CHECK-ARM-FP_ELIM: .cfi_offset 54, -4
+; CHECK-ARM-FP_ELIM: .cfi_offset r4, -8
+; CHECK-ARM-FP_ELIM: sub    sp, sp, #72
+; CHECK-ARM-FP_ELIM: sub    sp, sp, #4096
+; CHECK-ARM-FP_ELIM: .cfi_def_cfa_offset 4176
+; CHECK-ARM-FP_ELIM: .cfi_endproc
+
+define i32 @test3() {
+       %retval = alloca i32, align 4
+       %tmp = alloca i32, align 4
+       %a = alloca [805306369 x i8], align 16
+       store i32 0, i32* %tmp
+       %tmp1 = load i32* %tmp
+        ret i32 %tmp1
+}
+
+; CHECK-ARM-LABEL: test3:
+; CHECK-ARM: .cfi_startproc
+; CHECK-ARM: push    {r4, r5, r11}
+; CHECK-ARM: .cfi_def_cfa_offset 12
+; CHECK-ARM: .cfi_offset r11, -4
+; CHECK-ARM: .cfi_offset r5, -8
+; CHECK-ARM: .cfi_offset r4, -12
+; CHECK-ARM: add    r11, sp, #8
+; CHECK-ARM: .cfi_def_cfa r11, 4
+; CHECK-ARM: sub    sp, sp, #20
+; CHECK-ARM: sub    sp, sp, #805306368
+; CHECK-ARM: bic    sp, sp, #15
+; CHECK-ARM: .cfi_endproc
+
+; CHECK-ARM-FP-ELIM-LABEL: test3:
+; CHECK-ARM-FP-ELIM: .cfi_startproc
+; CHECK-ARM-FP-ELIM: push    {r4, r5, r11}
+; CHECK-ARM-FP-ELIM: .cfi_def_cfa_offset 12
+; CHECK-ARM-FP-ELIM: .cfi_offset r11, -4
+; CHECK-ARM-FP-ELIM: .cfi_offset r5, -8
+; CHECK-ARM-FP-ELIM: .cfi_offset r4, -12
+; CHECK-ARM-FP-ELIM: add    r11, sp, #8
+; CHECK-ARM-FP-ELIM: .cfi_def_cfa r11, 4
+; CHECK-ARM-FP-ELIM: sub    sp, sp, #20
+; CHECK-ARM-FP-ELIM: sub    sp, sp, #805306368
+; CHECK-ARM-FP-ELIM: bic    sp, sp, #15
+; CHECK-ARM-FP-ELIM: .cfi_endproc
+
diff --git a/test/CodeGen/ARM/debug-frame-no-debug.ll b/test/CodeGen/ARM/debug-frame-no-debug.ll
new file mode 100644 (file)
index 0000000..81702c6
--- /dev/null
@@ -0,0 +1,97 @@
+; ARM EHABI integrated test
+
+; This test case checks that the ARM DWARF stack frame directives
+; are not generated if compiling with no debug information.
+  
+; RUN: llc -mtriple arm-unknown-linux-gnueabi \
+; RUN:     -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-FP-ELIM
+
+; RUN: llc -mtriple thumb-unknown-linux-gnueabi \
+; RUN:     -disable-fp-elim -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-THUMB-FP
+
+;-------------------------------------------------------------------------------
+; Test 1
+;-------------------------------------------------------------------------------
+; This is the LLVM assembly generated from following C++ code:
+;
+;   extern void print(int, int, int, int, int);
+;   extern void print(double, double, double, double, double);
+;
+;   void test(int a, int b, int c, int d, int e,
+;             double m, double n, double p, double q, double r) {
+;     try {
+;       print(a, b, c, d, e);
+;     } catch (...) {
+;       print(m, n, p, q, r);
+;     }
+;   }
+
+declare void @_Z5printiiiii(i32, i32, i32, i32, i32)
+
+declare void @_Z5printddddd(double, double, double, double, double)
+
+define void @_Z4testiiiiiddddd(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e,
+                               double %m, double %n, double %p,
+                               double %q, double %r) {
+entry:
+  invoke void @_Z5printiiiii(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
+          to label %try.cont unwind label %lpad
+
+lpad:
+  %0 = landingpad { i8*, i32 }
+          personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+          catch i8* null
+  %1 = extractvalue { i8*, i32 } %0, 0
+  %2 = tail call i8* @__cxa_begin_catch(i8* %1)
+  invoke void @_Z5printddddd(double %m, double %n, double %p,
+                             double %q, double %r)
+          to label %invoke.cont2 unwind label %lpad1
+
+invoke.cont2:
+  tail call void @__cxa_end_catch()
+  br label %try.cont
+
+try.cont:
+  ret void
+
+lpad1:
+  %3 = landingpad { i8*, i32 }
+          personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+          cleanup
+  invoke void @__cxa_end_catch()
+          to label %eh.resume unwind label %terminate.lpad
+
+eh.resume:
+  resume { i8*, i32 } %3
+
+terminate.lpad:
+  %4 = landingpad { i8*, i32 }
+          personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+          catch i8* null
+  %5 = extractvalue { i8*, i32 } %4, 0
+  tail call void @__clang_call_terminate(i8* %5)
+  unreachable
+}
+
+declare void @__clang_call_terminate(i8*)
+
+declare i32 @__gxx_personality_v0(...)
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @__cxa_end_catch()
+
+declare void @_ZSt9terminatev()
+
+; CHECK-FP-ELIM-LABEL: _Z4testiiiiiddddd:
+; CHECK-FP-ELIM-NOT:   .cfi_startproc
+; CHECK-FP-ELIM:   push  {r4, r5, r6, r7, r8, r9, r10, r11, lr}
+; CHECK-FP-ELIM-NOT:   .cfi_def_cfa_offset 36
+
+; CHECK-THUMB-FP-LABEL: _Z4testiiiiiddddd:
+; CHECK-THUMB-FP-NOT:   .cfi_startproc
+; CHECK-THUMB-FP:   push   {r4, r5, r6, r7, lr}
+; CHECK-THUMB-FP-NOT:   .cfi_def_cfa_offset 20
+
diff --git a/test/CodeGen/ARM/debug-frame-vararg.ll b/test/CodeGen/ARM/debug-frame-vararg.ll
new file mode 100644 (file)
index 0000000..9b39525
--- /dev/null
@@ -0,0 +1,141 @@
+; RUN: llc -mtriple arm-unknown-linux-gnueabi -filetype asm -o - %s | FileCheck %s --check-prefix=CHECK-FP
+; RUN: llc -mtriple arm-unknown-linux-gnueabi -filetype asm -o - %s -disable-fp-elim | FileCheck %s --check-prefix=CHECK-FP-ELIM
+; RUN: llc -mtriple thumb-unknown-linux-gnueabi -filetype asm -o - %s | FileCheck %s --check-prefix=CHECK-THUMB-FP
+; RUN: llc -mtriple thumb-unknown-linux-gnueabi -filetype asm -o - %s -disable-fp-elim | FileCheck %s --check-prefix=CHECK-THUMB-FP-ELIM
+
+; Tests that the initial space allocated to the varargs on the stack is
+; taken into account in the the .cfi_ directives.
+
+; Generated from the C program:
+; #include <stdarg.h>
+;
+; extern int foo(int);
+;
+; int sum(int count, ...) {
+;  va_list vl;
+;  va_start(vl, count);
+;  int sum = 0;
+;  for (int i = 0; i < count; i++) {
+;   sum += foo(va_arg(vl, int));
+;  }
+;  va_end(vl);
+; }
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!9, !10}
+!llvm.ident = !{!11}
+
+!0 = metadata !{i32 786449, metadata !1, i32 12, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/tmp/var.c] [DW_LANG_C99]
+!1 = metadata !{metadata !"var.c", metadata !"/tmp"}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"sum", metadata !"sum", metadata !"", i32 5, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, i32 (i32, ...)* @sum, null, null, metadata !2, i32 5} ; [ DW_TAG_subprogram ] [line 5] [def] [sum]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [/tmp/var.c]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{metadata !8, metadata !8}
+!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!10 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!11 = metadata !{metadata !"clang version 3.5 "}
+!12 = metadata !{i32 786689, metadata !4, metadata !"count", metadata !5, i32 16777221, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [count] [line 5]
+!13 = metadata !{i32 5, i32 0, metadata !4, null}
+!14 = metadata !{i32 786688, metadata !4, metadata !"vl", metadata !5, i32 6, metadata !15, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [vl] [line 6]
+!15 = metadata !{i32 786454, metadata !16, null, metadata !"va_list", i32 30, i64 0, i64 0, i64 0, i32 0, metadata !17} ; [ DW_TAG_typedef ] [va_list] [line 30, size 0, align 0, offset 0] [from __builtin_va_list]
+!16 = metadata !{metadata !"/linux-x86_64-high/gcc_4.7.2/dbg/llvm/bin/../lib/clang/3.5/include/stdarg.h", metadata !"/tmp"}
+!17 = metadata !{i32 786454, metadata !1, null, metadata !"__builtin_va_list", i32 6, i64 0, i64 0, i64 0, i32 0, metadata !18} ; [ DW_TAG_typedef ] [__builtin_va_list] [line 6, size 0, align 0, offset 0] [from __va_list]
+!18 = metadata !{i32 786451, metadata !1, null, metadata !"__va_list", i32 6, i64 32, i64 32, i32 0, i32 0, null, metadata !19, i32 0, null, null, null} ; [ DW_TAG_structure_type ] [__va_list] [line 6, size 32, align 32, offset 0] [def] [from ]
+!19 = metadata !{metadata !20}
+!20 = metadata !{i32 786445, metadata !1, metadata !18, metadata !"__ap", i32 6, i64 32, i64 32, i64 0, i32 0, metadata !21} ; [ DW_TAG_member ] [__ap] [line 6, size 32, align 32, offset 0] [from ]
+!21 = metadata !{i32 786447, null, null, metadata !"", i32 0, i64 32, i64 32, i64 0, i32 0, null} ; [ DW_TAG_pointer_type ] [line 0, size 32, align 32, offset 0] [from ]
+!22 = metadata !{i32 6, i32 0, metadata !4, null}
+!23 = metadata !{i32 7, i32 0, metadata !4, null}
+!24 = metadata !{i32 786688, metadata !4, metadata !"sum", metadata !5, i32 8, metadata !8, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [sum] [line 8]
+!25 = metadata !{i32 8, i32 0, metadata !4, null} ; [ DW_TAG_imported_declaration ]
+!26 = metadata !{i32 786688, metadata !27, metadata !"i", metadata !5, i32 9, metadata !8, i32 0, i32 0} ; [ DW_TAG_auto_variable ] [i] [line 9]
+!27 = metadata !{i32 786443, metadata !1, metadata !4, i32 9, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [/tmp/var.c]
+!28 = metadata !{i32 9, i32 0, metadata !27, null}
+!29 = metadata !{i32 10, i32 0, metadata !30, null}
+!30 = metadata !{i32 786443, metadata !1, metadata !27, i32 9, i32 0, i32 1} ; [ DW_TAG_lexical_block ] [/tmp/var.c]
+!31 = metadata !{i32 11, i32 0, metadata !30, null}
+!32 = metadata !{i32 12, i32 0, metadata !4, null}
+!33 = metadata !{i32 13, i32 0, metadata !4, null}
+
+; CHECK-FP-LABEL: sum
+; CHECK-FP: .cfi_startproc
+; CHECK-FP: sub    sp, sp, #16
+; CHECK-FP: .cfi_def_cfa_offset 16
+; CHECK-FP: push   {r4, lr}
+; CHECK-FP: .cfi_def_cfa_offset 24
+; CHECK-FP: .cfi_offset lr, -20
+; CHECK-FP: .cfi_offset r4, -24
+; CHECK-FP: sub    sp, sp, #8
+; CHECK-FP: .cfi_def_cfa_offset 32
+
+; CHECK-FP-ELIM-LABEL: sum
+; CHECK-FP-ELIM: .cfi_startproc
+; CHECK-FP-ELIM: sub    sp, sp, #16
+; CHECK-FP-ELIM: .cfi_def_cfa_offset 16
+; CHECK-FP-ELIM: push   {r4, r11, lr}
+; CHECK-FP-ELIM: .cfi_def_cfa_offset 28
+; CHECK-FP-ELIM: .cfi_offset lr, -20
+; CHECK-FP-ELIM: .cfi_offset r11, -24
+; CHECK-FP-ELIM: .cfi_offset r4, -28
+; CHECK-FP-ELIM: add    r11, sp, #4
+; CHECK-FP-ELIM: .cfi_def_cfa r11, 24
+
+; CHECK-THUMB-FP-LABEL: sum
+; CHECK-THUMB-FP: .cfi_startproc
+; CHECK-THUMB-FP: sub    sp, #16
+; CHECK-THUMB-FP: .cfi_def_cfa_offset 16
+; CHECK-THUMB-FP: push   {r4, r5, r7, lr}
+; CHECK-THUMB-FP: .cfi_def_cfa_offset 32
+; CHECK-THUMB-FP: .cfi_offset lr, -20
+; CHECK-THUMB-FP: .cfi_offset r7, -24
+; CHECK-THUMB-FP: .cfi_offset r5, -28
+; CHECK-THUMB-FP: .cfi_offset r4, -32
+; CHECK-THUMB-FP: sub    sp, #8
+; CHECK-THUMB-FP: .cfi_def_cfa_offset 40
+
+; CHECK-THUMB-FP-ELIM-LABEL: sum
+; CHECK-THUMB-FP-ELIM: .cfi_startproc
+; CHECK-THUMB-FP-ELIM: sub    sp, #16
+; CHECK-THUMB-FP-ELIM: .cfi_def_cfa_offset 16
+; CHECK-THUMB-FP-ELIM: push   {r4, r5, r7, lr}
+; CHECK-THUMB-FP-ELIM: .cfi_def_cfa_offset 32
+; CHECK-THUMB-FP-ELIM: .cfi_offset lr, -20
+; CHECK-THUMB-FP-ELIM: .cfi_offset r7, -24
+; CHECK-THUMB-FP-ELIM: .cfi_offset r5, -28
+; CHECK-THUMB-FP-ELIM: .cfi_offset r4, -32
+; CHECK-THUMB-FP-ELIM: add    r7, sp, #8
+; CHECK-THUMB-FP-ELIM: .cfi_def_cfa r7, 24
+
+define i32 @sum(i32 %count, ...) {
+entry:
+  %vl = alloca i8*, align 4
+  %vl1 = bitcast i8** %vl to i8*
+  call void @llvm.va_start(i8* %vl1)
+  %cmp4 = icmp sgt i32 %count, 0
+  br i1 %cmp4, label %for.body, label %for.end
+
+for.body:                                         ; preds = %entry, %for.body
+  %i.05 = phi i32 [ %inc, %for.body ], [ 0, %entry ]
+  %ap.cur = load i8** %vl, align 4
+  %ap.next = getelementptr i8* %ap.cur, i32 4
+  store i8* %ap.next, i8** %vl, align 4
+  %0 = bitcast i8* %ap.cur to i32*
+  %1 = load i32* %0, align 4
+  %call = call i32 @foo(i32 %1) #1
+  %inc = add nsw i32 %i.05, 1
+  %exitcond = icmp eq i32 %inc, %count
+  br i1 %exitcond, label %for.end, label %for.body
+
+for.end:                                          ; preds = %for.body, %entry
+  call void @llvm.va_end(i8* %vl1)
+  ret i32 undef
+}
+
+declare void @llvm.va_start(i8*) nounwind
+
+declare i32 @foo(i32)
+
+declare void @llvm.va_end(i8*) nounwind
diff --git a/test/CodeGen/ARM/debug-frame.ll b/test/CodeGen/ARM/debug-frame.ll
new file mode 100644 (file)
index 0000000..e18501a
--- /dev/null
@@ -0,0 +1,551 @@
+; ARM EHABI integrated test
+
+; This test case checks whether the ARM DWARF stack frame directives
+; are properly generated or not.
+
+; We have to check several cases:
+; (1) arm with -disable-fp-elim
+; (2) arm without -disable-fp-elim
+; (3) armv7 with -disable-fp-elim
+; (4) armv7 without -disable-fp-elim
+; (5) thumb with -disable-fp-elim
+; (6) thumb without -disable-fp-elim
+; (7) thumbv7 with -disable-fp-elim
+; (8) thumbv7 without -disable-fp-elim
+
+; RUN: llc -mtriple arm-unknown-linux-gnueabi \
+; RUN:     -disable-fp-elim -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-FP
+
+; RUN: llc -mtriple arm-unknown-linux-gnueabi \
+; RUN:     -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-FP-ELIM
+
+; RUN: llc -mtriple armv7-unknown-linux-gnueabi \
+; RUN:     -disable-fp-elim -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-V7-FP
+
+; RUN: llc -mtriple armv7-unknown-linux-gnueabi \
+; RUN:     -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-V7-FP-ELIM
+
+; RUN: llc -mtriple thumb-unknown-linux-gnueabi \
+; RUN:     -disable-fp-elim -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-THUMB-FP
+
+; RUN: llc -mtriple thumb-unknown-linux-gnueabi \
+; RUN:     -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-THUMB-FP-ELIM
+
+; RUN: llc -mtriple thumbv7-unknown-linux-gnueabi \
+; RUN:     -disable-fp-elim -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-THUMB-V7-FP
+
+; RUN: llc -mtriple thumbv7-unknown-linux-gnueabi \
+; RUN:     -filetype=asm -o - %s \
+; RUN:   | FileCheck %s --check-prefix=CHECK-THUMB-V7-FP-ELIM
+
+;-------------------------------------------------------------------------------
+; Test 1
+;-------------------------------------------------------------------------------
+; This is the LLVM assembly generated from following C++ code:
+;
+;   extern void print(int, int, int, int, int);
+;   extern void print(double, double, double, double, double);
+;
+;   void test(int a, int b, int c, int d, int e,
+;             double m, double n, double p, double q, double r) {
+;     try {
+;       print(a, b, c, d, e);
+;     } catch (...) {
+;       print(m, n, p, q, r);
+;     }
+;   }
+
+declare void @_Z5printiiiii(i32, i32, i32, i32, i32)
+
+declare void @_Z5printddddd(double, double, double, double, double)
+
+define void @_Z4testiiiiiddddd(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e,
+                               double %m, double %n, double %p,
+                               double %q, double %r) {
+entry:
+  invoke void @_Z5printiiiii(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e)
+          to label %try.cont unwind label %lpad
+
+lpad:
+  %0 = landingpad { i8*, i32 }
+          personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+          catch i8* null
+  %1 = extractvalue { i8*, i32 } %0, 0
+  %2 = tail call i8* @__cxa_begin_catch(i8* %1)
+  invoke void @_Z5printddddd(double %m, double %n, double %p,
+                             double %q, double %r)
+          to label %invoke.cont2 unwind label %lpad1
+
+invoke.cont2:
+  tail call void @__cxa_end_catch()
+  br label %try.cont
+
+try.cont:
+  ret void
+
+lpad1:
+  %3 = landingpad { i8*, i32 }
+          personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+          cleanup
+  invoke void @__cxa_end_catch()
+          to label %eh.resume unwind label %terminate.lpad
+
+eh.resume:
+  resume { i8*, i32 } %3
+
+terminate.lpad:
+  %4 = landingpad { i8*, i32 }
+          personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*)
+          catch i8* null
+  %5 = extractvalue { i8*, i32 } %4, 0
+  tail call void @__clang_call_terminate(i8* %5)
+  unreachable
+}
+
+declare void @__clang_call_terminate(i8*)
+
+declare i32 @__gxx_personality_v0(...)
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @__cxa_end_catch()
+
+declare void @_ZSt9terminatev()
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!10, !11}
+!llvm.ident = !{!12}
+
+!0 = metadata !{i32 786449, metadata !1, i32 4, metadata !"clang version 3.5 ", i1 false, metadata !"", i32 0, metadata !2, metadata !2, metadata !3, metadata !2, metadata !2, metadata !""} ; [ DW_TAG_compile_unit ] [/tmp/exp.cpp] [DW_LANG_C_plus_plus]
+!1 = metadata !{metadata !"exp.cpp", metadata !"/tmp"}
+!2 = metadata !{}
+!3 = metadata !{metadata !4}
+!4 = metadata !{i32 786478, metadata !1, metadata !5, metadata !"test", metadata !"test", metadata !"_Z4testiiiiiddddd", i32 4, metadata !6, i1 false, i1 true, i32 0, i32 0, null, i32 256, i1 false, void (i32, i32, i32, i32, i32, double, double, double, double, double)* @_Z4testiiiiiddddd, null, null, metadata !2, i32 5} ; [ DW_TAG_subprogram ] [line 4] [def] [scope 5] [test]
+!5 = metadata !{i32 786473, metadata !1}          ; [ DW_TAG_file_type ] [/tmp/exp.cpp]
+!6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ]
+!7 = metadata !{null, metadata !8, metadata !8, metadata !8, metadata !8, metadata !8, metadata !9, metadata !9, metadata !9, metadata !9, metadata !9}
+!8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed]
+!9 = metadata !{i32 786468, null, null, metadata !"double", i32 0, i64 64, i64 64, i64 0, i32 0, i32 4} ; [ DW_TAG_base_type ] [double] [line 0, size 64, align 64, offset 0, enc DW_ATE_float]
+!10 = metadata !{i32 2, metadata !"Dwarf Version", i32 4}
+!11 = metadata !{i32 1, metadata !"Debug Info Version", i32 1}
+!12 = metadata !{metadata !"clang version 3.5 "}
+!13 = metadata !{i32 786689, metadata !4, metadata !"a", metadata !5, i32 16777220, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [a] [line 4]
+!14 = metadata !{i32 4, i32 0, metadata !4, null}
+!15 = metadata !{i32 786689, metadata !4, metadata !"b", metadata !5, i32 33554436, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [b] [line 4]
+!16 = metadata !{i32 786689, metadata !4, metadata !"c", metadata !5, i32 50331652, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [c] [line 4]
+!17 = metadata !{i32 786689, metadata !4, metadata !"d", metadata !5, i32 67108868, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [d] [line 4]
+!18 = metadata !{i32 786689, metadata !4, metadata !"e", metadata !5, i32 83886084, metadata !8, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [e] [line 4]
+!19 = metadata !{i32 786689, metadata !4, metadata !"m", metadata !5, i32 100663301, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [m] [line 5]
+!20 = metadata !{i32 5, i32 0, metadata !4, null}
+!21 = metadata !{i32 786689, metadata !4, metadata !"n", metadata !5, i32 117440517, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [n] [line 5]
+!22 = metadata !{i32 786689, metadata !4, metadata !"p", metadata !5, i32 134217733, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [p] [line 5]
+!23 = metadata !{i32 786689, metadata !4, metadata !"q", metadata !5, i32 150994949, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [q] [line 5]
+!24 = metadata !{i32 786689, metadata !4, metadata !"r", metadata !5, i32 167772165, metadata !9, i32 0, i32 0} ; [ DW_TAG_arg_variable ] [r] [line 5]
+!25 = metadata !{i32 7, i32 0, metadata !26, null}
+!26 = metadata !{i32 786443, metadata !1, metadata !4, i32 6, i32 0, i32 0} ; [ DW_TAG_lexical_block ] [/tmp/exp.cpp]
+!27 = metadata !{i32 8, i32 0, metadata !26, null} ; [ DW_TAG_imported_declaration ]
+!28 = metadata !{i32 11, i32 0, metadata !26, null}
+!29 = metadata !{i32 9, i32 0, metadata !30, null}
+!30 = metadata !{i32 786443, metadata !1, metadata !4, i32 8, i32 0, i32 1} ; [ DW_TAG_lexical_block ] [/tmp/exp.cpp]
+!31 = metadata !{i32 10, i32 0, metadata !30, null}
+!32 = metadata !{i32 10, i32 0, metadata !4, null}
+!33 = metadata !{i32 11, i32 0, metadata !4, null}
+!34 = metadata !{i32 11, i32 0, metadata !30, null}
+
+; CHECK-FP-LABEL: _Z4testiiiiiddddd:
+; CHECK-FP:   .cfi_startproc
+; CHECK-FP:   push   {r4, r5, r6, r7, r8, r9, r10, r11, lr}
+; CHECK-FP:   .cfi_def_cfa_offset 36
+; CHECK-FP:   .cfi_offset lr, -4
+; CHECK-FP:   .cfi_offset r11, -8
+; CHECK-FP:   .cfi_offset r10, -12
+; CHECK-FP:   .cfi_offset r9, -16
+; CHECK-FP:   .cfi_offset r8, -20
+; CHECK-FP:   .cfi_offset r7, -24
+; CHECK-FP:   .cfi_offset r6, -28
+; CHECK-FP:   .cfi_offset r5, -32
+; CHECK-FP:   .cfi_offset r4, -36
+; CHECK-FP:   add    r11, sp, #28
+; CHECK-FP:   .cfi_def_cfa r11, 8
+; CHECK-FP:   sub    sp, sp, #28
+; CHECK-FP:   .cfi_endproc
+
+; CHECK-FP-ELIM-LABEL: _Z4testiiiiiddddd:
+; CHECK-FP-ELIM:   .cfi_startproc
+; CHECK-FP-ELIM:   push  {r4, r5, r6, r7, r8, r9, r10, r11, lr}
+; CHECK-FP-ELIM:   .cfi_def_cfa_offset 36
+; CHECK-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-FP-ELIM:   .cfi_offset r10, -12
+; CHECK-FP-ELIM:   .cfi_offset r9, -16
+; CHECK-FP-ELIM:   .cfi_offset r8, -20
+; CHECK-FP-ELIM:   .cfi_offset r7, -24
+; CHECK-FP-ELIM:   .cfi_offset r6, -28
+; CHECK-FP-ELIM:   .cfi_offset r5, -32
+; CHECK-FP-ELIM:   .cfi_offset r4, -36
+; CHECK-FP-ELIM:   sub   sp, sp, #28
+; CHECK-FP-ELIM:   .cfi_def_cfa_offset 64
+; CHECK-FP-ELIM:   .cfi_endproc
+
+; CHECK-V7-FP-LABEL: _Z4testiiiiiddddd:
+; CHECK-V7-FP:   .cfi_startproc
+; CHECK-V7-FP:   push   {r4, r11, lr}
+; CHECK-V7-FP:   .cfi_def_cfa_offset 12
+; CHECK-V7-FP:   .cfi_offset lr, -4
+; CHECK-V7-FP:   .cfi_offset r11, -8
+; CHECK-V7-FP:   .cfi_offset r4, -12
+; CHECK-V7-FP:   add    r11, sp, #4
+; CHECK-V7-FP:   .cfi_def_cfa r11, 8
+; CHECK-V7-FP:   vpush  {d8, d9, d10, d11, d12}
+; CHECK-V7-FP:   .cfi_offset d12, -24
+; CHECK-V7-FP:   .cfi_offset d11, -32
+; CHECK-V7-FP:   .cfi_offset d10, -40
+; CHECK-V7-FP:   .cfi_offset d9, -48
+; CHECK-V7-FP:   .cfi_offset d8, -56
+; CHECK-V7-FP:   sub    sp, sp, #28
+; CHECK-V7-FP:   .cfi_endproc
+
+; CHECK-V7-FP-ELIM-LABEL: _Z4testiiiiiddddd:
+; CHECK-V7-FP-ELIM:   .cfi_startproc
+; CHECK-V7-FP-ELIM:   push   {r4, lr}
+; CHECK-V7-FP-ELIM:   .cfi_def_cfa_offset 8
+; CHECK-V7-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-V7-FP-ELIM:   .cfi_offset r4, -8
+; CHECK-V7-FP-ELIM:   vpush  {d8, d9, d10, d11, d12}
+; CHECK-V7-FP-ELIM:   .cfi_def_cfa_offset 48
+; CHECK-V7-FP-ELIM:   .cfi_offset d12, -16
+; CHECK-V7-FP-ELIM:   .cfi_offset d11, -24
+; CHECK-V7-FP-ELIM:   .cfi_offset d10, -32
+; CHECK-V7-FP-ELIM:   .cfi_offset d9, -40
+; CHECK-V7-FP-ELIM:   .cfi_offset d8, -48
+; CHECK-V7-FP-ELIM:   sub    sp, sp, #24
+; CHECK-V7-FP-ELIM:   .cfi_def_cfa_offset 72
+; CHECK-V7-FP-ELIM:   .cfi_endproc
+
+; CHECK-THUMB-FP-LABEL: _Z4testiiiiiddddd:
+; CHECK-THUMB-FP:   .cfi_startproc
+; CHECK-THUMB-FP:   push   {r4, r5, r6, r7, lr}
+; CHECK-THUMB-FP:   .cfi_def_cfa_offset 20
+; CHECK-THUMB-FP:   .cfi_offset lr, -4
+; CHECK-THUMB-FP:   .cfi_offset r7, -8
+; CHECK-THUMB-FP:   .cfi_offset r6, -12
+; CHECK-THUMB-FP:   .cfi_offset r5, -16
+; CHECK-THUMB-FP:   .cfi_offset r4, -20
+; CHECK-THUMB-FP:   add    r7, sp, #12
+; CHECK-THUMB-FP:   .cfi_def_cfa r7, 8
+; CHECK-THUMB-FP:   sub    sp, #60
+; CHECK-THUMB-FP:   .cfi_endproc
+
+; CHECK-THUMB-FP-ELIM-LABEL: _Z4testiiiiiddddd:
+; CHECK-THUMB-FP-ELIM:   .cfi_startproc
+; CHECK-THUMB-FP-ELIM:   push   {r4, r5, r6, r7, lr}
+; CHECK-THUMB-FP-ELIM:   .cfi_def_cfa_offset 20
+; CHECK-THUMB-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r7, -8
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r6, -12
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r5, -16
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r4, -20
+; CHECK-THUMB-FP-ELIM:   sub    sp, #60
+; CHECK-THUMB-FP-ELIM:   .cfi_def_cfa_offset 80
+; CHECK-THUMB-FP-ELIM:   .cfi_endproc
+
+; CHECK-THUMB-V7-FP-LABEL: _Z4testiiiiiddddd:
+; CHECK-THUMB-V7-FP:   .cfi_startproc
+; CHECK-THUMB-V7-FP:   push.w   {r4, r7, r11, lr}
+; CHECK-THUMB-V7-FP:   .cfi_def_cfa_offset 16
+; CHECK-THUMB-V7-FP:   .cfi_offset lr, -4
+; CHECK-THUMB-V7-FP:   .cfi_offset r11, -8
+; CHECK-THUMB-V7-FP:   .cfi_offset r7, -12
+; CHECK-THUMB-V7-FP:   .cfi_offset r4, -16
+; CHECK-THUMB-V7-FP:   add    r7, sp, #4
+; CHECK-THUMB-V7-FP:   .cfi_def_cfa r7, 12
+; CHECK-THUMB-V7-FP:   vpush  {d8, d9, d10, d11, d12}
+; CHECK-THUMB-V7-FP:   .cfi_offset d12, -24
+; CHECK-THUMB-V7-FP:   .cfi_offset d11, -32
+; CHECK-THUMB-V7-FP:   .cfi_offset d10, -40
+; CHECK-THUMB-V7-FP:   .cfi_offset d9, -48
+; CHECK-THUMB-V7-FP:   .cfi_offset d8, -56
+; CHECK-THUMB-V7-FP:   sub    sp, #24
+; CHECK-THUMB-V7-FP:   .cfi_endproc
+
+; CHECK-THUMB-V7-FP-ELIM-LABEL: _Z4testiiiiiddddd:
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_startproc
+; CHECK-THUMB-V7-FP-ELIM:   push   {r4, lr}
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_def_cfa_offset 8
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset r4, -8
+; CHECK-THUMB-V7-FP-ELIM:   vpush  {d8, d9, d10, d11, d12}
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_def_cfa_offset 48
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset d12, -16
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset d11, -24
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset d10, -32
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset d9, -40
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset d8, -48
+; CHECK-THUMB-V7-FP-ELIM:   sub    sp, #24
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_def_cfa_offset 72
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_endproc
+
+
+;-------------------------------------------------------------------------------
+; Test 2
+;-------------------------------------------------------------------------------
+
+declare void @throw_exception_2()
+
+define void @test2() {
+entry:
+  tail call void @throw_exception_2()
+  ret void
+}
+
+; CHECK-FP-LABEL: test2:
+; CHECK-FP:   .cfi_startproc
+; CHECK-FP:   push   {r11, lr}
+; CHECK-FP:   .cfi_def_cfa_offset 8
+; CHECK-FP:   .cfi_offset lr, -4
+; CHECK-FP:   .cfi_offset r11, -8
+; CHECK-FP:   mov    r11, sp
+; CHECK-FP:   .cfi_def_cfa_register r11
+; CHECK-FP:   pop    {r11, lr}
+; CHECK-FP:   mov    pc, lr
+; CHECK-FP:   .cfi_endproc
+
+; CHECK-FP-ELIM-LABEL: test2:
+; CHECK-FP-ELIM:   .cfi_startproc
+; CHECK-FP-ELIM:   push  {r11, lr}
+; CHECK-FP-ELIM:   .cfi_def_cfa_offset 8
+; CHECK-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-FP-ELIM:   pop   {r11, lr}
+; CHECK-FP-ELIM:   mov   pc, lr
+; CHECK-FP-ELIM:   .cfi_endproc
+
+; CHECK-V7-FP-LABEL: test2:
+; CHECK-V7-FP:   .cfi_startproc
+; CHECK-V7-FP:   push   {r11, lr}
+; CHECK-V7-FP:   .cfi_def_cfa_offset 8
+; CHECK-V7-FP:   .cfi_offset lr, -4
+; CHECK-V7-FP:   .cfi_offset r11, -8
+; CHECK-V7-FP:   mov    r11, sp
+; CHECK-V7-FP:   .cfi_def_cfa_register r11
+; CHECK-V7-FP:   pop    {r11, pc}
+; CHECK-V7-FP:   .cfi_endproc
+
+; CHECK-V7-FP-ELIM-LABEL: test2:
+; CHECK-V7-FP-ELIM:   .cfi_startproc
+; CHECK-V7-FP-ELIM:   push  {r11, lr}
+; CHECK-V7-FP-ELIM:   .cfi_def_cfa_offset 8
+; CHECK-V7-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-V7-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-V7-FP-ELIM:   pop   {r11, pc}
+; CHECK-V7-FP-ELIM:   .cfi_endproc
+
+; CHECK-THUMB-FP-LABEL: test2:
+; CHECK-THUMB-FP:   .cfi_startproc
+; CHECK-THUMB-FP:   push   {r7, lr}
+; CHECK-THUMB-FP:   .cfi_def_cfa_offset 8
+; CHECK-THUMB-FP:   .cfi_offset lr, -4
+; CHECK-THUMB-FP:   .cfi_offset r7, -8
+; CHECK-THUMB-FP:   add    r7, sp, #0
+; CHECK-THUMB-FP:   .cfi_def_cfa_register r7
+; CHECK-THUMB-FP:   pop    {r7, pc}
+; CHECK-THUMB-FP:   .cfi_endproc
+
+; CHECK-THUMB-FP-ELIM-LABEL: test2:
+; CHECK-THUMB-FP-ELIM:   .cfi_startproc
+; CHECK-THUMB-FP-ELIM:   push  {r7, lr}
+; CHECK-THUMB-FP-ELIM:   .cfi_def_cfa_offset 8
+; CHECK-THUMB-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r7, -8
+; CHECK-THUMB-FP-ELIM:   pop   {r7, pc}
+; CHECK-THUMB-FP-ELIM:   .cfi_endproc
+
+; CHECK-THUMB-V7-FP-LABEL: test2:
+; CHECK-THUMB-V7-FP:   .cfi_startproc
+; CHECK-THUMB-V7-FP:   push   {r7, lr}
+; CHECK-THUMB-V7-FP:   .cfi_def_cfa_offset 8
+; CHECK-THUMB-V7-FP:   .cfi_offset lr, -4
+; CHECK-THUMB-V7-FP:   .cfi_offset r7, -8
+; CHECK-THUMB-V7-FP:   mov    r7, sp
+; CHECK-THUMB-V7-FP:   .cfi_def_cfa_register r7
+; CHECK-THUMB-V7-FP:   pop    {r7, pc}
+; CHECK-THUMB-V7-FP:   .cfi_endproc
+
+; CHECK-THUMB-V7-FP-ELIM-LABEL: test2:
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_startproc
+; CHECK-THUMB-V7-FP-ELIM:   push.w  {r11, lr}
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_def_cfa_offset 8
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-THUMB-V7-FP-ELIM:   pop.w   {r11, pc}
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_endproc
+
+
+;-------------------------------------------------------------------------------
+; Test 3
+;-------------------------------------------------------------------------------
+
+declare void @throw_exception_3(i32)
+
+define i32 @test3(i32 %a, i32 %b, i32 %c, i32 %d,
+                  i32 %e, i32 %f, i32 %g, i32 %h) {
+entry:
+  %add = add nsw i32 %b, %a
+  %add1 = add nsw i32 %add, %c
+  %add2 = add nsw i32 %add1, %d
+  tail call void @throw_exception_3(i32 %add2)
+  %add3 = add nsw i32 %f, %e
+  %add4 = add nsw i32 %add3, %g
+  %add5 = add nsw i32 %add4, %h
+  tail call void @throw_exception_3(i32 %add5)
+  %add6 = add nsw i32 %add5, %add2
+  ret i32 %add6
+}
+
+; CHECK-FP-LABEL: test3:
+; CHECK-FP:   .cfi_startproc
+; CHECK-FP:   push   {r4, r5, r11, lr}
+; CHECK-FP:   .cfi_def_cfa_offset 16
+; CHECK-FP:   .cfi_offset lr, -4
+; CHECK-FP:   .cfi_offset r11, -8
+; CHECK-FP:   .cfi_offset r5, -12
+; CHECK-FP:   .cfi_offset r4, -16
+; CHECK-FP:   add    r11, sp, #8
+; CHECK-FP:   .cfi_def_cfa r11, 8
+; CHECK-FP:   pop    {r4, r5, r11, lr}
+; CHECK-FP:   mov    pc, lr
+; CHECK-FP:   .cfi_endproc
+
+; CHECK-FP-ELIM-LABEL: test3:
+; CHECK-FP-ELIM:   .cfi_startproc
+; CHECK-FP-ELIM:   push  {r4, r5, r11, lr}
+; CHECK-FP-ELIM:   .cfi_def_cfa_offset 16
+; CHECK-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-FP-ELIM:   .cfi_offset r5, -12
+; CHECK-FP-ELIM:   .cfi_offset r4, -16
+; CHECK-FP-ELIM:   pop   {r4, r5, r11, lr}
+; CHECK-FP-ELIM:   mov   pc, lr
+; CHECK-FP-ELIM:   .cfi_endproc
+
+; CHECK-V7-FP-LABEL: test3:
+; CHECK-V7-FP:   .cfi_startproc
+; CHECK-V7-FP:   push   {r4, r5, r11, lr}
+; CHECK-V7-FP:   .cfi_def_cfa_offset 16
+; CHECK-V7-FP:   .cfi_offset lr, -4
+; CHECK-V7-FP:   .cfi_offset r11, -8
+; CHECK-V7-FP:   .cfi_offset r5, -12
+; CHECK-V7-FP:   .cfi_offset r4, -16
+; CHECK-V7-FP:   add    r11, sp, #8
+; CHECK-V7-FP:   .cfi_def_cfa r11, 8
+; CHECK-V7-FP:   pop    {r4, r5, r11, pc}
+; CHECK-V7-FP:   .cfi_endproc
+
+; CHECK-V7-FP-ELIM-LABEL: test3:
+; CHECK-V7-FP-ELIM:   .cfi_startproc
+; CHECK-V7-FP-ELIM:   push  {r4, r5, r11, lr}
+; CHECK-V7-FP-ELIM:   .cfi_def_cfa_offset 16
+; CHECK-V7-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-V7-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-V7-FP-ELIM:   .cfi_offset r5, -12
+; CHECK-V7-FP-ELIM:   .cfi_offset r4, -16
+; CHECK-V7-FP-ELIM:   pop   {r4, r5, r11, pc}
+; CHECK-V7-FP-ELIM:   .cfi_endproc
+
+; CHECK-THUMB-FP-LABEL: test3:
+; CHECK-THUMB-FP:   .cfi_startproc
+; CHECK-THUMB-FP:   push   {r4, r5, r7, lr}
+; CHECK-THUMB-FP:   .cfi_def_cfa_offset 16
+; CHECK-THUMB-FP:   .cfi_offset lr, -4
+; CHECK-THUMB-FP:   .cfi_offset r7, -8
+; CHECK-THUMB-FP:   .cfi_offset r5, -12
+; CHECK-THUMB-FP:   .cfi_offset r4, -16
+; CHECK-THUMB-FP:   add    r7, sp, #8
+; CHECK-THUMB-FP:   .cfi_def_cfa r7, 8
+; CHECK-THUMB-FP:   pop    {r4, r5, r7, pc}
+; CHECK-THUMB-FP:   .cfi_endproc
+
+; CHECK-THUMB-FP-ELIM-LABEL: test3:
+; CHECK-THUMB-FP-ELIM:   .cfi_startproc
+; CHECK-THUMB-FP-ELIM:   push  {r4, r5, r7, lr}
+; CHECK-THUMB-FP-ELIM:   .cfi_def_cfa_offset 16
+; CHECK-THUMB-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r7, -8
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r5, -12
+; CHECK-THUMB-FP-ELIM:   .cfi_offset r4, -16
+; CHECK-THUMB-FP-ELIM:   pop   {r4, r5, r7, pc}
+; CHECK-THUMB-FP-ELIM:   .cfi_endproc
+
+; CHECK-THUMB-V7-FP-LABEL: test3:
+; CHECK-THUMB-V7-FP:   .cfi_startproc
+; CHECK-THUMB-V7-FP:   push   {r4, r5, r7, lr}
+; CHECK-THUMB-V7-FP:   .cfi_def_cfa_offset 16
+; CHECK-THUMB-V7-FP:   .cfi_offset lr, -4
+; CHECK-THUMB-V7-FP:   .cfi_offset r7, -8
+; CHECK-THUMB-V7-FP:   .cfi_offset r5, -12
+; CHECK-THUMB-V7-FP:   .cfi_offset r4, -16
+; CHECK-THUMB-V7-FP:   add    r7, sp, #8
+; CHECK-THUMB-V7-FP:   .cfi_def_cfa r7, 8
+; CHECK-THUMB-V7-FP:   pop    {r4, r5, r7, pc}
+; CHECK-THUMB-V7-FP:   .cfi_endproc
+
+; CHECK-THUMB-V7-FP-ELIM-LABEL: test3:
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_startproc
+; CHECK-THUMB-V7-FP-ELIM:   push.w  {r4, r5, r11, lr}
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_def_cfa_offset 16
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset lr, -4
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset r11, -8
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset r5, -12
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_offset r4, -16
+; CHECK-THUMB-V7-FP-ELIM:   pop.w   {r4, r5, r11, pc}
+; CHECK-THUMB-V7-FP-ELIM:   .cfi_endproc
+
+
+;-------------------------------------------------------------------------------
+; Test 4
+;-------------------------------------------------------------------------------
+
+define void @test4() nounwind {
+entry:
+  ret void
+}
+
+; CHECK-FP-LABEL: test4:
+; CHECK-FP:   mov pc, lr
+; CHECK-FP-NOT:   .cfi_def_cfa_offset
+
+; CHECK-FP-ELIM-LABEL: test4:
+; CHECK-FP-ELIM:   mov pc, lr
+; CHECK-FP-ELIM-NOT:   .cfi_def_cfa_offset
+
+; CHECK-V7-FP-LABEL: test4:
+; CHECK-V7-FP:   bx lr
+; CHECK-V7-FP-NOT:   .cfi_def_cfa_offset
+
+; CHECK-V7-FP-ELIM-LABEL: test4:
+; CHECK-V7-FP-ELIM:   bx lr
+; CHECK-V7-FP-ELIM-NOT:   .cfi_def_cfa_offset
+
+; CHECK-THUMB-FP-LABEL: test4:
+; CHECK-THUMB-FP:   bx lr
+; CHECK-THUMB-FP-NOT:   .cfi_def_cfa_offset
+
+; CHECK-THUMB-FP-ELIM-LABEL: test4:
+; CHECK-THUMB-FP-ELIM:   bx lr
+; CHECK-THUMB-FP-ELIM-NOT:   .cfi_def_cfa_offset
+
+; CHECK-THUMB-V7-FP-LABEL: test4:
+; CHECK-THUMB-V7-FP:   bx lr
+; CHECK-THUMB-V7-FP-NOT:   .cfi_def_cfa_offset
+
+; CHECK-THUMB-V7-FP-ELIM-LABEL: test4:
+; CHECK-THUMB-V7-FP-ELIM:   bx lr
+; CHECK-THUMB-V7-FP-ELIM-NOT:   .cfi_def_cfa_offset
+
index 854fcab..a27b056 100644 (file)
@@ -3,9 +3,12 @@
 target datalayout = "e-p:32:32:32-i1:8:32-i8:8:32-i16:16:32-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:32:64-v128:32:128-a0:0:32-n32"
 target triple = "thumbv7-apple-macosx10.6.7"
 
-;CHECK: Ldebug_loc0:
-;CHECK-NEXT:        .long   Ltmp0
-;CHECK-NEXT:        .long   Ltmp1
+;CHECK-LABEL: Lfunc_begin0:
+;CHECK: Ltmp[[K:[0-9]+]]:
+;CHECK: Ltmp[[L:[0-9]+]]:
+;CHECK-LABEL: Ldebug_loc0:
+;CHECK-NEXT:        .long   Ltmp[[K]]
+;CHECK-NEXT:        .long   Ltmp[[L]]
 ;CHECK-NEXT: Lset[[N:[0-9]+]] = Ltmp{{[0-9]+}}-Ltmp[[M:[0-9]+]]        @ Loc expr size
 ;CHECK-NEXT:        .short  Lset[[N]]
 ;CHECK-NEXT: Ltmp[[M]]:
index 0c41da6..9b9ab2a 100644 (file)
@@ -9,7 +9,7 @@
 ; statement shouldn't be implicitly defined.
 
 ; CHECK-LABEL:      func:
-; CHECK:      Ltmp1:    @ Block address taken
+; CHECK:      Ltmp3:    @ Block address taken
 ; CHECK-NOT:            @ implicit-def: R0
 ; CHECK:                @ 4-byte Reload
 
index 7c49cb3..9a6f417 100644 (file)
@@ -69,7 +69,7 @@ L1:                                               ; preds = %L2, %bb2
   store i8* blockaddress(@foo, %L5), i8** @nextaddr, align 4
   ret i32 %res.3
 }
-; ARM: .long Ltmp0-(LPC{{.*}}+8)
-; THUMB: .long Ltmp0-(LPC{{.*}}+4)
+; ARM: .long Ltmp1-(LPC{{.*}}+8)
+; THUMB: .long Ltmp1-(LPC{{.*}}+4)
 ; THUMB: .long _nextaddr-([[NEXTADDR_PCBASE]]+4)
-; THUMB2: .long Ltmp0
+; THUMB2: .long Ltmp1
index a006bb6..9b7b41b 100644 (file)
@@ -23,8 +23,8 @@ define arm_aapcscc void @irq_fn() alignstack(8) "interrupt"="IRQ" {
 
 ; CHECK-A-THUMB-LABEL: irq_fn:
 ; CHECK-A-THUMB: push.w {r0, r1, r2, r3, r4, r7, r12, lr}
-; CHECK-A-THUMB: mov r4, sp
 ; CHECK-A-THUMB: add r7, sp, #20
+; CHECK-A-THUMB: mov r4, sp
 ; CHECK-A-THUMB: bic r4, r4, #7
 ; CHECK-A-THUMB: bl bar
 ; CHECK-A-THUMB: sub.w r4, r7,  #20