summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/CodeGen/PrologEpilogInserter.cpp11
-rw-r--r--lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp46
-rw-r--r--lib/CodeGen/WinEHPrepare.cpp213
-rw-r--r--lib/IR/Verifier.cpp55
-rw-r--r--lib/MC/MCContext.cpp7
-rw-r--r--lib/Target/X86/X86RegisterInfo.cpp19
6 files changed, 145 insertions, 206 deletions
diff --git a/lib/CodeGen/PrologEpilogInserter.cpp b/lib/CodeGen/PrologEpilogInserter.cpp
index 6d29b98f3c9..e75cb038abb 100644
--- a/lib/CodeGen/PrologEpilogInserter.cpp
+++ b/lib/CodeGen/PrologEpilogInserter.cpp
@@ -810,17 +810,6 @@ void PEI::replaceFrameIndices(MachineBasicBlock *BB, MachineFunction &Fn,
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/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 097b618252e..c5bd2ab19ca 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5618,45 +5618,47 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
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/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp
index 5a13e556d54..eefb278f0a7 100644
--- a/lib/CodeGen/WinEHPrepare.cpp
+++ b/lib/CodeGen/WinEHPrepare.cpp
@@ -36,17 +36,12 @@ using namespace llvm::PatternMatch;
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 @@ private:
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 @@ bool WinEHPrepare::prepareCPPEHHandlers(
// 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 @@ bool WinEHPrepare::prepareCPPEHHandlers(
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 @@ bool WinEHPrepare::prepareCPPEHHandlers(
// 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 @@ bool WinEHPrepare::prepareCPPEHHandlers(
// 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 @@ bool WinEHPrepare::prepareCPPEHHandlers(
}
}
- // 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.
-
- // 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;
-
- // 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;
+ continue;
+ }
+
+ // 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 : 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 @@ bool WinEHPrepare::outlineHandler(HandlerType CatchOrCleanup, Function *SrcFn,
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 @@ Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
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 @@ Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
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;
}
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index fbdc9880c5c..71e53f4b15c 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -198,14 +198,18 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
/// personality function.
const Value *PersonalityFn;
- /// \brief Whether we've seen a call to @llvm.frameallocate in this function
+ /// \brief Whether we've seen a call to @llvm.frameescape in this function
/// already.
- bool SawFrameAllocate;
+ bool SawFrameEscape;
+
+ /// Stores the count of how many objects were passed to llvm.frameescape for a
+ /// given function and the largest index passed to llvm.framerecover.
+ DenseMap<Function *, std::pair<unsigned, unsigned>> FrameEscapeInfo;
public:
explicit Verifier(raw_ostream &OS = dbgs())
: VerifierSupport(OS), Context(nullptr), PersonalityFn(nullptr),
- SawFrameAllocate(false) {}
+ SawFrameEscape(false) {}
bool verify(const Function &F) {
M = F.getParent();
@@ -240,7 +244,7 @@ public:
visit(const_cast<Function &>(F));
InstsInThisBlock.clear();
PersonalityFn = nullptr;
- SawFrameAllocate = false;
+ SawFrameEscape = false;
return !Broken;
}
@@ -259,6 +263,10 @@ public:
visitFunction(*I);
}
+ // Now that we've visited every function, verify that we never asked to
+ // recover a frame index that wasn't escaped.
+ verifyFrameRecoverIndices();
+
for (Module::const_global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I)
visitGlobalVariable(*I);
@@ -373,6 +381,7 @@ private:
void VerifyConstantExprBitcastType(const ConstantExpr *CE);
void VerifyStatepoint(ImmutableCallSite CS);
+ void verifyFrameRecoverIndices();
};
class DebugInfoVerifier : public VerifierSupport {
public:
@@ -1266,6 +1275,20 @@ void Verifier::VerifyStatepoint(ImmutableCallSite CS) {
// about. See example statepoint.ll in the verifier subdirectory
}
+void Verifier::verifyFrameRecoverIndices() {
+ llvm::errs() << "verifyFrameRecoverIndices\n";
+ for (auto &Counts : FrameEscapeInfo) {
+ Function *F = Counts.first;
+ unsigned EscapedObjectCount = Counts.second.first;
+ unsigned MaxRecoveredIndex = Counts.second.second;
+ Assert1(MaxRecoveredIndex <= EscapedObjectCount,
+ "all indices passed to llvm.framerecover must be less than the "
+ "number of arguments passed ot llvm.frameescape in the parent "
+ "function",
+ F);
+ }
+}
+
// visitFunction - Verify that a function is ok.
//
void Verifier::visitFunction(const Function &F) {
@@ -2859,15 +2882,19 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
"llvm.invariant.end parameter #2 must be a constant integer", &CI);
break;
- case Intrinsic::frameallocate: {
+ case Intrinsic::frameescape: {
BasicBlock *BB = CI.getParent();
Assert1(BB == &BB->getParent()->front(),
- "llvm.frameallocate used outside of entry block", &CI);
- Assert1(!SawFrameAllocate,
- "multiple calls to llvm.frameallocate in one function", &CI);
- SawFrameAllocate = true;
- Assert1(isa<ConstantInt>(CI.getArgOperand(0)),
- "llvm.frameallocate argument must be constant integer size", &CI);
+ "llvm.frameescape used outside of entry block", &CI);
+ Assert1(!SawFrameEscape,
+ "multiple calls to llvm.frameescape in one function", &CI);
+ for (Value *Arg : CI.arg_operands()) {
+ auto *AI = dyn_cast<AllocaInst>(Arg->stripPointerCasts());
+ Assert1(AI && AI->isStaticAlloca(),
+ "llvm.frameescape only accepts static allocas", &CI);
+ }
+ FrameEscapeInfo[BB->getParent()].first = CI.getNumArgOperands();
+ SawFrameEscape = true;
break;
}
case Intrinsic::framerecover: {
@@ -2875,6 +2902,12 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
Function *Fn = dyn_cast<Function>(FnArg);
Assert1(Fn && !Fn->isDeclaration(), "llvm.framerecover first "
"argument must be function defined in this module", &CI);
+ auto *IdxArg = dyn_cast<ConstantInt>(CI.getArgOperand(2));
+ Assert1(IdxArg, "idx argument of llvm.framerecover must be a constant int",
+ &CI);
+ auto &Entry = FrameEscapeInfo[Fn];
+ Entry.second = unsigned(
+ std::max(uint64_t(Entry.second), IdxArg->getLimitedValue(~0U) + 1));
break;
}
diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp
index 27b0728403a..ae082bb6074 100644
--- a/lib/MC/MCContext.cpp
+++ b/lib/MC/MCContext.cpp
@@ -131,9 +131,10 @@ MCSymbol *MCContext::getOrCreateSectionSymbol(const MCSectionELF &Section) {
return Sym;
}
-MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName) {
- return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) +
- "frameallocation_" + FuncName);
+MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName,
+ unsigned Idx) {
+ return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + FuncName +
+ "$frame_escape_" + Twine(Idx));
}
MCSymbol *MCContext::CreateSymbol(StringRef Name) {
diff --git a/lib/Target/X86/X86RegisterInfo.cpp b/lib/Target/X86/X86RegisterInfo.cpp
index f1fd5470c88..dc3de1c01b0 100644
--- a/lib/Target/X86/X86RegisterInfo.cpp
+++ b/lib/Target/X86/X86RegisterInfo.cpp
@@ -496,6 +496,25 @@ X86RegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
else
BasePtr = (TFI->hasFP(MF) ? FramePtr : StackPtr);
+ // FRAME_ALLOC uses a single offset, with no register. It only works in the
+ // simple FP case, and doesn't work with stack realignment. On 32-bit, the
+ // offset is from the traditional base pointer location. On 64-bit, the
+ // offset is from the SP at the end of the prologue, not the FP location. This
+ // matches the behavior of llvm.frameaddress.
+ if (Opc == TargetOpcode::FRAME_ALLOC) {
+ assert(TFI->hasFP(MF) && "frame alloc requires FP");
+ MachineOperand &FI = MI.getOperand(FIOperandNum);
+ const MachineFrameInfo *MFI = MF.getFrameInfo();
+ int Offset = MFI->getObjectOffset(FrameIndex) - TFI->getOffsetOfLocalArea();
+ bool IsWinEH = MF.getTarget().getMCAsmInfo()->usesWindowsCFI();
+ if (IsWinEH)
+ Offset += MFI->getStackSize();
+ else
+ Offset += SlotSize;
+ FI.ChangeToImmediate(Offset);
+ return;
+ }
+
// For LEA64_32r when BasePtr is 32-bits (X32) we can use full-size 64-bit
// register as source operand, semantic is the same and destination is
// 32-bits. It saves one byte per lea in code since 0x67 prefix is avoided.