summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp68
-rw-r--r--llvm/lib/IR/LLVMContext.cpp5
-rw-r--r--llvm/lib/IR/Verifier.cpp20
-rw-r--r--llvm/lib/Transforms/Utils/InlineFunction.cpp93
-rw-r--r--llvm/lib/Transforms/Utils/Local.cpp4
5 files changed, 134 insertions, 56 deletions
diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp
index 3ac5d8a7c3b..3b076b65e69 100644
--- a/llvm/lib/CodeGen/WinEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -74,7 +74,7 @@ private:
void demotePHIsOnFunclets(Function &F);
void cloneCommonBlocks(Function &F);
- void removeImplausibleTerminators(Function &F);
+ void removeImplausibleInstructions(Function &F);
void cleanupPreparedFunclets(Function &F);
void verifyPreparedFunclets(Function &F);
@@ -765,19 +765,56 @@ void WinEHPrepare::cloneCommonBlocks(Function &F) {
}
}
-void WinEHPrepare::removeImplausibleTerminators(Function &F) {
+void WinEHPrepare::removeImplausibleInstructions(Function &F) {
// Remove implausible terminators and replace them with UnreachableInst.
for (auto &Funclet : FuncletBlocks) {
BasicBlock *FuncletPadBB = Funclet.first;
std::vector<BasicBlock *> &BlocksInFunclet = Funclet.second;
- Instruction *FuncletPadInst = FuncletPadBB->getFirstNonPHI();
- auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPadInst);
- auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPadInst);
+ Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI();
+ auto *FuncletPad = dyn_cast<FuncletPadInst>(FirstNonPHI);
+ auto *CatchPad = dyn_cast_or_null<CatchPadInst>(FuncletPad);
+ auto *CleanupPad = dyn_cast_or_null<CleanupPadInst>(FuncletPad);
for (BasicBlock *BB : BlocksInFunclet) {
+ for (Instruction &I : *BB) {
+ CallSite CS(&I);
+ if (!CS)
+ continue;
+
+ Value *FuncletBundleOperand = nullptr;
+ if (auto BU = CS.getOperandBundle(LLVMContext::OB_funclet))
+ FuncletBundleOperand = BU->Inputs.front();
+
+ if (FuncletBundleOperand == FuncletPad)
+ continue;
+
+ // Skip call sites which are nounwind intrinsics.
+ auto *CalledFn =
+ dyn_cast<Function>(CS.getCalledValue()->stripPointerCasts());
+ if (CalledFn && CalledFn->isIntrinsic() && CS.doesNotThrow())
+ continue;
+
+ // This call site was not part of this funclet, remove it.
+ if (CS.isInvoke()) {
+ // Remove the unwind edge if it was an invoke.
+ removeUnwindEdge(BB);
+ // Get a pointer to the new call.
+ BasicBlock::iterator CallI =
+ std::prev(BB->getTerminator()->getIterator());
+ auto *CI = cast<CallInst>(&*CallI);
+ changeToUnreachable(CI, /*UseLLVMTrap=*/false);
+ } else {
+ changeToUnreachable(&I, /*UseLLVMTrap=*/false);
+ }
+
+ // There are no more instructions in the block (except for unreachable),
+ // we are done.
+ break;
+ }
+
TerminatorInst *TI = BB->getTerminator();
// CatchPadInst and CleanupPadInst can't transfer control to a ReturnInst.
- bool IsUnreachableRet = isa<ReturnInst>(TI) && (CatchPad || CleanupPad);
+ bool IsUnreachableRet = isa<ReturnInst>(TI) && FuncletPad;
// The token consumed by a CatchReturnInst must match the funclet token.
bool IsUnreachableCatchret = false;
if (auto *CRI = dyn_cast<CatchReturnInst>(TI))
@@ -788,19 +825,14 @@ void WinEHPrepare::removeImplausibleTerminators(Function &F) {
IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad;
if (IsUnreachableRet || IsUnreachableCatchret ||
IsUnreachableCleanupret) {
- // Loop through all of our successors and make sure they know that one
- // of their predecessors is going away.
- for (BasicBlock *SuccBB : TI->successors())
- SuccBB->removePredecessor(BB);
-
- new UnreachableInst(BB->getContext(), TI);
- TI->eraseFromParent();
+ changeToUnreachable(TI, /*UseLLVMTrap=*/false);
} else if (isa<InvokeInst>(TI)) {
- // Invokes within a cleanuppad for the MSVC++ personality never
- // transfer control to their unwind edge: the personality will
- // terminate the program.
- if (Personality == EHPersonality::MSVC_CXX && CleanupPad)
+ if (Personality == EHPersonality::MSVC_CXX && CleanupPad) {
+ // Invokes within a cleanuppad for the MSVC++ personality never
+ // transfer control to their unwind edge: the personality will
+ // terminate the program.
removeUnwindEdge(BB);
+ }
}
}
}
@@ -854,7 +886,7 @@ bool WinEHPrepare::prepareExplicitEH(Function &F) {
demotePHIsOnFunclets(F);
if (!DisableCleanups) {
- removeImplausibleTerminators(F);
+ removeImplausibleInstructions(F);
cleanupPreparedFunclets(F);
}
diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp
index af998c86135..8848bcb7147 100644
--- a/llvm/lib/IR/LLVMContext.cpp
+++ b/llvm/lib/IR/LLVMContext.cpp
@@ -132,6 +132,11 @@ LLVMContext::LLVMContext() : pImpl(new LLVMContextImpl(*this)) {
assert(DeoptEntry->second == LLVMContext::OB_deopt &&
"deopt operand bundle id drifted!");
(void)DeoptEntry;
+
+ auto *FuncletEntry = pImpl->getOrInsertBundleTag("funclet");
+ assert(FuncletEntry->second == LLVMContext::OB_funclet &&
+ "funclet operand bundle id drifted!");
+ (void)FuncletEntry;
}
LLVMContext::~LLVMContext() { delete pImpl; }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 234ab29d8ed..32646cf7999 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2381,13 +2381,25 @@ void Verifier::VerifyCallSite(CallSite CS) {
if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID())
visitIntrinsicCallSite(ID, CS);
- // Verify that a callsite has at most one "deopt" operand bundle.
- bool FoundDeoptBundle = false;
+ // Verify that a callsite has at most one "deopt" and one "funclet" operand
+ // bundle.
+ bool FoundDeoptBundle = false, FoundFuncletBundle = false;
for (unsigned i = 0, e = CS.getNumOperandBundles(); i < e; ++i) {
- if (CS.getOperandBundleAt(i).getTagID() == LLVMContext::OB_deopt) {
+ OperandBundleUse BU = CS.getOperandBundleAt(i);
+ uint32_t Tag = BU.getTagID();
+ if (Tag == LLVMContext::OB_deopt) {
Assert(!FoundDeoptBundle, "Multiple deopt operand bundles", I);
FoundDeoptBundle = true;
}
+ if (Tag == LLVMContext::OB_funclet) {
+ Assert(!FoundFuncletBundle, "Multiple funclet operand bundles", I);
+ FoundFuncletBundle = true;
+ Assert(BU.Inputs.size() == 1,
+ "Expected exactly one funclet bundle operand", I);
+ Assert(isa<FuncletPadInst>(BU.Inputs.front()),
+ "Funclet bundle operands should correspond to a FuncletPadInst",
+ I);
+ }
}
visitInstruction(*I);
@@ -3002,6 +3014,8 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
UnwindDest = CRI->getUnwindDest();
} else if (isa<CleanupPadInst>(U) || isa<CatchSwitchInst>(U)) {
continue;
+ } else if (CallSite(U)) {
+ continue;
} else {
Assert(false, "bogus cleanuppad use", &CPI);
}
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index b0d99a8e830..db2cacd4739 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -1035,12 +1035,17 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
// The inliner does not know how to inline through calls with operand bundles
// in general ...
if (CS.hasOperandBundles()) {
- // ... but it knows how to inline through "deopt" operand bundles.
- bool CanInline =
- CS.getNumOperandBundles() == 1 &&
- CS.getOperandBundleAt(0).getTagID() == LLVMContext::OB_deopt;
- if (!CanInline)
+ for (int i = 0, e = CS.getNumOperandBundles(); i != e; ++i) {
+ uint32_t Tag = CS.getOperandBundleAt(i).getTagID();
+ // ... but it knows how to inline through "deopt" operand bundles ...
+ if (Tag == LLVMContext::OB_deopt)
+ continue;
+ // ... and "funclet" operand bundles.
+ if (Tag == LLVMContext::OB_funclet)
+ continue;
+
return false;
+ }
}
// If the call to the callee cannot throw, set the 'nounwind' flag on any
@@ -1088,23 +1093,13 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
// We need to figure out which funclet the callsite was in so that we may
// properly nest the callee.
Instruction *CallSiteEHPad = nullptr;
- if (CalledPersonality && CallerPersonality) {
- EHPersonality Personality = classifyEHPersonality(CalledPersonality);
+ if (CallerPersonality) {
+ EHPersonality Personality = classifyEHPersonality(CallerPersonality);
if (isFuncletEHPersonality(Personality)) {
- DenseMap<BasicBlock *, ColorVector> CallerBlockColors =
- colorEHFunclets(*Caller);
- ColorVector &CallSiteColors = CallerBlockColors[OrigBB];
- size_t NumColors = CallSiteColors.size();
- // There is no single parent, inlining will not succeed.
- if (NumColors > 1)
- return false;
- if (NumColors == 1) {
- BasicBlock *CallSiteFuncletBB = CallSiteColors.front();
- if (CallSiteFuncletBB != Caller->begin()) {
- CallSiteEHPad = CallSiteFuncletBB->getFirstNonPHI();
- assert(CallSiteEHPad->isEHPad() && "Expected an EHPad!");
- }
- }
+ Optional<OperandBundleUse> ParentFunclet =
+ CS.getOperandBundle(LLVMContext::OB_funclet);
+ if (ParentFunclet)
+ CallSiteEHPad = cast<FuncletPadInst>(ParentFunclet->Inputs.front());
// OK, the inlining site is legal. What about the target function?
@@ -1116,7 +1111,7 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
// Ok, the call site is within a cleanuppad. Let's check the callee
// for catchpads.
for (const BasicBlock &CalledBB : *CalledFunc) {
- if (isa<CatchPadInst>(CalledBB.getFirstNonPHI()))
+ if (isa<CatchSwitchInst>(CalledBB.getFirstNonPHI()))
return false;
}
}
@@ -1195,11 +1190,9 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
HandleByValArgumentInit(Init.first, Init.second, Caller->getParent(),
&*FirstNewBlock, IFI);
- if (CS.hasOperandBundles()) {
- auto ParentDeopt = CS.getOperandBundleAt(0);
- assert(ParentDeopt.getTagID() == LLVMContext::OB_deopt &&
- "Checked on entry!");
-
+ Optional<OperandBundleUse> ParentDeopt =
+ CS.getOperandBundle(LLVMContext::OB_deopt);
+ if (ParentDeopt) {
SmallVector<OperandBundleDef, 2> OpDefs;
for (auto &VH : InlinedFunctionInfo.OperandBundleCallSites) {
@@ -1225,12 +1218,12 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
// Prepend the parent's deoptimization continuation to the newly
// inlined call's deoptimization continuation.
std::vector<Value *> MergedDeoptArgs;
- MergedDeoptArgs.reserve(ParentDeopt.Inputs.size() +
+ MergedDeoptArgs.reserve(ParentDeopt->Inputs.size() +
ChildOB.Inputs.size());
MergedDeoptArgs.insert(MergedDeoptArgs.end(),
- ParentDeopt.Inputs.begin(),
- ParentDeopt.Inputs.end());
+ ParentDeopt->Inputs.begin(),
+ ParentDeopt->Inputs.end());
MergedDeoptArgs.insert(MergedDeoptArgs.end(), ChildOB.Inputs.begin(),
ChildOB.Inputs.end());
@@ -1423,12 +1416,48 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
}
}
- // Update the lexical scopes of the new funclets. Anything that had 'none' as
- // its parent is now nested inside the callsite's EHPad.
+ // Update the lexical scopes of the new funclets and callsites.
+ // Anything that had 'none' as its parent is now nested inside the callsite's
+ // EHPad.
+
if (CallSiteEHPad) {
for (Function::iterator BB = FirstNewBlock->getIterator(),
E = Caller->end();
BB != E; ++BB) {
+ // Add bundle operands to any top-level call sites.
+ SmallVector<OperandBundleDef, 1> OpBundles;
+ for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;) {
+ Instruction *I = &*BBI++;
+ CallSite CS(I);
+ if (!CS)
+ continue;
+
+ // Skip call sites which are nounwind intrinsics.
+ auto *CalledFn =
+ dyn_cast<Function>(CS.getCalledValue()->stripPointerCasts());
+ if (CalledFn && CalledFn->isIntrinsic() && CS.doesNotThrow())
+ continue;
+
+ // Skip call sites which already have a "funclet" bundle.
+ if (CS.getOperandBundle(LLVMContext::OB_funclet))
+ continue;
+
+ CS.getOperandBundlesAsDefs(OpBundles);
+ OpBundles.emplace_back("funclet", CallSiteEHPad);
+
+ Instruction *NewInst;
+ if (CS.isCall())
+ NewInst = CallInst::Create(cast<CallInst>(I), OpBundles, I);
+ else
+ NewInst = InvokeInst::Create(cast<InvokeInst>(I), OpBundles, I);
+ NewInst->setDebugLoc(I->getDebugLoc());
+ NewInst->takeName(I);
+ I->replaceAllUsesWith(NewInst);
+ I->eraseFromParent();
+
+ OpBundles.clear();
+ }
+
Instruction *I = BB->getFirstNonPHI();
if (!I->isEHPad())
continue;
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index 24f88179c90..31039816e14 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -1180,9 +1180,7 @@ bool llvm::replaceDbgDeclareForAlloca(AllocaInst *AI, Value *NewAllocaAddress,
Deref, Offset);
}
-/// changeToUnreachable - Insert an unreachable instruction before the specified
-/// instruction, making it and the rest of the code in the block dead.
-static void changeToUnreachable(Instruction *I, bool UseLLVMTrap) {
+void llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap) {
BasicBlock *BB = I->getParent();
// Loop over all of the successors, removing BB's entry from any PHI
// nodes.
OpenPOWER on IntegriCloud