mirror of
https://github.com/RPCSX/llvm.git
synced 2025-04-10 04:01:27 +00:00
[WinEH] Don't inline an 'unwinds to caller' cleanupret into funclets which locally unwind
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. If the funclet unwinds anywhere other than to the caller, then we will give the funclet two unwind destinations. This will result in a verifier failure. Seeing as how the caller wasn't an invoke (which would locally unwind) and that the funclet cannot unwind to caller, we must conclude that an 'unwind to caller' cleanupret is dynamically unreachable. This fixes PR26698. Differential Revision: http://reviews.llvm.org/D17536 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@261656 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
a10a4f18bf
commit
e759b51ef4
@ -1420,6 +1420,19 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if we are dealing with a call in an EHPad which does not unwind
|
||||
// to caller.
|
||||
bool EHPadForCallUnwindsLocally = false;
|
||||
if (CallSiteEHPad && CS.isCall()) {
|
||||
UnwindDestMemoTy FuncletUnwindMap;
|
||||
Value *CallSiteUnwindDestToken =
|
||||
getUnwindDestToken(CallSiteEHPad, FuncletUnwindMap);
|
||||
|
||||
EHPadForCallUnwindsLocally =
|
||||
CallSiteUnwindDestToken &&
|
||||
!isa<ConstantTokenNone>(CallSiteUnwindDestToken);
|
||||
}
|
||||
|
||||
// Get an iterator to the last basic block in the function, which will have
|
||||
// the new function inlined after it.
|
||||
Function::iterator LastBlock = --Caller->end();
|
||||
@ -1763,6 +1776,14 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
|
||||
OpBundles.clear();
|
||||
}
|
||||
|
||||
// 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
|
||||
// an EH pad that does. Such an edge must be dynamically unreachable.
|
||||
// As such, we replace the cleanupret with unreachable.
|
||||
if (auto *CleanupRet = dyn_cast<CleanupReturnInst>(BB->getTerminator()))
|
||||
if (CleanupRet->unwindsToCaller() && EHPadForCallUnwindsLocally)
|
||||
changeToUnreachable(CleanupRet, /*UseLLVMTrap=*/false);
|
||||
|
||||
Instruction *I = BB->getFirstNonPHI();
|
||||
if (!I->isEHPad())
|
||||
continue;
|
||||
|
65
test/Transforms/Inline/pr26698.ll
Normal file
65
test/Transforms/Inline/pr26698.ll
Normal file
@ -0,0 +1,65 @@
|
||||
; RUN: opt -S -inline < %s | FileCheck %s
|
||||
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
|
||||
target triple = "i686-pc-windows-msvc18.0.0"
|
||||
|
||||
declare void @g(i32)
|
||||
|
||||
define void @f() personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
invoke void @g(i32 0)
|
||||
to label %invoke.cont unwind label %cs.bb
|
||||
|
||||
invoke.cont:
|
||||
ret void
|
||||
|
||||
cs.bb:
|
||||
%cs = catchswitch within none [label %cp.bb] unwind label %cleanup.bb
|
||||
|
||||
cp.bb:
|
||||
%cpouter1 = catchpad within %cs [i8* null, i32 0, i8* null]
|
||||
call void @dtor() #1 [ "funclet"(token %cpouter1) ]
|
||||
catchret from %cpouter1 to label %invoke.cont
|
||||
|
||||
cleanup.bb:
|
||||
%cpouter2 = cleanuppad within none []
|
||||
call void @g(i32 1) [ "funclet"(token %cpouter2) ]
|
||||
cleanupret from %cpouter2 unwind to caller
|
||||
}
|
||||
|
||||
declare i32 @__CxxFrameHandler3(...)
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @dtor() #1 personality i32 (...)* @__CxxFrameHandler3 {
|
||||
entry:
|
||||
invoke void @g(i32 2)
|
||||
to label %invoke.cont unwind label %ehcleanup1
|
||||
|
||||
invoke.cont:
|
||||
ret void
|
||||
|
||||
ehcleanup1:
|
||||
%cpinner1 = cleanuppad within none []
|
||||
invoke void @g(i32 3) [ "funclet" (token %cpinner1) ]
|
||||
to label %done unwind label %ehcleanup2
|
||||
done:
|
||||
unreachable
|
||||
|
||||
ehcleanup2:
|
||||
%cpinner2 = cleanuppad within %cpinner1 []
|
||||
call void @g(i32 4) [ "funclet" (token %cpinner2) ]
|
||||
cleanupret from %cpinner2 unwind to caller
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define void @f(
|
||||
|
||||
; CHECK: %[[cs:.*]] = catchswitch within none
|
||||
|
||||
; CHECK: %[[cpouter1:.*]] = catchpad within %[[cs]]
|
||||
|
||||
; CHECK: %[[cpinner1:.*]] = cleanuppad within %[[cpouter1]]
|
||||
|
||||
; CHECK: %[[cpinner2:.*]] = cleanuppad within %[[cpinner1]]
|
||||
; CHECK-NEXT: call void @g(i32 4) #0 [ "funclet"(token %[[cpinner2]]) ]
|
||||
; CHECK-NEXT: unreachable
|
||||
|
||||
attributes #1 = { nounwind }
|
Loading…
x
Reference in New Issue
Block a user