[llvm] r346568 - [ARM64] [Windows] Handle funclets

Eli Friedman via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 9 15:33:30 PST 2018


Author: efriedma
Date: Fri Nov  9 15:33:30 2018
New Revision: 346568

URL: http://llvm.org/viewvc/llvm-project?rev=346568&view=rev
Log:
[ARM64] [Windows] Handle funclets

This patch adds support for funclets in frame lowering and ISel
lowering. Together with D50288 and D50166, it enables C++ exception
handling.

Patch by Sanjin Sijaric, with some fixes by me.

Differential Revision: https://reviews.llvm.org/D51524


Added:
    llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-nobase.ll
    llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-realign.ll
    llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-vla.ll
    llvm/trunk/test/CodeGen/AArch64/wineh-try-catch.ll
Modified:
    llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp
    llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.h
    llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp
    llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp
    llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
    llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp
    llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp
    llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.h

Modified: llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.cpp Fri Nov  9 15:33:30 2018
@@ -204,6 +204,11 @@ bool AArch64FrameLowering::canUseRedZone
 bool AArch64FrameLowering::hasFP(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
   const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
+  // Win64 EH requires a frame pointer if funclets are present, as the locals
+  // are accessed off the frame pointer in both the parent function and the
+  // funclets.
+  if (MF.hasEHFunclets())
+    return true;
   // Retain behavior of always omitting the FP for leaf functions when possible.
   if (MFI.hasCalls() && MF.getTarget().Options.DisableFramePointerElim(MF))
     return true;
@@ -774,6 +779,12 @@ static bool ShouldSignWithAKey(MachineFu
   return Key.equals_lower("a_key");
 }
 
+static bool needsWinCFI(const MachineFunction &MF) {
+  const Function &F = MF.getFunction();
+  return MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
+         F.needsUnwindTableEntry();
+}
+
 void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
                                         MachineBasicBlock &MBB) const {
   MachineBasicBlock::iterator MBBI = MBB.begin();
@@ -787,9 +798,10 @@ void AArch64FrameLowering::emitPrologue(
   bool needsFrameMoves = (MMI.hasDebugInfo() || F.needsUnwindTableEntry()) &&
                          !MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
   bool HasFP = hasFP(MF);
-  bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
-                     F.needsUnwindTableEntry();
+  bool NeedsWinCFI = needsWinCFI(MF);
   MF.setHasWinCFI(NeedsWinCFI);
+  bool IsFunclet = MBB.isEHFuncletEntry();
+
   // At this point, we're going to decide whether or not the function uses a
   // redzone. In most cases, the function doesn't have a redzone so let's
   // assume that's false and set it to true in the case that there's a redzone.
@@ -811,7 +823,14 @@ void AArch64FrameLowering::emitPrologue(
   if (MF.getFunction().getCallingConv() == CallingConv::GHC)
     return;
 
-  int NumBytes = (int)MFI.getStackSize();
+  // getStackSize() includes all the locals in its size calculation. We don't
+  // include these locals when computing the stack size of a funclet, as they
+  // are allocated in the parent's stack frame and accessed via the frame
+  // pointer from the funclet.  We only save the callee saved registers in the
+  // funclet, which are really the callee saved registers of the parent
+  // function, including the funclet.
+  int NumBytes = IsFunclet ? (int)getWinEHFuncletFrameSize(MF)
+                           : (int)MFI.getStackSize();
   if (!AFI->hasStackFrame() && !windowsRequiresStackProbe(MF, NumBytes)) {
     assert(!HasFP && "unexpected function without stack frame but with FP");
     // All of the stack allocation is for locals.
@@ -847,7 +866,10 @@ void AArch64FrameLowering::emitPrologue(
 
   bool IsWin64 =
       Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
-  unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
+  // Var args are accounted for in the containing function, so don't
+  // include them for funclets.
+  unsigned FixedObject = (IsWin64 && !IsFunclet) ?
+                         alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
 
   auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
   // All of the remaining stack allocations are for locals.
@@ -875,6 +897,16 @@ void AArch64FrameLowering::emitPrologue(
     ++MBBI;
   }
 
+  // The code below is not applicable to funclets. We have emitted all the SEH
+  // opcodes that we needed to emit.  The FP and BP belong to the containing
+  // function.
+  if (IsFunclet) {
+    if (NeedsWinCFI)
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
+          .setMIFlag(MachineInstr::FrameSetup);
+    return;
+  }
+
   if (HasFP) {
     // Only set up FP if we actually need to. Frame pointer is fp =
     // sp - fixedobject - 16.
@@ -1165,6 +1197,16 @@ static void InsertReturnAddressAuth(Mach
   }
 }
 
+static bool isFuncletReturnInstr(const MachineInstr &MI) {
+  switch (MI.getOpcode()) {
+  default:
+    return false;
+  case AArch64::CATCHRET:
+  case AArch64::CLEANUPRET:
+    return true;
+  }
+}
+
 void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
                                         MachineBasicBlock &MBB) const {
   MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
@@ -1173,8 +1215,8 @@ void AArch64FrameLowering::emitEpilogue(
   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
   DebugLoc DL;
   bool IsTailCallReturn = false;
-  bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
-                     MF.getFunction().needsUnwindTableEntry();
+  bool NeedsWinCFI = needsWinCFI(MF);
+  bool IsFunclet = false;
 
   if (MBB.end() != MBBI) {
     DL = MBBI->getDebugLoc();
@@ -1182,9 +1224,11 @@ void AArch64FrameLowering::emitEpilogue(
     IsTailCallReturn = RetOpcode == AArch64::TCRETURNdi ||
                        RetOpcode == AArch64::TCRETURNri ||
                        RetOpcode == AArch64::TCRETURNriBTI;
+    IsFunclet = isFuncletReturnInstr(*MBBI);
   }
 
-  int NumBytes = MFI.getStackSize();
+  int NumBytes = IsFunclet ? (int)getWinEHFuncletFrameSize(MF)
+                           : MFI.getStackSize();
   AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
 
   // All calls are tail calls in GHC calling conv, and functions have no
@@ -1245,6 +1289,10 @@ void AArch64FrameLowering::emitEpilogue(
 
   uint64_t AfterCSRPopSize = ArgumentPopSize;
   auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
+  // Var args are accounted for in the containting function, so don't
+  // include them for funclets.
+  if (MF.hasEHFunclets())
+    AFI->setLocalStackSize(NumBytes - PrologueSaveSize);
   bool CombineSPBump = shouldCombineCSRLocalStackBump(MF, NumBytes);
   // Assume we can't combine the last pop with the sp restore.
 
@@ -1340,7 +1388,7 @@ void AArch64FrameLowering::emitEpilogue(
   // FIXME: Rather than doing the math here, we should instead just use
   // non-post-indexed loads for the restores if we aren't actually going to
   // be able to save any instructions.
-  if (MFI.hasVarSizedObjects() || AFI->isStackRealigned())
+  if (!IsFunclet && (MFI.hasVarSizedObjects() || AFI->isStackRealigned()))
     emitFrameOffset(MBB, LastPopI, DL, AArch64::SP, AArch64::FP,
                     -AFI->getCalleeSavedStackSize() + 16, TII,
                     MachineInstr::FrameDestroy, false, NeedsWinCFI);
@@ -1445,6 +1493,14 @@ int AArch64FrameLowering::resolveFrameIn
         // being in range for direct access. If the FPOffset is positive,
         // that'll always be best, as the SP will be even further away.
         UseFP = true;
+      } else if (MF.hasEHFunclets() && !RegInfo->hasBasePointer(MF)) {
+        // Funclets access the locals contained in the parent's stack frame
+        // via the frame pointer, so we have to use the FP in the parent
+        // function.
+        assert(
+            Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()) &&
+            "Funclets should only be present on Win64");
+        UseFP = true;
       } else {
         // We have the choice between FP and (SP or BP).
         if (FPOffsetFits && PreferFP) // If FP is the best fit, use it.
@@ -1538,8 +1594,7 @@ static void computeCalleeSaveRegisterPai
   if (CSI.empty())
     return;
 
-  bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
-                     MF.getFunction().needsUnwindTableEntry();
+  bool NeedsWinCFI = needsWinCFI(MF);
   AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
   MachineFrameInfo &MFI = MF.getFrameInfo();
   CallingConv::ID CC = MF.getFunction().getCallingConv();
@@ -1652,8 +1707,7 @@ bool AArch64FrameLowering::spillCalleeSa
     const TargetRegisterInfo *TRI) const {
   MachineFunction &MF = *MBB.getParent();
   const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
-  bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
-                     MF.getFunction().needsUnwindTableEntry();
+  bool NeedsWinCFI = needsWinCFI(MF);
   DebugLoc DL;
   SmallVector<RegPairInfo, 8> RegPairs;
 
@@ -1765,8 +1819,7 @@ bool AArch64FrameLowering::restoreCallee
   const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
   DebugLoc DL;
   SmallVector<RegPairInfo, 8> RegPairs;
-  bool NeedsWinCFI = MF.getTarget().getMCAsmInfo()->usesWindowsCFI() &&
-                     MF.getFunction().needsUnwindTableEntry();
+  bool NeedsWinCFI = needsWinCFI(MF);
 
   if (MI != MBB.end())
     DL = MI->getDebugLoc();
@@ -1998,3 +2051,69 @@ bool AArch64FrameLowering::enableStackSl
   const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
   return AFI->hasCalleeSaveStackFreeSpace();
 }
+
+void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
+    MachineFunction &MF, RegScavenger *RS) const {
+  // If this function isn't doing Win64-style C++ EH, we don't need to do
+  // anything.
+  if (!MF.hasEHFunclets())
+    return;
+  const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
+  MachineFrameInfo &MFI = MF.getFrameInfo();
+  WinEHFuncInfo &EHInfo = *MF.getWinEHFuncInfo();
+
+  MachineBasicBlock &MBB = MF.front();
+  auto MBBI = MBB.begin();
+  while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
+    ++MBBI;
+
+  if (MBBI->isTerminator())
+    return;
+
+  // Create an UnwindHelp object.
+  int UnwindHelpFI =
+      MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
+  EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
+  // We need to store -2 into the UnwindHelp object at the start of the
+  // function.
+  DebugLoc DL;
+  RS->enterBasicBlock(MBB);
+  unsigned DstReg = RS->scavengeRegister(&AArch64::GPR64RegClass, MBBI, 0);
+  BuildMI(MBB, MBBI, DL, TII.get(AArch64::MOVi64imm), DstReg).addImm(-2);
+  BuildMI(MBB, MBBI, DL, TII.get(AArch64::STURXi))
+      .addReg(DstReg, getKillRegState(true))
+      .addFrameIndex(UnwindHelpFI)
+      .addImm(0);
+}
+
+/// For Win64 AArch64 EH, the offset to the Unwind object is from the SP before
+/// the update.  This is easily retrieved as it is exactly the offset that is set
+/// in processFunctionBeforeFrameFinalized.
+int AArch64FrameLowering::getFrameIndexReferencePreferSP(
+    const MachineFunction &MF, int FI, unsigned &FrameReg,
+    bool IgnoreSPUpdates) const {
+  const MachineFrameInfo &MFI = MF.getFrameInfo();
+  LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
+                    << MFI.getObjectOffset(FI) << "\n");
+  FrameReg = AArch64::SP;
+  return MFI.getObjectOffset(FI);
+}
+
+/// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve
+/// the parent's frame pointer
+unsigned AArch64FrameLowering::getWinEHParentFrameOffset(
+    const MachineFunction &MF) const {
+  return 0;
+}
+
+/// Funclets only need to account for space for the callee saved registers,
+/// as the locals are accounted for in the parent's stack frame.
+unsigned AArch64FrameLowering::getWinEHFuncletFrameSize(
+    const MachineFunction &MF) const {
+  // This is the size of the pushed CSRs.
+  unsigned CSSize =
+      MF.getInfo<AArch64FunctionInfo>()->getCalleeSavedStackSize();
+  // This is the amount of stack a funclet needs to allocate.
+  return alignTo(CSSize + MF.getFrameInfo().getMaxCallFrameSize(),
+                 getStackAlignment());
+}

Modified: llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.h?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64FrameLowering.h Fri Nov  9 15:33:30 2018
@@ -69,6 +69,17 @@ public:
 
   bool enableStackSlotScavenging(const MachineFunction &MF) const override;
 
+  void processFunctionBeforeFrameFinalized(MachineFunction &MF,
+                                             RegScavenger *RS) const override;
+
+  unsigned getWinEHParentFrameOffset(const MachineFunction &MF) const override;
+
+  unsigned getWinEHFuncletFrameSize(const MachineFunction &MF) const;
+
+  int getFrameIndexReferencePreferSP(const MachineFunction &MF, int FI,
+                                     unsigned &FrameReg,
+                                     bool IgnoreSPUpdates) const override;
+
 private:
   bool shouldCombineCSRLocalStackBump(MachineFunction &MF,
                                       unsigned StackBumpBytes) const;

Modified: llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.cpp Fri Nov  9 15:33:30 2018
@@ -1273,6 +1273,20 @@ AArch64TargetLowering::EmitF128CSEL(Mach
   return EndBB;
 }
 
+MachineBasicBlock *AArch64TargetLowering::EmitLoweredCatchRet(
+       MachineInstr &MI, MachineBasicBlock *BB) const {
+  assert(!isAsynchronousEHPersonality(classifyEHPersonality(
+             BB->getParent()->getFunction().getPersonalityFn())) &&
+         "SEH does not use catchret!");
+  return BB;
+}
+
+MachineBasicBlock *AArch64TargetLowering::EmitLoweredCatchPad(
+     MachineInstr &MI, MachineBasicBlock *BB) const {
+  MI.eraseFromParent();
+  return BB;
+}
+
 MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
     MachineInstr &MI, MachineBasicBlock *BB) const {
   switch (MI.getOpcode()) {
@@ -1288,6 +1302,11 @@ MachineBasicBlock *AArch64TargetLowering
   case TargetOpcode::STACKMAP:
   case TargetOpcode::PATCHPOINT:
     return emitPatchPoint(MI, BB);
+
+  case AArch64::CATCHRET:
+    return EmitLoweredCatchRet(MI, BB);
+  case AArch64::CATCHPAD:
+    return EmitLoweredCatchPad(MI, BB);
   }
 }
 
@@ -11805,3 +11824,8 @@ void AArch64TargetLowering::finalizeLowe
   MF.getFrameInfo().computeMaxCallFrameSize(MF);
   TargetLoweringBase::finalizeLowering(MF);
 }
+
+// Unlike X86, we let frame lowering assign offsets to all catch objects.
+bool AArch64TargetLowering::needsFixedCatchObjects() const {
+  return false;
+}

Modified: llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64ISelLowering.h Fri Nov  9 15:33:30 2018
@@ -302,6 +302,12 @@ public:
   MachineBasicBlock *EmitF128CSEL(MachineInstr &MI,
                                   MachineBasicBlock *BB) const;
 
+  MachineBasicBlock *EmitLoweredCatchRet(MachineInstr &MI,
+                                           MachineBasicBlock *BB) const;
+
+  MachineBasicBlock *EmitLoweredCatchPad(MachineInstr &MI,
+                                         MachineBasicBlock *BB) const;
+
   MachineBasicBlock *
   EmitInstrWithCustomInserter(MachineInstr &MI,
                               MachineBasicBlock *MBB) const override;
@@ -521,6 +527,8 @@ public:
   bool functionArgumentNeedsConsecutiveRegisters(Type *Ty,
                                                  CallingConv::ID CallConv,
                                                  bool isVarArg) const override;
+  /// Used for exception handling on Win64.
+  bool needsFixedCatchObjects() const override;
 private:
   /// Keep a pointer to the AArch64Subtarget around so that we can
   /// make the right decision when generating code for different targets.

Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.cpp Fri Nov  9 15:33:30 2018
@@ -66,7 +66,8 @@ static cl::opt<unsigned>
                         cl::desc("Restrict range of Bcc instructions (DEBUG)"));
 
 AArch64InstrInfo::AArch64InstrInfo(const AArch64Subtarget &STI)
-    : AArch64GenInstrInfo(AArch64::ADJCALLSTACKDOWN, AArch64::ADJCALLSTACKUP),
+    : AArch64GenInstrInfo(AArch64::ADJCALLSTACKDOWN, AArch64::ADJCALLSTACKUP,
+                          AArch64::CATCHRET),
       RI(STI.getTargetTriple()), Subtarget(STI) {}
 
 /// GetInstSize - Return the number of bytes of code the specified
@@ -1657,11 +1658,36 @@ bool AArch64InstrInfo::substituteCmpToZe
 }
 
 bool AArch64InstrInfo::expandPostRAPseudo(MachineInstr &MI) const {
-  if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD)
+  if (MI.getOpcode() != TargetOpcode::LOAD_STACK_GUARD &&
+      MI.getOpcode() != AArch64::CATCHRET)
     return false;
 
   MachineBasicBlock &MBB = *MI.getParent();
   DebugLoc DL = MI.getDebugLoc();
+
+  if (MI.getOpcode() == AArch64::CATCHRET) {
+    // Skip to the first instruction before the epilog.
+    const TargetInstrInfo *TII =
+      MBB.getParent()->getSubtarget().getInstrInfo();
+    MachineBasicBlock *TargetMBB = MI.getOperand(0).getMBB();
+    auto MBBI = MachineBasicBlock::iterator(MI);
+    MachineBasicBlock::iterator FirstEpilogSEH = std::prev(MBBI);
+    while (FirstEpilogSEH->getFlag(MachineInstr::FrameDestroy) &&
+           FirstEpilogSEH != MBB.begin())
+      FirstEpilogSEH = std::prev(FirstEpilogSEH);
+    if (FirstEpilogSEH != MBB.begin())
+      FirstEpilogSEH = std::next(FirstEpilogSEH);
+    BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADRP))
+        .addReg(AArch64::X0, RegState::Define)
+        .addMBB(TargetMBB);
+    BuildMI(MBB, FirstEpilogSEH, DL, TII->get(AArch64::ADDXri))
+        .addReg(AArch64::X0, RegState::Define)
+        .addReg(AArch64::X0)
+        .addMBB(TargetMBB)
+        .addImm(0);
+    return true;
+  }
+
   unsigned Reg = MI.getOperand(0).getReg();
   const GlobalValue *GV =
       cast<GlobalValue>((*MI.memoperands_begin())->getValue());

Modified: llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64InstrInfo.td Fri Nov  9 15:33:30 2018
@@ -3175,6 +3175,20 @@ let isPseudo = 1 in {
   def SEH_EpilogEnd : Pseudo<(outs), (ins), []>, Sched<[]>;
 }
 
+// Pseudo instructions for Windows EH
+//===----------------------------------------------------------------------===//
+let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
+    isCodeGenOnly = 1, isReturn = 1, isEHScopeReturn = 1, isPseudo = 1 in {
+   def CLEANUPRET : Pseudo<(outs), (ins), [(cleanupret)]>, Sched<[]>;
+   let usesCustomInserter = 1 in
+     def CATCHRET : Pseudo<(outs), (ins am_brcond:$dst, am_brcond:$src), [(catchret bb:$dst, bb:$src)]>,
+                    Sched<[]>;
+}
+
+let hasSideEffects = 1, hasCtrlDep = 1, isCodeGenOnly = 1,
+    usesCustomInserter = 1 in
+def CATCHPAD : Pseudo<(outs), (ins), [(catchpad)]>, Sched<[]>;
+
 //===----------------------------------------------------------------------===//
 // Floating point immediate move.
 //===----------------------------------------------------------------------===//

Modified: llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64MCInstLower.cpp Fri Nov  9 15:33:30 2018
@@ -269,4 +269,17 @@ void AArch64MCInstLower::Lower(const Mac
     if (lowerOperand(MO, MCOp))
       OutMI.addOperand(MCOp);
   }
+
+  switch (OutMI.getOpcode()) {
+  case AArch64::CATCHRET:
+    OutMI = MCInst();
+    OutMI.setOpcode(AArch64::RET);
+    OutMI.addOperand(MCOperand::createReg(AArch64::LR));
+    break;
+  case AArch64::CLEANUPRET:
+    OutMI = MCInst();
+    OutMI.setOpcode(AArch64::RET);
+    OutMI.addOperand(MCOperand::createReg(AArch64::LR));
+    break;
+  }
 }

Modified: llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.cpp Fri Nov  9 15:33:30 2018
@@ -161,6 +161,10 @@ void AArch64RegisterInfo::UpdateCustomCa
   *Mask = UpdatedMask;
 }
 
+const uint32_t *AArch64RegisterInfo::getNoPreservedMask() const {
+  return CSR_AArch64_NoRegs_RegMask;
+}
+
 const uint32_t *
 AArch64RegisterInfo::getThisReturnPreservedMask(const MachineFunction &MF,
                                                 CallingConv::ID CC) const {
@@ -251,14 +255,15 @@ unsigned AArch64RegisterInfo::getBaseReg
 bool AArch64RegisterInfo::hasBasePointer(const MachineFunction &MF) const {
   const MachineFrameInfo &MFI = MF.getFrameInfo();
 
-  // In the presence of variable sized objects, if the fixed stack size is
-  // large enough that referencing from the FP won't result in things being
-  // in range relatively often, we can use a base pointer to allow access
+  // In the presence of variable sized objects or funclets, if the fixed stack
+  // size is large enough that referencing from the FP won't result in things
+  // being in range relatively often, we can use a base pointer to allow access
   // from the other direction like the SP normally works.
+  //
   // Furthermore, if both variable sized objects are present, and the
   // stack needs to be dynamically re-aligned, the base pointer is the only
   // reliable way to reference the locals.
-  if (MFI.hasVarSizedObjects()) {
+  if (MFI.hasVarSizedObjects() || MF.hasEHFunclets()) {
     if (needsStackRealignment(MF))
       return true;
     // Conservatively estimate whether the negative offset from the frame

Modified: llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.h?rev=346568&r1=346567&r2=346568&view=diff
==============================================================================
--- llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.h (original)
+++ llvm/trunk/lib/Target/AArch64/AArch64RegisterInfo.h Fri Nov  9 15:33:30 2018
@@ -65,6 +65,9 @@ public:
   // normal calls, so they need a different mask to represent this.
   const uint32_t *getTLSCallPreservedMask() const;
 
+  // Funclets on ARM64 Windows don't preserve any registers.
+  const uint32_t *getNoPreservedMask() const override;
+
   /// getThisReturnPreservedMask - Returns a call preserved mask specific to the
   /// case that 'returned' is on an i64 first argument if the calling convention
   /// is one that can (partially) model this attribute with a preserved mask

Added: llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-nobase.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-nobase.ll?rev=346568&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-nobase.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-nobase.ll Fri Nov  9 15:33:30 2018
@@ -0,0 +1,49 @@
+; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
+
+; Make sure we don't have a base pointer.
+; CHECK-LABEL: "?a@@YAXXZ":
+; CHECK-NOT: x19
+
+; Check that we compute the address relative to fp.
+; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ at 4HA":
+; CHECK:             stp     x29, x30, [sp, #-16]!   ; 16-byte Folded Spill
+; CHECK-NEXT:        sub     x0, x29, #16            ; =16
+; CHECK-NEXT:        mov     x1, xzr
+; CHECK-NEXT:        bl      "?bb@@YAXPEAHH at Z"
+; CHECK-NEXT:        adrp    x0, .LBB0_1
+; CHECK-NEXT:        add     x0, x0, .LBB0_1
+; CHECK-NEXT:        ldp     x29, x30, [sp], #16     ; 16-byte Folded Reload
+; CHECK-NEXT:        ret
+
+target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-windows-msvc19.11.0"
+
+define dso_local void @"?a@@YAXXZ"(i64 %p1) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %a = alloca i32, align 16
+  %0 = bitcast i32* %a to i8*  
+  store i32 305419896, i32* %a, align 16
+  invoke void @"?bb@@YAXPEAHH at Z"(i32* nonnull %a, i32* null)
+          to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %entry
+  %1 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %2 = catchpad within %1 [i8* null, i32 64, i8* null]
+  call void @"?bb@@YAXPEAHH at Z"(i32* nonnull %a, i32* null) [ "funclet"(token %2) ]
+  catchret from %2 to label %try.cont
+
+try.cont:                                         ; preds = %entry, %catch
+  call void @"?cc@@YAXXZ"()
+  ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
+
+declare dso_local void @"?bb@@YAXPEAHH at Z"(i32*, i32*)
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+declare dso_local void @"?cc@@YAXXZ"()
+

Added: llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-realign.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-realign.ll?rev=346568&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-realign.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-realign.ll Fri Nov  9 15:33:30 2018
@@ -0,0 +1,59 @@
+; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
+
+; Make sure we have a base pointer.
+; CHECK-LABEL: "?a@@YAXXZ":
+; CHECK: and     sp, x9, #0xffffffffffffffc0
+; CHECK: mov     x19, sp
+
+; Make sure the funclet prologue/epilogue are correct: specifically,
+; it shouldn't access the parent's frame via sp, and the prologue and
+; epilogue should be symmetrical.
+; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ at 4HA":
+; CHECK:      str     x28, [sp, #-32]!
+; CHECK-NEXT: str     x19, [sp, #8]
+; CHECK-NEXT: stp     x29, x30, [sp, #16]
+; CHECK-NEXT: add     x0, x19, #64
+; CHECK-NEXT: mov     w1, wzr
+; CHECK-NEXT: bl      "?bb@@YAXPEAHH at Z"
+; CHECK-NEXT: adrp    x0, .LBB0_1
+; CHECK-NEXT: add     x0, x0, .LBB0_1
+; CHECK-NEXT: ldp     x29, x30, [sp, #16]
+; CHECK-NEXT: ldr     x19, [sp, #8]
+; CHECK-NEXT: ldr     x28, [sp], #32
+; CHECK-NEXT: ret
+
+
+target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-windows-msvc19.11.0"
+
+define dso_local void @"?a@@YAXXZ"() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %a = alloca [100 x i32], align 64
+  %0 = bitcast [100 x i32]* %a to i8*  
+  call void @llvm.memset.p0i8.i64(i8* nonnull align 64 %0, i8 0, i64 400, i1 false)
+  %1 = getelementptr inbounds [100 x i32], [100 x i32]* %a, i64 0, i64 0
+  store i32 305419896, i32* %1, align 64
+  invoke void @"?bb@@YAXPEAHH at Z"(i32* nonnull %1, i32 1)
+          to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %entry
+  %2 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %3 = catchpad within %2 [i8* null, i32 64, i8* null]
+  call void @"?bb@@YAXPEAHH at Z"(i32* nonnull %1, i32 0) [ "funclet"(token %3) ]
+  catchret from %3 to label %try.cont
+
+try.cont:                                         ; preds = %entry, %catch
+  call void @"?cc@@YAXXZ"()
+  ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
+
+declare dso_local void @"?bb@@YAXPEAHH at Z"(i32*, i32)
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+declare dso_local void @"?cc@@YAXXZ"()
+

Added: llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-vla.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-vla.ll?rev=346568&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-vla.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/wineh-try-catch-vla.ll Fri Nov  9 15:33:30 2018
@@ -0,0 +1,52 @@
+; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
+
+; Check we don't have a base pointer.
+; CHECK-LABEL: "?a@@YAXXZ":
+; CHECK-NOT: x19
+
+; Make sure the prologue and epilogue are sane. Make sure the
+; frame index is relative to the FP, since there is no base pointer.
+; (Funclets aren't allowed to contain dynamic allocas.)
+; CHECK-LABEL: "?catch$2@?0??a@@YAXXZ at 4HA":
+; CHECK:      stp     x29, x30, [sp, #-16]!
+; CHECK-NEXT: ldur    x0, [x29, #-8]
+; CHECK-NEXT: mov     x1, x0
+; CHECK-NEXT: bl      "?bb@@YAXPEAHH at Z"
+; CHECK-NEXT: adrp    x0, .LBB0_1
+; CHECK-NEXT: add     x0, x0, .LBB0_1
+; CHECK-NEXT: ldp     x29, x30, [sp], #16
+; CHECK-NEXT: ret
+
+target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-windows-msvc19.11.0"
+
+define dso_local void @"?a@@YAXXZ"(i64 %p1) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %a = alloca i32, i64 %p1, align 16
+  %0 = bitcast i32* %a to i8*  
+  call void @llvm.memset.p0i8.i64(i8* nonnull align 16 %0, i8 0, i64 400, i1 false)
+  store i32 305419896, i32* %a, align 16
+  invoke void @"?bb@@YAXPEAHH at Z"(i32* nonnull %a, i32* null)
+          to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %entry
+  %1 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %2 = catchpad within %1 [i8* null, i32 64, i8* null]
+  call void @"?bb@@YAXPEAHH at Z"(i32* nonnull %a, i32* %a) [ "funclet"(token %2) ]
+  catchret from %2 to label %try.cont
+
+try.cont:                                         ; preds = %entry, %catch
+  call void @"?cc@@YAXXZ"()
+  ret void
+}
+
+declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1)
+
+declare dso_local void @"?bb@@YAXPEAHH at Z"(i32*, i32*)
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+declare dso_local void @"?cc@@YAXXZ"()
+

Added: llvm/trunk/test/CodeGen/AArch64/wineh-try-catch.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AArch64/wineh-try-catch.ll?rev=346568&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/AArch64/wineh-try-catch.ll (added)
+++ llvm/trunk/test/CodeGen/AArch64/wineh-try-catch.ll Fri Nov  9 15:33:30 2018
@@ -0,0 +1,197 @@
+; RUN: llc -o - %s -mtriple=aarch64-windows -verify-machineinstrs | FileCheck %s
+; RUN: llc -o %t -filetype=obj %s -mtriple=aarch64-windows
+; RUN: llvm-readobj -unwind %t | FileCheck %s -check-prefix=UNWIND
+
+; We test the following
+; 1) That the unwind help object is created and that its offset from the stack
+;    pointer on entry is patched into the table fed to __CxxFrameHandler3
+; 2) That the stack update for the catch funclet only includes the callee saved
+;    registers
+; 3) That the locals are accessed using the frame pointer in both the funclet
+;    and the parent function.
+
+; The following checks that the unwind help object has -2 stored into it at
+; fp - 400 - 256 = fp - 656, which is on-entry sp - 48 + 32 - 656 =
+; on-entry sp - 672.  We check this offset in the table later on.
+
+; CHECK-LABEL: "?func@@YAHXZ":
+; CHECK:       str     x28, [sp, #-48]!
+; CHECK:       str     x21, [sp, #8]
+; CHECK:       stp     x19, x20, [sp, #16]
+; CHECK:       stp     x29, x30, [sp, #32]
+; CHECK:       add     x29, sp, #32
+; CHECK:       sub     sp, sp, #624
+; CHECK:       mov     x19, sp
+; CHECK:       orr     x1, xzr, #0xfffffffffffffffe
+; CHECK:       stur    x1, [x19]
+
+; Now check that x is stored at fp - 20.  We check that this is the same
+; location accessed from the funclet to retrieve x.
+; CHECK:       orr     w8, wzr, #0x1
+; CHECK:       stur    w8, [x29, [[X_OFFSET:#-[1-9][0-9]+]]
+
+; Check the offset off the frame pointer at which B is located.
+; Check the same offset is used to pass the address of B to init2 in the
+; funclet.
+; CHECK:       sub     x0, x29, [[B_OFFSET:#[1-9][0-9]+]]
+; CHECK:       bl      "?init@@YAXPEAH at Z"
+
+; This is the label for the throw that is encoded in the ip2state.
+; We are inside the try block, where we make a call to func2
+; CHECK-LABEL: .Ltmp0:
+; CHECK:       bl      "?func2@@YAHXZ
+
+; CHECK:        [[CATCHRETDEST:.LBB0_[0-9]+]]:      ; %catchret.dest
+
+; Check the catch funclet.
+; CHECK-LABEL: "?catch$2@?0??func@@YAHXZ at 4HA":
+
+; Check that the stack space is allocated only for the callee saved registers.
+; CHECK:       str     x28, [sp, #-48]!
+; CHECK:       str     x21, [sp, #8]
+; CHECK:       stp     x19, x20, [sp, #16]
+; CHECK:       stp     x29, x30, [sp, #32]
+; CHECK:       add     x20, x19, #12
+
+; Check that there are no further stack updates.
+; CHECK-NOT:   sub     sp, sp
+
+; Check that the stack address passed to init2 is off the frame pointer, and
+; that it matches the address of B in the parent function.
+; CHECK:       sub     x0, x29, [[B_OFFSET]]
+; CHECK:       bl      "?init2@@YAXPEAH at Z"
+
+; Check that are storing x back to the same location off the frame pointer as in
+; the parent function.
+; CHECK:       stur    w8, [x29, [[X_OFFSET]]]
+
+; Check that the funclet branches back to the catchret destination
+; CHECK:       adrp    x0, .LBB0_3
+; CHECK-NEXT:  add     x0, x0, [[CATCHRETDEST]]
+
+
+; Now check that the offset of the unwind help object from the stack pointer on
+; entry to func is encoded in cppxdata that is passed to __CxxFrameHandler3.  As
+; computed above, this comes to -672.
+; CHECK-LABEL:        "$cppxdata$?func@@YAHXZ":
+; CHECK-NEXT:         .word   429065506               ; MagicNumber
+; CHECK-NEXT:         .word   2                       ; MaxState
+; CHECK-NEXT:         .word   ("$stateUnwindMap$?func@@YAHXZ")@IMGREL ; UnwindMap
+; CHECK-NEXT:         .word   1                       ; NumTryBlocks
+; CHECK-NEXT:         .word   ("$tryMap$?func@@YAHXZ")@IMGREL ; TryBlockMap
+; CHECK-NEXT:         .word   4                       ; IPMapEntries
+; CHECK-NEXT:         .word   ("$ip2state$?func@@YAHXZ")@IMGREL ; IPToStateXData
+; CHECK-NEXT:         .word   -672                    ; UnwindHelp
+
+; UNWIND: Function: ?func@@YAHXZ (0x0)
+; UNWIND: Prologue [
+; UNWIND-NEXT: ; nop
+; UNWIND-NEXT: ; sub sp, #624
+; UNWIND-NEXT: ; add fp, sp, #32
+; UNWIND-NEXT: ; stp x29, x30, [sp, #32]
+; UNWIND-NEXT: ; stp x19, x20, [sp, #16]
+; UNWIND-NEXT: ; str x21, [sp, #8]
+; UNWIND-NEXT: ; str x28, [sp, #48]!
+; UNWIND-NEXT: ; end
+; UNWIND: Function: ?catch$2@?0??func@@YAHXZ at 4HA
+; UNWIND: Prologue [
+; UNWIND-NEXT: ; stp x29, x30, [sp, #32]
+; UNWIND-NEXT: ; stp x19, x20, [sp, #16]
+; UNWIND-NEXT: ; str x21, [sp, #8]
+; UNWIND-NEXT: ; str x28, [sp, #48]!
+; UNWIND-NEXT: ; end
+
+target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
+target triple = "aarch64-unknown-windows-msvc19.11.0"
+
+%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
+%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
+%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
+%eh.ThrowInfo = type { i32, i32, i32, i32 }
+
+$"??_R0H at 8" = comdat any
+
+$"_CT??_R0H at 84" = comdat any
+
+$_CTA1H = comdat any
+
+$_TI1H = comdat any
+
+@"??_7type_info@@6B@" = external constant i8*
+@"??_R0H at 8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
+ at __ImageBase = external dso_local constant i8
+@"_CT??_R0H at 84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H at 8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
+ at _CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H at 84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
+ at _TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
+
+; Function Attrs: noinline optnone
+define dso_local i32 @"?func@@YAHXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %B = alloca [50 x i32], align 4
+  %x = alloca i32, align 4
+  %tmp = alloca i32, align 4
+  %i = alloca i32, align 4
+  %C = alloca [100 x i32], align 4
+  store i32 1, i32* %x, align 4
+  %arraydecay = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 0, i32 0
+  call void @"?init@@YAXPEAH at Z"(i32* %arraydecay)
+  %call = invoke i32 @"?func2@@YAHXZ"()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %entry
+  store i32 %call, i32* %tmp, align 4
+  %0 = bitcast i32* %tmp to i8*
+  invoke void @_CxxThrowException(i8* %0, %eh.ThrowInfo* @_TI1H) #2
+          to label %unreachable unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont, %entry
+  %1 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %2 = catchpad within %1 [%rtti.TypeDescriptor2* @"??_R0H at 8", i32 0, i32* %i]
+  %arraydecay1 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i32 0, i32 0
+  call void @"?init@@YAXPEAH at Z"(i32* %arraydecay1) [ "funclet"(token %2) ]
+  %arraydecay2 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 0, i32 0
+  call void @"?init2@@YAXPEAH at Z"(i32* %arraydecay2) [ "funclet"(token %2) ]
+  %3 = load i32, i32* %i, align 4
+  %idxprom = sext i32 %3 to i64
+  %arrayidx = getelementptr inbounds [50 x i32], [50 x i32]* %B, i64 0, i64 %idxprom
+  %4 = load i32, i32* %arrayidx, align 4
+  %5 = load i32, i32* %i, align 4
+  %idxprom3 = sext i32 %5 to i64
+  %arrayidx4 = getelementptr inbounds [100 x i32], [100 x i32]* %C, i64 0, i64 %idxprom3
+  %6 = load i32, i32* %arrayidx4, align 4
+  %add = add nsw i32 %4, %6
+  %7 = load i32, i32* %i, align 4
+  %8 = load i32, i32* %i, align 4
+  %mul = mul nsw i32 %7, %8
+  %add5 = add nsw i32 %add, %mul
+  store i32 %add5, i32* %x, align 4
+  catchret from %2 to label %catchret.dest
+
+catchret.dest:                                    ; preds = %catch
+  br label %try.cont
+
+try.cont:                                         ; preds = %catchret.dest
+  %arrayidx6 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i64 0, i64 2
+  %9 = load i32, i32* %arrayidx6, align 4
+  %10 = load i32, i32* %x, align 4
+  %add7 = add nsw i32 %9, %10
+  ret i32 %add7
+
+unreachable:                                      ; preds = %invoke.cont
+  unreachable
+}
+
+declare dso_local void @"?init@@YAXPEAH at Z"(i32*)
+
+declare dso_local i32 @"?func2@@YAHXZ"()
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+declare dllimport void @_CxxThrowException(i8*, %eh.ThrowInfo*)
+
+declare dso_local void @"?init2@@YAXPEAH at Z"(i32*)
+
+attributes #0 = { noinline optnone }
+attributes #2 = { noreturn }




More information about the llvm-commits mailing list