summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp53
-rw-r--r--llvm/lib/IR/Verifier.cpp2
2 files changed, 46 insertions, 9 deletions
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index c7a3ab113bd..94d522faca4 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -52,6 +52,12 @@ namespace {
// frame allocation structure.
typedef MapVector<Value *, TinyPtrVector<AllocaInst *>> FrameVarInfoMap;
+// TinyPtrVector cannot hold nullptr, so we need our own sentinel that isn't
+// quite null.
+AllocaInst *getCatchObjectSentinel() {
+ return static_cast<AllocaInst *>(nullptr) + 1;
+}
+
typedef SmallSet<BasicBlock *, 4> VisitedBlockSet;
class LandingPadActions;
@@ -107,6 +113,8 @@ public:
virtual Value *materializeValueFor(Value *V) override;
+ void escapeCatchObject(Value *V);
+
private:
FrameVarInfoMap &FrameVarInfo;
IRBuilder<> Builder;
@@ -193,13 +201,13 @@ public:
CloningAction handleResume(ValueToValueMapTy &VMap, const ResumeInst *Resume,
BasicBlock *NewBB) override;
- const Value *getExceptionVar() { return ExceptionObjectVar; }
+ Value *getExceptionVar() { return ExceptionObjectVar; }
TinyPtrVector<BasicBlock *> &getReturnTargets() { return ReturnTargets; }
private:
Value *CurrentSelector;
- const Value *ExceptionObjectVar;
+ Value *ExceptionObjectVar;
TinyPtrVector<BasicBlock *> ReturnTargets;
};
@@ -405,11 +413,17 @@ bool WinEHPrepare::prepareExceptionHandlers(
if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
ActionArgs.push_back(ConstantInt::get(Int32Type, 1));
ActionArgs.push_back(CatchAction->getSelector());
+ // Find the frame escape index of the exception object alloca in the
+ // parent.
+ int FrameEscapeIdx = -1;
Value *EHObj = const_cast<Value *>(CatchAction->getExceptionVar());
- if (EHObj)
- ActionArgs.push_back(EHObj);
- else
- ActionArgs.push_back(ConstantPointerNull::get(Int8PtrType));
+ if (EHObj && !isa<ConstantPointerNull>(EHObj)) {
+ auto I = FrameVarInfo.find(EHObj);
+ assert(I != FrameVarInfo.end() &&
+ "failed to map llvm.eh.begincatch var");
+ FrameEscapeIdx = std::distance(FrameVarInfo.begin(), I);
+ }
+ ActionArgs.push_back(ConstantInt::get(Int32Type, FrameEscapeIdx));
} else {
ActionArgs.push_back(ConstantInt::get(Int32Type, 0));
}
@@ -495,10 +509,15 @@ bool WinEHPrepare::prepareExceptionHandlers(
}
}
- // 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) {
+ // If the parent alloca is used by exactly one handler and is not a catch
+ // parameter, erase the parent and leave the copy in the outlined handler.
+ // Catch parameters are indicated by a single null pointer in Allocas.
+ if (ParentAlloca->getNumUses() == 0 && Allocas.size() == 1 &&
+ Allocas[0] != getCatchObjectSentinel()) {
ParentAlloca->eraseFromParent();
+ // FIXME: Put a null entry in the llvm.frameescape call because we've
+ // already created llvm.eh.actions calls with indices into it.
+ AllocasToEscape.push_back(Constant::getNullValue(Int8PtrType));
continue;
}
@@ -507,6 +526,8 @@ bool WinEHPrepare::prepareExceptionHandlers(
// Next replace all outlined allocas that are mapped to it.
for (AllocaInst *TempAlloca : Allocas) {
+ if (TempAlloca == getCatchObjectSentinel())
+ continue; // Skip catch parameter sentinels.
Function *HandlerFn = TempAlloca->getParent()->getParent();
// FIXME: Sink this GEP into the blocks where it is used.
Builder.SetInsertPoint(TempAlloca);
@@ -859,6 +880,11 @@ CloningDirector::CloningAction WinEHCatchDirector::handleBeginCatch(
"llvm.eh.begincatch found while "
"outlining catch handler.");
ExceptionObjectVar = Inst->getOperand(1)->stripPointerCasts();
+ if (isa<ConstantPointerNull>(ExceptionObjectVar))
+ return CloningDirector::SkipInstruction;
+ AllocaInst *AI = dyn_cast<AllocaInst>(ExceptionObjectVar);
+ assert(AI && AI->isStaticAlloca() && "catch parameter is not static alloca");
+ Materializer.escapeCatchObject(ExceptionObjectVar);
return CloningDirector::SkipInstruction;
}
@@ -1045,6 +1071,15 @@ Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
return nullptr;
}
+void WinEHFrameVariableMaterializer::escapeCatchObject(Value *V) {
+ // Catch parameter objects have to live in the parent frame. When we see a use
+ // of a catch parameter, add a sentinel to the multimap to indicate that it's
+ // used from another handler. This will prevent us from trying to sink the
+ // alloca into the handler and ensure that the catch parameter is present in
+ // the call to llvm.frameescape.
+ FrameVarInfo[V].push_back(getCatchObjectSentinel());
+}
+
// This function maps the catch and cleanup handlers that are reachable from the
// specified landing pad. The landing pad sequence will have this basic shape:
//
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 1cdb99c4366..31ddd6543a7 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3204,6 +3204,8 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
Assert(!SawFrameEscape,
"multiple calls to llvm.frameescape in one function", &CI);
for (Value *Arg : CI.arg_operands()) {
+ if (isa<ConstantPointerNull>(Arg))
+ continue; // Null values are allowed as placeholders.
auto *AI = dyn_cast<AllocaInst>(Arg->stripPointerCasts());
Assert(AI && AI->isStaticAlloca(),
"llvm.frameescape only accepts static allocas", &CI);
OpenPOWER on IntegriCloud