Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 80fab33

Browse files
majnemeralexcrichton
authored andcommitted
[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
1 parent 25c7dc3 commit 80fab33

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

lib/Transforms/Utils/InlineFunction.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,19 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
14221422
}
14231423
}
14241424

1425+
// Determine if we are dealing with a call in an EHPad which does not unwind
1426+
// to caller.
1427+
bool EHPadForCallUnwindsLocally = false;
1428+
if (CallSiteEHPad && CS.isCall()) {
1429+
UnwindDestMemoTy FuncletUnwindMap;
1430+
Value *CallSiteUnwindDestToken =
1431+
getUnwindDestToken(CallSiteEHPad, FuncletUnwindMap);
1432+
1433+
EHPadForCallUnwindsLocally =
1434+
CallSiteUnwindDestToken &&
1435+
!isa<ConstantTokenNone>(CallSiteUnwindDestToken);
1436+
}
1437+
14251438
// Get an iterator to the last basic block in the function, which will have
14261439
// the new function inlined after it.
14271440
Function::iterator LastBlock = --Caller->end();
@@ -1766,6 +1779,14 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI,
17661779
OpBundles.clear();
17671780
}
17681781

1782+
// It is problematic if the inlinee has a cleanupret which unwinds to
1783+
// caller and we inline it into a call site which doesn't unwind but into
1784+
// an EH pad that does. Such an edge must be dynamically unreachable.
1785+
// As such, we replace the cleanupret with unreachable.
1786+
if (auto *CleanupRet = dyn_cast<CleanupReturnInst>(BB->getTerminator()))
1787+
if (CleanupRet->unwindsToCaller() && EHPadForCallUnwindsLocally)
1788+
changeToUnreachable(CleanupRet, /*UseLLVMTrap=*/false);
1789+
17691790
Instruction *I = BB->getFirstNonPHI();
17701791
if (!I->isEHPad())
17711792
continue;

test/Transforms/Inline/pr26698.ll

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
; RUN: opt -S -inline < %s | FileCheck %s
2+
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
3+
target triple = "i686-pc-windows-msvc18.0.0"
4+
5+
declare void @g(i32)
6+
7+
define void @f() personality i32 (...)* @__CxxFrameHandler3 {
8+
entry:
9+
invoke void @g(i32 0)
10+
to label %invoke.cont unwind label %cs.bb
11+
12+
invoke.cont:
13+
ret void
14+
15+
cs.bb:
16+
%cs = catchswitch within none [label %cp.bb] unwind label %cleanup.bb
17+
18+
cp.bb:
19+
%cpouter1 = catchpad within %cs [i8* null, i32 0, i8* null]
20+
call void @dtor() #1 [ "funclet"(token %cpouter1) ]
21+
catchret from %cpouter1 to label %invoke.cont
22+
23+
cleanup.bb:
24+
%cpouter2 = cleanuppad within none []
25+
call void @g(i32 1) [ "funclet"(token %cpouter2) ]
26+
cleanupret from %cpouter2 unwind to caller
27+
}
28+
29+
declare i32 @__CxxFrameHandler3(...)
30+
31+
; Function Attrs: nounwind
32+
define internal void @dtor() #1 personality i32 (...)* @__CxxFrameHandler3 {
33+
entry:
34+
invoke void @g(i32 2)
35+
to label %invoke.cont unwind label %ehcleanup1
36+
37+
invoke.cont:
38+
ret void
39+
40+
ehcleanup1:
41+
%cpinner1 = cleanuppad within none []
42+
invoke void @g(i32 3) [ "funclet" (token %cpinner1) ]
43+
to label %done unwind label %ehcleanup2
44+
done:
45+
unreachable
46+
47+
ehcleanup2:
48+
%cpinner2 = cleanuppad within %cpinner1 []
49+
call void @g(i32 4) [ "funclet" (token %cpinner2) ]
50+
cleanupret from %cpinner2 unwind to caller
51+
}
52+
53+
; CHECK-LABEL: define void @f(
54+
55+
; CHECK: %[[cs:.*]] = catchswitch within none
56+
57+
; CHECK: %[[cpouter1:.*]] = catchpad within %[[cs]]
58+
59+
; CHECK: %[[cpinner1:.*]] = cleanuppad within %[[cpouter1]]
60+
61+
; CHECK: %[[cpinner2:.*]] = cleanuppad within %[[cpinner1]]
62+
; CHECK-NEXT: call void @g(i32 4) #0 [ "funclet"(token %[[cpinner2]]) ]
63+
; CHECK-NEXT: unreachable
64+
65+
attributes #1 = { nounwind }

0 commit comments

Comments
 (0)