diff options
author | Stefan Gränitz <stefan.graenitz@gmail.com> | 2022-07-26 11:40:48 +0200 |
---|---|---|
committer | Stefan Gränitz <stefan.graenitz@gmail.com> | 2022-07-26 17:52:43 +0200 |
commit | 1e308204838b5edc5ffbd775896a004edb08c60a (patch) | |
tree | 7caf76337be9414026ef1ac577ce98296f11a998 /llvm/lib/Transforms/Utils/InlineFunction.cpp | |
parent | 75b15a7e63d9d31b5191afa49e38439dfe12bd40 (diff) | |
download | llvm-1e308204838b5edc5ffbd775896a004edb08c60a.zip llvm-1e308204838b5edc5ffbd775896a004edb08c60a.tar.gz llvm-1e308204838b5edc5ffbd775896a004edb08c60a.tar.bz2 |
[WinEH] Apply funclet operand bundles to nounwind intrinsics that lower to function calls in the course of IR transforms
WinEHPrepare marks any function call from EH funclets as unreachable, if it's not a nounwind intrinsic or has no proper funclet bundle operand. This
affects ARC intrinsics on Windows, because they are lowered to regular function calls in the PreISelIntrinsicLowering pass. It caused silent binary truncations and crashes during unwinding with the GNUstep ObjC runtime: https://github.com/gnustep/libobjc2/issues/222
This patch adds a new function `llvm::IntrinsicInst::mayLowerToFunctionCall()` that aims to collect all affected intrinsic IDs.
* Clang CodeGen uses it to determine whether or not it must emit a funclet bundle operand.
* PreISelIntrinsicLowering asserts that the function returns true for all ObjC runtime calls it lowers.
* LLVM uses it to determine whether or not a funclet bundle operand must be propagated to inlined call sites.
Reviewed By: theraven
Differential Revision: https://reviews.llvm.org/D128190
Diffstat (limited to 'llvm/lib/Transforms/Utils/InlineFunction.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/InlineFunction.cpp | 59 |
1 files changed, 31 insertions, 28 deletions
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index 00387ec..878f947 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -825,6 +825,35 @@ static void PropagateCallSiteMetadata(CallBase &CB, Function::iterator FStart, } } +/// Bundle operands of the inlined function must be added to inlined call sites. +static void PropagateOperandBundles(Function::iterator InlinedBB, + Instruction *CallSiteEHPad) { + for (Instruction &II : llvm::make_early_inc_range(*InlinedBB)) { + CallBase *I = dyn_cast<CallBase>(&II); + if (!I) + continue; + // Skip call sites which already have a "funclet" bundle. + if (I->getOperandBundle(LLVMContext::OB_funclet)) + continue; + // Skip call sites which are nounwind intrinsics (as long as they don't + // lower into regular function calls in the course of IR transformations). + auto *CalledFn = + dyn_cast<Function>(I->getCalledOperand()->stripPointerCasts()); + if (CalledFn && CalledFn->isIntrinsic() && I->doesNotThrow() && + !IntrinsicInst::mayLowerToFunctionCall(CalledFn->getIntrinsicID())) + continue; + + SmallVector<OperandBundleDef, 1> OpBundles; + I->getOperandBundlesAsDefs(OpBundles); + OpBundles.emplace_back("funclet", CallSiteEHPad); + + Instruction *NewInst = CallBase::Create(I, OpBundles, I); + NewInst->takeName(I); + I->replaceAllUsesWith(NewInst); + I->eraseFromParent(); + } +} + namespace { /// Utility for cloning !noalias and !alias.scope metadata. When a code region /// using scoped alias metadata is inlined, the aliasing relationships may not @@ -2304,38 +2333,12 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // 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 (Instruction &II : llvm::make_early_inc_range(*BB)) { - CallBase *I = dyn_cast<CallBase>(&II); - if (!I) - continue; - - // Skip call sites which are nounwind intrinsics. - auto *CalledFn = - dyn_cast<Function>(I->getCalledOperand()->stripPointerCasts()); - if (CalledFn && CalledFn->isIntrinsic() && I->doesNotThrow()) - continue; - - // Skip call sites which already have a "funclet" bundle. - if (I->getOperandBundle(LLVMContext::OB_funclet)) - continue; - - I->getOperandBundlesAsDefs(OpBundles); - OpBundles.emplace_back("funclet", CallSiteEHPad); - - Instruction *NewInst = CallBase::Create(I, OpBundles, I); - NewInst->takeName(I); - I->replaceAllUsesWith(NewInst); - I->eraseFromParent(); - - OpBundles.clear(); - } + // Add bundle operands to inlined call sites. + PropagateOperandBundles(BB, CallSiteEHPad); // It is problematic if the inlinee has a cleanupret which unwinds to // caller and we inline it into a call site which doesn't unwind but into |