Replace llvm.frameallocate with llvm.frameescape

Turns out it's pretty straightforward and simplifies the implementation.

Reviewers: andrew.w.kaylor

Differential Revision: http://reviews.llvm.org/D8051

llvm-svn: 231386
diff --git a/llvm/lib/CodeGen/PrologEpilogInserter.cpp b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
index 6d29b98..e75cb03 100644
--- a/llvm/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/llvm/lib/CodeGen/PrologEpilogInserter.cpp
@@ -810,17 +810,6 @@
         continue;
       }
 
-      // Frame allocations are target independent. Simply swap the index with
-      // the offset.
-      if (MI->getOpcode() == TargetOpcode::FRAME_ALLOC) {
-        assert(TFI->hasFP(Fn) && "frame alloc requires FP");
-        MachineOperand &FI = MI->getOperand(i);
-        unsigned Reg;
-        int FrameOffset = TFI->getFrameIndexReference(Fn, FI.getIndex(), Reg);
-        FI.ChangeToImmediate(FrameOffset);
-        continue;
-      }
-
       // Some instructions (e.g. inline asm instructions) can have
       // multiple frame indices and/or cause eliminateFrameIndex
       // to insert more than one instruction. We need the register
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 097b618..c5bd2ab 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5618,45 +5618,47 @@
   case Intrinsic::instrprof_increment:
     llvm_unreachable("instrprof failed to lower an increment");
 
-  case Intrinsic::frameallocate: {
+  case Intrinsic::frameescape: {
     MachineFunction &MF = DAG.getMachineFunction();
     const TargetInstrInfo *TII = DAG.getSubtarget().getInstrInfo();
 
-    // Do the allocation and map it as a normal value.
-    // FIXME: Maybe we should add this to the alloca map so that we don't have
-    // to register allocate it?
-    uint64_t Size = cast<ConstantInt>(I.getArgOperand(0))->getZExtValue();
-    int Alloc = MF.getFrameInfo()->CreateFrameAllocation(Size);
-    MVT PtrVT = TLI.getPointerTy(0);
-    SDValue FIVal = DAG.getFrameIndex(Alloc, PtrVT);
-    setValue(&I, FIVal);
-
-    // Directly emit a FRAME_ALLOC machine instr. Label assignment emission is
-    // the same on all targets.
-    MCSymbol *FrameAllocSym =
-        MF.getMMI().getContext().getOrCreateFrameAllocSymbol(MF.getName());
-    BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, dl,
-            TII->get(TargetOpcode::FRAME_ALLOC))
-        .addSym(FrameAllocSym)
-        .addFrameIndex(Alloc);
+    // Directly emit some FRAME_ALLOC machine instrs. Label assignment emission
+    // is the same on all targets.
+    for (unsigned Idx = 0, E = I.getNumArgOperands(); Idx < E; ++Idx) {
+      AllocaInst *Slot =
+          cast<AllocaInst>(I.getArgOperand(Idx)->stripPointerCasts());
+      assert(FuncInfo.StaticAllocaMap.count(Slot) &&
+             "can only escape static allocas");
+      int FI = FuncInfo.StaticAllocaMap[Slot];
+      MCSymbol *FrameAllocSym =
+          MF.getMMI().getContext().getOrCreateFrameAllocSymbol(MF.getName(),
+                                                               Idx);
+      BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, dl,
+              TII->get(TargetOpcode::FRAME_ALLOC))
+          .addSym(FrameAllocSym)
+          .addFrameIndex(FI);
+    }
 
     return nullptr;
   }
 
   case Intrinsic::framerecover: {
-    // i8* @llvm.framerecover(i8* %fn, i8* %fp)
+    // i8* @llvm.framerecover(i8* %fn, i8* %fp, i32 %idx)
     MachineFunction &MF = DAG.getMachineFunction();
     MVT PtrVT = TLI.getPointerTy(0);
 
     // Get the symbol that defines the frame offset.
-    Function *Fn = cast<Function>(I.getArgOperand(0)->stripPointerCasts());
+    auto *Fn = cast<Function>(I.getArgOperand(0)->stripPointerCasts());
+    auto *Idx = cast<ConstantInt>(I.getArgOperand(2));
+    unsigned IdxVal = unsigned(Idx->getLimitedValue(INT_MAX));
     MCSymbol *FrameAllocSym =
-        MF.getMMI().getContext().getOrCreateFrameAllocSymbol(Fn->getName());
+        MF.getMMI().getContext().getOrCreateFrameAllocSymbol(Fn->getName(),
+                                                             IdxVal);
 
     // Create a TargetExternalSymbol for the label to avoid any target lowering
     // that would make this PC relative.
     StringRef Name = FrameAllocSym->getName();
-    assert(Name.size() == strlen(Name.data()) && "not null terminated");
+    assert(Name.data()[Name.size()] == '\0' && "not null terminated");
     SDValue OffsetSym = DAG.getTargetExternalSymbol(Name.data(), PtrVT);
     SDValue OffsetVal =
         DAG.getNode(ISD::FRAME_ALLOC_RECOVER, sdl, PtrVT, OffsetSym);
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index 5a13e55..eefb278 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -36,17 +36,12 @@
 
 namespace {
 
-struct HandlerAllocas {
-  TinyPtrVector<AllocaInst *> Allocas;
-  int ParentFrameAllocationIndex;
-};
-
 // This map is used to model frame variable usage during outlining, to
 // construct a structure type to hold the frame variables in a frame
 // allocation block, and to remap the frame variable allocas (including
 // spill locations as needed) to GEPs that get the variable from the
 // frame allocation structure.
-typedef MapVector<Value *, HandlerAllocas> FrameVarInfoMap;
+typedef MapVector<Value *, TinyPtrVector<AllocaInst *>> FrameVarInfoMap;
 
 class WinEHPrepare : public FunctionPass {
   std::unique_ptr<FunctionPass> DwarfPrepare;
@@ -73,7 +68,7 @@
                             SmallVectorImpl<LandingPadInst *> &LPads);
   bool outlineHandler(HandlerType CatchOrCleanup, Function *SrcFn,
                       Constant *SelectorType, LandingPadInst *LPad,
-                      CallInst *&EHAlloc, FrameVarInfoMap &VarInfo);
+                      FrameVarInfoMap &VarInfo);
 };
 
 class WinEHFrameVariableMaterializer : public ValueMaterializer {
@@ -236,7 +231,6 @@
   // outlined catch and cleanup handlers.  They will be populated as the
   // handlers are outlined.
   FrameVarInfoMap FrameVarInfo;
-  SmallVector<CallInst *, 4> HandlerAllocs;
 
   bool HandlersOutlined = false;
 
@@ -263,15 +257,10 @@
       if (LPad->isCatch(Idx)) {
         // Create a new instance of the handler data structure in the
         // HandlerData vector.
-        CallInst *EHAlloc = nullptr;
         bool Outlined = outlineHandler(Catch, &F, LPad->getClause(Idx), LPad,
-                                       EHAlloc, FrameVarInfo);
+                                       FrameVarInfo);
         if (Outlined) {
           HandlersOutlined = true;
-          // These values must be resolved after all handlers have been
-          // outlined.
-          if (EHAlloc)
-            HandlerAllocs.push_back(EHAlloc);
         }
       } // End if (isCatch)
     }   // End for each clause
@@ -283,14 +272,10 @@
     //        multiple landing pads.  Those cases will be supported later
     //        when landing pad block analysis is added.
     if (LPad->isCleanup()) {
-      CallInst *EHAlloc = nullptr;
       bool Outlined =
-          outlineHandler(Cleanup, &F, nullptr, LPad, EHAlloc, FrameVarInfo);
+          outlineHandler(Cleanup, &F, nullptr, LPad, FrameVarInfo);
       if (Outlined) {
         HandlersOutlined = true;
-        // This value must be resolved after all handlers have been outlined.
-        if (EHAlloc)
-          HandlerAllocs.push_back(EHAlloc);
       }
     }
   } // End for each landingpad
@@ -306,103 +291,27 @@
   //        that looks for allocas with no uses in the parent function.
   //        That will only happen after the pruning is implemented.
 
-  // Remap the frame variables.
-  SmallVector<Type *, 2> StructTys;
-  StructTys.push_back(Type::getInt32Ty(F.getContext()));   // EH state
-  StructTys.push_back(Type::getInt8PtrTy(F.getContext())); // EH object
-
-  // Start the index at two since we always have the above fields at 0 and 1.
-  int Idx = 2;
-
-  // FIXME: Sort the FrameVarInfo vector by the ParentAlloca size and alignment
-  //        and add padding as necessary to provide the proper alignment.
-
-  // Map the alloca instructions to the corresponding index in the
-  // frame allocation structure.  If any alloca is used only in a single
-  // handler and is not used in the parent frame after outlining, it will
-  // be assigned an index of -1, meaning the handler can keep its
-  // "temporary" alloca and the original alloca can be erased from the
-  // parent function.  If we later encounter this alloca in a second
-  // handler, we will assign it a place in the frame allocation structure
-  // at that time.  Since the instruction replacement doesn't happen until
-  // all the entries in the HandlerData have been processed this isn't a
-  // problem.
-  for (auto &VarInfoEntry : FrameVarInfo) {
-    Value *ParentVal = VarInfoEntry.first;
-    HandlerAllocas &AllocaInfo = VarInfoEntry.second;
-
-    if (auto *ParentAlloca = dyn_cast<AllocaInst>(ParentVal)) {
-      // If the instruction still has uses in the parent function or if it is
-      // referenced by more than one handler, add it to the frame allocation
-      // structure.
-      if (ParentAlloca->getNumUses() != 0 || AllocaInfo.Allocas.size() > 1) {
-        Type *VarTy = ParentAlloca->getAllocatedType();
-        StructTys.push_back(VarTy);
-        AllocaInfo.ParentFrameAllocationIndex = Idx++;
-      } else {
-        // If the variable is not used in the parent frame and it is only used
-        // in one handler, the alloca can be removed from the parent frame
-        // and the handler will keep its "temporary" alloca to define the value.
-        // An element index of -1 is used to indicate this condition.
-        AllocaInfo.ParentFrameAllocationIndex = -1;
-      }
-    } else {
-      // FIXME: Sink non-alloca values into the handler if they have no other
-      //        uses in the parent function after outlining and are only used in
-      //        one handler.
-      Type *VarTy = ParentVal->getType();
-      StructTys.push_back(VarTy);
-      AllocaInfo.ParentFrameAllocationIndex = Idx++;
-    }
-  }
-
-  // Having filled the StructTys vector and assigned an index to each element,
-  // we can now create the structure.
-  StructType *EHDataStructTy = StructType::create(
-      F.getContext(), StructTys, "struct." + F.getName().str() + ".ehdata");
-  IRBuilder<> Builder(F.getParent()->getContext());
-
-  // Create a frame allocation.
   Module *M = F.getParent();
   LLVMContext &Context = M->getContext();
   BasicBlock *Entry = &F.getEntryBlock();
+  IRBuilder<> Builder(F.getParent()->getContext());
   Builder.SetInsertPoint(Entry->getFirstInsertionPt());
-  Function *FrameAllocFn =
-      Intrinsic::getDeclaration(M, Intrinsic::frameallocate);
-  uint64_t EHAllocSize = M->getDataLayout().getTypeAllocSize(EHDataStructTy);
-  Value *FrameAllocArgs[] = {
-      ConstantInt::get(Type::getInt32Ty(Context), EHAllocSize)};
-  CallInst *FrameAlloc =
-      Builder.CreateCall(FrameAllocFn, FrameAllocArgs, "frame.alloc");
 
-  Value *FrameEHData = Builder.CreateBitCast(
-      FrameAlloc, EHDataStructTy->getPointerTo(), "eh.data");
-
-  // Now visit each handler that is using the structure and bitcast its EHAlloc
-  // value to be a pointer to the frame alloc structure.
-  DenseMap<Function *, Value *> EHDataMap;
-  for (CallInst *EHAlloc : HandlerAllocs) {
-    // The EHAlloc has no uses at this time, so we need to just insert the
-    // cast before the next instruction. There is always a next instruction.
-    BasicBlock::iterator II = EHAlloc;
-    ++II;
-    Builder.SetInsertPoint(cast<Instruction>(II));
-    Value *EHData = Builder.CreateBitCast(
-        EHAlloc, EHDataStructTy->getPointerTo(), "eh.data");
-    EHDataMap[EHAlloc->getParent()->getParent()] = EHData;
-  }
+  Function *FrameEscapeFn =
+      Intrinsic::getDeclaration(M, Intrinsic::frameescape);
+  Function *RecoverFrameFn =
+      Intrinsic::getDeclaration(M, Intrinsic::framerecover);
+  Type *Int8PtrType = Type::getInt8PtrTy(Context);
+  Type *Int32Type = Type::getInt32Ty(Context);
 
   // Finally, replace all of the temporary allocas for frame variables used in
-  // the outlined handlers and the original frame allocas with GEP instructions
-  // that get the equivalent pointer from the frame allocation struct.
-  Instruction *FrameEHDataInst = cast<Instruction>(FrameEHData);
-  BasicBlock::iterator II = FrameEHDataInst;
-  ++II;
+  // the outlined handlers with calls to llvm.framerecover.
+  BasicBlock::iterator II = Entry->getFirstInsertionPt();
   Instruction *AllocaInsertPt = II;
+  SmallVector<Value *, 8> AllocasToEscape;
   for (auto &VarInfoEntry : FrameVarInfo) {
     Value *ParentVal = VarInfoEntry.first;
-    HandlerAllocas &AllocaInfo = VarInfoEntry.second;
-    int Idx = AllocaInfo.ParentFrameAllocationIndex;
+    TinyPtrVector<AllocaInst *> &Allocas = VarInfoEntry.second;
 
     // If the mapped value isn't already an alloca, we need to spill it if it
     // is a computed value or copy it if it is an argument.
@@ -430,48 +339,51 @@
       }
     }
 
-    // If we have an index of -1 for this instruction, it means it isn't used
-    // outside of this handler.  In that case, we just keep the "temporary"
-    // alloca in the handler and erase the original alloca from the parent.
-    if (Idx == -1) {
+    // If the parent alloca is no longer used and only one of the handlers used
+    // it, erase the parent and leave the copy in the outlined handler.
+    if (ParentAlloca->getNumUses() == 0 && Allocas.size() == 1) {
       ParentAlloca->eraseFromParent();
-    } else {
-      // Otherwise, we replace the parent alloca and all outlined allocas
-      // which map to it with GEP instructions.
+      continue;
+    }
 
-      // First replace the original alloca.
-      Builder.SetInsertPoint(ParentAlloca);
-      Builder.SetCurrentDebugLocation(ParentAlloca->getDebugLoc());
-      Value *ElementPtr =
-          Builder.CreateConstInBoundsGEP2_32(FrameEHData, 0, Idx);
-      ParentAlloca->replaceAllUsesWith(ElementPtr);
-      ParentAlloca->removeFromParent();
-      ElementPtr->takeName(ParentAlloca);
-      if (ParentAlloca == AllocaInsertPt)
-        AllocaInsertPt = dyn_cast<Instruction>(ElementPtr);
-      delete ParentAlloca;
+    // Add this alloca to the list of things to escape.
+    AllocasToEscape.push_back(ParentAlloca);
 
-      // Next replace all outlined allocas that are mapped to it.
-      for (AllocaInst *TempAlloca : AllocaInfo.Allocas) {
-        Value *EHData = EHDataMap[TempAlloca->getParent()->getParent()];
-        // FIXME: Sink this GEP into the blocks where it is used.
-        Builder.SetInsertPoint(TempAlloca);
-        Builder.SetCurrentDebugLocation(TempAlloca->getDebugLoc());
-        ElementPtr = Builder.CreateConstInBoundsGEP2_32(EHData, 0, Idx);
-        TempAlloca->replaceAllUsesWith(ElementPtr);
-        TempAlloca->removeFromParent();
-        ElementPtr->takeName(TempAlloca);
-        delete TempAlloca;
+    // Next replace all outlined allocas that are mapped to it.
+    for (AllocaInst *TempAlloca : Allocas) {
+      Function *HandlerFn = TempAlloca->getParent()->getParent();
+      // FIXME: Sink this GEP into the blocks where it is used.
+      Builder.SetInsertPoint(TempAlloca);
+      Builder.SetCurrentDebugLocation(TempAlloca->getDebugLoc());
+      Value *RecoverArgs[] = {
+          Builder.CreateBitCast(&F, Int8PtrType, ""),
+          &(HandlerFn->getArgumentList().back()),
+          llvm::ConstantInt::get(Int32Type, AllocasToEscape.size() - 1)};
+      Value *RecoveredAlloca =
+          Builder.CreateCall(RecoverFrameFn, RecoverArgs);
+      // Add a pointer bitcast if the alloca wasn't an i8.
+      if (RecoveredAlloca->getType() != TempAlloca->getType()) {
+        RecoveredAlloca->setName(Twine(TempAlloca->getName()) + ".i8");
+        RecoveredAlloca =
+            Builder.CreateBitCast(RecoveredAlloca, TempAlloca->getType());
       }
-    } // end else of if (Idx == -1)
+      TempAlloca->replaceAllUsesWith(RecoveredAlloca);
+      TempAlloca->removeFromParent();
+      RecoveredAlloca->takeName(TempAlloca);
+      delete TempAlloca;
+    }
   }   // End for each FrameVarInfo entry.
 
+  // Insert 'call void (...)* @llvm.frameescape(...)' at the end of the entry
+  // block.
+  Builder.SetInsertPoint(&F.getEntryBlock().back());
+  Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
+
   return HandlersOutlined;
 }
 
 bool WinEHPrepare::outlineHandler(HandlerType CatchOrCleanup, Function *SrcFn,
                                   Constant *SelectorType, LandingPadInst *LPad,
-                                  CallInst *&EHAlloc,
                                   FrameVarInfoMap &VarInfo) {
   Module *M = SrcFn->getParent();
   LLVMContext &Context = M->getContext();
@@ -500,23 +412,6 @@
   Builder.SetInsertPoint(Entry);
   Builder.SetCurrentDebugLocation(LPad->getDebugLoc());
 
-  // The outlined handler will be called with the parent's frame pointer as
-  // its second argument. To enable the handler to access variables from
-  // the parent frame, we use that pointer to get locate a special block
-  // of memory that was allocated using llvm.eh.allocateframe for this
-  // purpose.  During the outlining process we will determine which frame
-  // variables are used in handlers and create a structure that maps these
-  // variables into the frame allocation block.
-  //
-  // The frame allocation block also contains an exception state variable
-  // used by the runtime and a pointer to the exception object pointer
-  // which will be filled in by the runtime for use in the handler.
-  Function *RecoverFrameFn =
-      Intrinsic::getDeclaration(M, Intrinsic::framerecover);
-  Value *RecoverArgs[] = {Builder.CreateBitCast(SrcFn, Int8PtrType, ""),
-                          &(Handler->getArgumentList().back())};
-  EHAlloc = Builder.CreateCall(RecoverFrameFn, RecoverArgs, "eh.alloc");
-
   std::unique_ptr<WinEHCloningDirectorBase> Director;
 
   if (CatchOrCleanup == Catch) {
@@ -765,7 +660,7 @@
   if (auto *AV = dyn_cast<AllocaInst>(V)) {
     AllocaInst *NewAlloca = dyn_cast<AllocaInst>(AV->clone());
     Builder.Insert(NewAlloca, AV->getName());
-    FrameVarInfo[AV].Allocas.push_back(NewAlloca);
+    FrameVarInfo[AV].push_back(NewAlloca);
     return NewAlloca;
   }
 
@@ -776,7 +671,7 @@
   if (isa<Instruction>(V) || isa<Argument>(V)) {
     AllocaInst *NewAlloca =
         Builder.CreateAlloca(V->getType(), nullptr, "eh.temp.alloca");
-    FrameVarInfo[V].Allocas.push_back(NewAlloca);
+    FrameVarInfo[V].push_back(NewAlloca);
     LoadInst *NewLoad = Builder.CreateLoad(NewAlloca, V->getName() + ".reload");
     return NewLoad;
   }