llvm.org GIT mirror llvm / 25f74b9
Revert r258580 and r258581. Those commits created an artificial edge from a cleanup to a synthesized catchswitch in order to get the MSVC personality routine to execute cleanups which don't cleanupret and are not wrapped by a catchswitch. This worked well enough but is not a complete solution in situations where there the cleanup infinite loops. However, the real deal breaker behind this approach comes about from a degenerate case where the cleanup is post-dominated by unreachable *and* throws an exception. This ends poorly because the catchswitch will inadvertently catch the exception. Because of this we should go back to our previous behavior of not executing certain cleanups (identical behavior with the Itanium ABI implementation in clang, GCC and ICC). N.B. I think this could be salvaged by making the catchpad rethrow the exception and properly transforming throwing calls in the cleanup into invokes. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@259338 91177308-0d34-0410-b5e6-96231b3b80d8 David Majnemer 4 years ago
5 changed file(s) with 4 addition(s) and 213 deletion(s). Raw diff Collapse all Expand all
8080 void cloneCommonBlocks(Function &F);
8181 void removeImplausibleInstructions(Function &F);
8282 void cleanupPreparedFunclets(Function &F);
83 void fixupNoReturnCleanupPads(Function &F);
8483 void verifyPreparedFunclets(Function &F);
8584
8685 // All fields are reset by runOnFunction.
656655
657656 void WinEHPrepare::colorFunclets(Function &F) {
658657 BlockColors = colorEHFunclets(F);
659 FuncletBlocks.clear();
660658
661659 // Invert the map from BB to colors to color to BBs.
662660 for (BasicBlock &BB : F) {
10021000 removeUnreachableBlocks(F);
10031001 }
10041002
1005 // Cleanuppads which are postdominated by unreachable will not unwind to any
1006 // catchswitches, making them dead. This is problematic if the original source
1007 // had a catch clause which could legitimately catch the exception, causing the
1008 // cleanup to run.
1009 //
1010 // This is only a problem for C++ where down-stream catches cause cleanups to
1011 // run.
1012 void WinEHPrepare::fixupNoReturnCleanupPads(Function &F) {
1013 // We only need to do this for C++ personality routines,
1014 // skip this work for all others.
1015 if (Personality != EHPersonality::MSVC_CXX)
1016 return;
1017
1018 // Do a quick sanity check on the color map before we throw it away so as to
1019 // avoid hiding latent bugs.
1020 DEBUG(verifyPreparedFunclets(F));
1021 // Re-color the funclets because cleanupPreparedFunclets might have
1022 // invalidated FuncletBlocks.
1023 colorFunclets(F);
1024
1025 // We create a unique catchswitch for each parent it will be nested within.
1026 SmallDenseMap NewCatchSwitches;
1027 // Create a new catchswitch+catchpad where the catchpad is post-dominated by
1028 // unreachable.
1029 auto GetOrCreateCatchSwitch = [&](Value *ParentPad) {
1030 auto &CatchSwitch = NewCatchSwitches[ParentPad];
1031 if (CatchSwitch)
1032 return CatchSwitch;
1033
1034 auto *ParentBB = isa(ParentPad)
1035 ? &F.getEntryBlock()
1036 : cast(ParentPad)->getParent();
1037
1038 StringRef NameSuffix = ParentBB->getName();
1039
1040 BasicBlock *CatchSwitchBB = BasicBlock::Create(
1041 F.getContext(), Twine("catchswitchbb.for.", NameSuffix));
1042 CatchSwitchBB->insertInto(&F, ParentBB->getNextNode());
1043 CatchSwitch = CatchSwitchInst::Create(ParentPad, /*UnwindDest=*/nullptr,
1044 /*NumHandlers=*/1,
1045 Twine("catchswitch.for.", NameSuffix),
1046 CatchSwitchBB);
1047
1048 BasicBlock *CatchPadBB = BasicBlock::Create(
1049 F.getContext(), Twine("catchpadbb.for.", NameSuffix));
1050 CatchPadBB->insertInto(&F, CatchSwitchBB->getNextNode());
1051 Value *CatchPadArgs[] = {
1052 Constant::getNullValue(Type::getInt8PtrTy(F.getContext())),
1053 ConstantInt::get(Type::getInt32Ty(F.getContext()), 64),
1054 Constant::getNullValue(Type::getInt8PtrTy(F.getContext())),
1055 };
1056 CatchPadInst::Create(CatchSwitch, CatchPadArgs,
1057 Twine("catchpad.for.", NameSuffix), CatchPadBB);
1058 new UnreachableInst(F.getContext(), CatchPadBB);
1059
1060 CatchSwitch->addHandler(CatchPadBB);
1061
1062 return CatchSwitch;
1063 };
1064
1065 // Look for all basic blocks which are within cleanups which are postdominated
1066 // by unreachable.
1067 for (auto &Funclets : FuncletBlocks) {
1068 BasicBlock *FuncletPadBB = Funclets.first;
1069 auto *CleanupPad = dyn_cast(FuncletPadBB->getFirstNonPHI());
1070 // Skip over any non-cleanup funclets.
1071 if (!CleanupPad)
1072 continue;
1073 // Skip over any cleanups have unwind targets, they do not need this.
1074 if (any_of(CleanupPad->users(),
1075 [](const User *U) { return isa(U); }))
1076 continue;
1077 // Walk the blocks within the cleanup which end in 'unreachable'.
1078 // We will replace the unreachable instruction with a cleanupret;
1079 // this cleanupret will unwind to a catchswitch with a lone catch-all
1080 // catchpad.
1081 std::vector &BlocksInFunclet = Funclets.second;
1082 for (BasicBlock *BB : BlocksInFunclet) {
1083 auto *UI = dyn_cast(BB->getTerminator());
1084 if (!UI)
1085 continue;
1086 // Remove the unreachable instruction.
1087 UI->eraseFromParent();
1088
1089 // Add our new cleanupret.
1090 auto *ParentPad = CleanupPad->getParentPad();
1091 CatchSwitchInst *CatchSwitch = GetOrCreateCatchSwitch(ParentPad);
1092 CleanupReturnInst::Create(CleanupPad, CatchSwitch->getParent(), BB);
1093 }
1094 }
1095
1096 // Update BlockColors and FuncletBlocks to maintain WinEHPrepare's
1097 // invariants.
1098 for (auto CatchSwitchKV : NewCatchSwitches) {
1099 CatchSwitchInst *CatchSwitch = CatchSwitchKV.second;
1100 BasicBlock *CatchSwitchBB = CatchSwitch->getParent();
1101
1102 assert(CatchSwitch->getNumSuccessors() == 1);
1103 BasicBlock *CatchPadBB = CatchSwitch->getSuccessor(0);
1104 assert(isa(CatchPadBB->getFirstNonPHI()));
1105
1106 BlockColors.insert({CatchSwitchBB, ColorVector(CatchSwitchBB)});
1107 FuncletBlocks[CatchSwitchBB] = {CatchSwitchBB};
1108
1109 BlockColors.insert({CatchPadBB, ColorVector(CatchPadBB)});
1110 FuncletBlocks[CatchPadBB] = {CatchPadBB};
1111 }
1112 }
1113
11141003 void WinEHPrepare::verifyPreparedFunclets(Function &F) {
11151004 for (BasicBlock &BB : F) {
11161005 size_t NumColors = BlockColors[&BB].size();
11451034 DEBUG(verifyFunction(F));
11461035 cleanupPreparedFunclets(F);
11471036 }
1148
1149 fixupNoReturnCleanupPads(F);
11501037
11511038 DEBUG(verifyPreparedFunclets(F));
11521039 // Recolor the CFG to verify that all is well.
+0
-95
test/CodeGen/WinEH/wineh-cleanuppad-nounwind.ll less more
None ; RUN: opt -S -winehprepare < %s | FileCheck %s
1 target triple = "x86_64-pc-windows-msvc"
2
3 ; CHECK-LABEL: @test1(
4 define void @test1(i1 %b) personality i32 (...)* @__CxxFrameHandler3 {
5 entry:
6 invoke void @f()
7 to label %try.cont unwind label %cleanup.bb
8
9 ; CHECK: entry:
10
11 ; CHECK: [[catchswitch_entry:.*]]:
12 ; CHECK-NEXT: %[[cs0:.*]] = catchswitch within none [label %[[catchpad:.*]]] unwind to caller
13 ; CHECK: [[catchpad]]:
14 ; CHECK-NEXT: %[[cp0:.*]] = catchpad within %[[cs0]] [i8* null, i32 64, i8* null]
15 ; CHECK-NEXT: unreachable
16
17 try.cont:
18 invoke void @f()
19 to label %exit unwind label %catchswitch.bb
20
21 cleanup.bb:
22 %cleanup = cleanuppad within none []
23 br i1 %b, label %left, label %right
24
25 left:
26 call void @exit(i32 0) [ "funclet"(token %cleanup) ]
27 unreachable
28
29 right:
30 call void @exit(i32 1) [ "funclet"(token %cleanup) ]
31 unreachable
32
33 catchswitch.bb:
34 %cs = catchswitch within none [label %catchpad.bb] unwind to caller
35
36 ; CHECK: catchpad.bb:
37 ; CHECK-NEXT: %catch = catchpad within %cs [i8* null, i32 64, i8* null]
38
39 ; CHECK: [[catchswitch_catch:.*]]:
40 ; CHECK-NEXT: %[[cs1:.*]] = catchswitch within %catch [label %[[catchpad_catch:.*]]] unwind to caller
41 ; CHECK: [[catchpad_catch]]:
42 ; CHECK-NEXT: %[[cp1:.*]] = catchpad within %[[cs1]] [i8* null, i32 64, i8* null]
43 ; CHECK-NEXT: unreachable
44
45 ; CHECK: nested.cleanup.bb:
46 ; CHECK-NEXT: %nested.cleanup = cleanuppad within %catch []
47 ; CHECK-NEXT: call void @exit(i32 2) [ "funclet"(token %nested.cleanup) ]
48 ; CHECK-NEXT: cleanupret from %nested.cleanup unwind label %[[catchswitch_catch]]
49
50 catchpad.bb:
51 %catch = catchpad within %cs [i8* null, i32 64, i8* null]
52 invoke void @f() [ "funclet"(token %catch) ]
53 to label %unreachable unwind label %nested.cleanup.bb
54
55 nested.cleanup.bb:
56 %nested.cleanup = cleanuppad within %catch []
57 call void @exit(i32 2) [ "funclet"(token %nested.cleanup) ]
58 unreachable
59
60 unreachable:
61 unreachable
62
63 exit:
64 unreachable
65 }
66
67 ; CHECK-LABEL: @test2(
68 define void @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
69 entry:
70 invoke void @f()
71 to label %invoke.cont unwind label %ehcleanup
72
73 invoke.cont:
74 unreachable
75
76 ehcleanup:
77 %cp = cleanuppad within none []
78 br i1 %B, label %ret, label %if.then
79
80 if.then:
81 call void @exit(i32 1) [ "funclet"(token %cp) ]
82 unreachable
83
84 ret:
85 cleanupret from %cp unwind to caller
86 }
87
88 ; CHECK: call void @exit(i32 1) [ "funclet"(token %cp) ]
89 ; CHECK-NEXT: unreachable
90
91 declare void @f()
92 declare void @exit(i32) nounwind noreturn
93
94 declare i32 @__CxxFrameHandler3(...)
4343 ; CHECK: call void @llvm.foo(i32 %x)
4444
4545
46 define void @test2() personality i32 (...)* @__C_specific_handler {
46 define void @test2() personality i32 (...)* @__CxxFrameHandler3 {
4747 entry:
4848 invoke void @f()
4949 to label %exit unwind label %cleanup
7070 ; CHECK-NEXT: ret void
7171
7272
73 define void @test3() personality i32 (...)* @__C_specific_handler {
73 define void @test3() personality i32 (...)* @__CxxFrameHandler3 {
7474 entry:
7575 invoke void @f()
7676 to label %invoke.cont unwind label %catch.switch
0 ; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare < %s | FileCheck %s
11
22 declare i32 @__CxxFrameHandler3(...)
3 declare i32 @__C_specific_handler(...)
43
54 declare void @f()
65
327326 }
328327
329328 ; CHECK-LABEL: @test8(
330 define void @test8() personality i32 (...)* @__C_specific_handler { entry:
329 define void @test8() personality i32 (...)* @__CxxFrameHandler3 { entry:
331330 invoke void @f()
332331 to label %done unwind label %cleanup1
333332 invoke void @f()
None ; RUN: opt -mtriple=x86_64-pc-windows-msvc -S -winehprepare -disable-demotion -disable-cleanups < %s | FileCheck %s
0 ; RUN: opt -mtriple=x86_x64-pc-windows-msvc -S -winehprepare -disable-demotion -disable-cleanups < %s | FileCheck %s
11
22 declare i32 @__CxxFrameHandler3(...)
33