llvm.org GIT mirror llvm / 68754da
[WinEH] Make FuncletLayout more robust against catchret Catchret transfers control from a catch funclet to an earlier funclet. However, it is not completely clear which funclet the catchret target is part of. Make this clear by stapling the catchret target's funclet membership onto the CATCHRET SDAG node. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249052 91177308-0d34-0410-b5e6-96231b3b80d8 David Majnemer 4 years ago
13 changed file(s) with 252 addition(s) and 53 deletion(s). Raw diff Collapse all Expand all
160160
161161 struct WinEHFuncInfo {
162162 DenseMap EHPadStateMap;
163 DenseMap
164 CatchRetSuccessorColorMap;
163165 DenseMap> InvokeToStateMap;
164166 SmallVector UnwindMap;
165167 SmallVector TryBlockMap;
190192
191193 void calculateSEHStateNumbers(const Function *ParentFn,
192194 WinEHFuncInfo &FuncInfo);
195
196 void calculateCatchReturnSuccessorColors(const Function *Fn,
197 WinEHFuncInfo &FuncInfo);
193198 }
194199 #endif // LLVM_CODEGEN_WINEHFUNCINFO_H
5353 TargetInstrInfo(const TargetInstrInfo &) = delete;
5454 void operator=(const TargetInstrInfo &) = delete;
5555 public:
56 TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u)
57 : CallFrameSetupOpcode(CFSetupOpcode),
58 CallFrameDestroyOpcode(CFDestroyOpcode) {
59 }
56 TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u,
57 unsigned CatchRetOpcode = ~0u)
58 : CallFrameSetupOpcode(CFSetupOpcode),
59 CallFrameDestroyOpcode(CFDestroyOpcode),
60 CatchRetOpcode(CatchRetOpcode) {}
6061
6162 virtual ~TargetInstrInfo();
6263
144145 ///
145146 unsigned getCallFrameSetupOpcode() const { return CallFrameSetupOpcode; }
146147 unsigned getCallFrameDestroyOpcode() const { return CallFrameDestroyOpcode; }
148
149 unsigned getCatchReturnOpcode() const { return CatchRetOpcode; }
147150
148151 /// Returns the actual stack pointer adjustment made by an instruction
149152 /// as part of a call sequence. By default, only call frame setup/destroy
13971400
13981401 private:
13991402 unsigned CallFrameSetupOpcode, CallFrameDestroyOpcode;
1403 unsigned CatchRetOpcode;
14001404 };
14011405
14021406 /// \brief Provide DenseMapInfo for TargetInstrInfo::RegSubRegPair.
183183
184184 def SDTBrind : SDTypeProfile<0, 1, [ // brind
185185 SDTCisPtrTy<0>
186 ]>;
187
188 def SDTCatchret : SDTypeProfile<0, 2, [ // catchret
189 SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>
186190 ]>;
187191
188192 def SDTNone : SDTypeProfile<0, 0, []>; // ret, trap
450454 def brcond : SDNode<"ISD::BRCOND" , SDTBrcond, [SDNPHasChain]>;
451455 def brind : SDNode<"ISD::BRIND" , SDTBrind, [SDNPHasChain]>;
452456 def br : SDNode<"ISD::BR" , SDTBr, [SDNPHasChain]>;
453 def catchret : SDNode<"ISD::CATCHRET" , SDTBr, [SDNPHasChain]>;
457 def catchret : SDNode<"ISD::CATCHRET" , SDTCatchret, [SDNPHasChain]>;
454458 def cleanupret : SDNode<"ISD::CLEANUPRET" , SDTNone, [SDNPHasChain]>;
455459
456460 def trap : SDNode<"ISD::TRAP" , SDTNone,
1515 #include "llvm/CodeGen/MachineFunction.h"
1616 #include "llvm/CodeGen/MachineFunctionPass.h"
1717 #include "llvm/CodeGen/MachineModuleInfo.h"
18 #include "llvm/Target/TargetInstrInfo.h"
19 #include "llvm/Target/TargetSubtargetInfo.h"
1820 using namespace llvm;
1921
2022 #define DEBUG_TYPE "funclet-layout"
3537 collectFuncletMembers(DenseMap &FuncletMembership,
3638 int Funclet, MachineBasicBlock *MBB) {
3739 // Don't revisit blocks.
38 if (FuncletMembership.count(MBB) > 0)
40 if (FuncletMembership.count(MBB) > 0) {
41 // FIXME: This is a hack, we need to assert this unconditionally.
42 bool IsProbablyUnreachableBlock =
43 MBB->empty() ||
44 (MBB->succ_empty() && !MBB->getFirstTerminator()->isReturn() &&
45 MBB->size() == 1);
46
47 if (!IsProbablyUnreachableBlock) {
48 if (FuncletMembership[MBB] != Funclet) {
49 assert(false && "MBB is part of two funclets!");
50 report_fatal_error("MBB is part of two funclets!");
51 }
52 }
3953 return;
54 }
4055
4156 // Add this MBB to our funclet.
4257 FuncletMembership[MBB] = Funclet;
7085 if (!F.getMMI().hasEHFunclets())
7186 return false;
7287
88 const TargetInstrInfo *TII = F.getSubtarget().getInstrInfo();
7389 SmallVector FuncletBlocks;
74 for (MachineBasicBlock &MBB : F)
90 SmallVector, 16> CatchRetSuccessors;
91 for (MachineBasicBlock &MBB : F) {
7592 if (MBB.isEHFuncletEntry())
7693 FuncletBlocks.push_back(&MBB);
94
95 MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator();
96 if (MBBI->getOpcode() != TII->getCatchReturnOpcode())
97 continue;
98
99 MachineBasicBlock *Successor = MBBI->getOperand(0).getMBB();
100 MachineBasicBlock *SuccessorColor = MBBI->getOperand(1).getMBB();
101 CatchRetSuccessors.push_back({Successor, SuccessorColor->getNumber()});
102 }
77103
78104 // We don't have anything to do if there aren't any EH pads.
79105 if (FuncletBlocks.empty())
80106 return false;
81107
82108 DenseMap FuncletMembership;
109 // Identify all the basic blocks reachable from the function entry.
110 collectFuncletMembers(FuncletMembership, F.front().getNumber(), F.begin());
111 // Next, identify all the blocks inside the funclets.
83112 for (MachineBasicBlock *MBB : FuncletBlocks)
84113 collectFuncletMembers(FuncletMembership, MBB->getNumber(), MBB);
114 // Finally, identify all the targets of a catchret.
115 for (std::pair CatchRetPair : CatchRetSuccessors)
116 collectFuncletMembers(FuncletMembership, CatchRetPair.second,
117 CatchRetPair.first);
85118
86119 F.sort([&](MachineBasicBlock &x, MachineBasicBlock &y) {
87120 return FuncletMembership[&x] < FuncletMembership[&y];
289289 const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
290290 if (Personality == EHPersonality::MSVC_CXX)
291291 calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
292 else
292 else if (isAsynchronousEHPersonality(Personality))
293293 calculateSEHStateNumbers(WinEHParentFn, EHInfo);
294
295 calculateCatchReturnSuccessorColors(WinEHParentFn, EHInfo);
294296
295297 // Map all BB references in the WinEH data to MBBs.
296298 for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
11671167 MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()];
11681168 FuncInfo.MBB->addSuccessor(TargetMBB);
11691169
1170 // Figure out the funclet membership for the catchret's successor.
1171 // This will be used by the FuncletLayout pass to determine how to order the
1172 // BB's.
1173 MachineModuleInfo &MMI = DAG.getMachineFunction().getMMI();
1174 WinEHFuncInfo &EHInfo =
1175 MMI.getWinEHFuncInfo(DAG.getMachineFunction().getFunction());
1176 const BasicBlock *SuccessorColor = EHInfo.CatchRetSuccessorColorMap[&I];
1177 assert(SuccessorColor && "No parent funclet for catchret!");
1178 MachineBasicBlock *SuccessorColorMBB = FuncInfo.MBBMap[SuccessorColor];
1179 assert(SuccessorColorMBB && "No MBB for SuccessorColor!");
1180
11701181 // Create the terminator node.
11711182 SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other,
1172 getControlRoot(), DAG.getBasicBlock(TargetMBB));
1183 getControlRoot(), DAG.getBasicBlock(TargetMBB),
1184 DAG.getBasicBlock(SuccessorColorMBB));
11731185 DAG.setRoot(Ret);
11741186 }
11751187
398398 return new WinEHPrepare(TM);
399399 }
400400
401 bool WinEHPrepare::runOnFunction(Function &Fn) {
402 if (!Fn.hasPersonalityFn())
403 return false;
404
405 // No need to prepare outlined handlers.
406 if (Fn.hasFnAttribute("wineh-parent"))
407 return false;
408
409 // Classify the personality to see what kind of preparation we need.
410 Personality = classifyEHPersonality(Fn.getPersonalityFn());
411
412 // Do nothing if this is not an MSVC personality.
413 if (!isMSVCEHPersonality(Personality))
414 return false;
415
416 SmallVector LPads;
417 SmallVector Resumes;
418 SmallVector EntryBlocks;
401 static bool
402 findExceptionalConstructs(Function &Fn,
403 SmallVectorImpl &LPads,
404 SmallVectorImpl &Resumes,
405 SmallVectorImpl &EntryBlocks) {
419406 bool ForExplicitEH = false;
420407 for (BasicBlock &BB : Fn) {
421408 Instruction *First = BB.getFirstNonPHI();
431418 if (auto *Resume = dyn_cast(BB.getTerminator()))
432419 Resumes.push_back(Resume);
433420 }
421 return ForExplicitEH;
422 }
423
424 bool WinEHPrepare::runOnFunction(Function &Fn) {
425 if (!Fn.hasPersonalityFn())
426 return false;
427
428 // No need to prepare outlined handlers.
429 if (Fn.hasFnAttribute("wineh-parent"))
430 return false;
431
432 // Classify the personality to see what kind of preparation we need.
433 Personality = classifyEHPersonality(Fn.getPersonalityFn());
434
435 // Do nothing if this is not an MSVC personality.
436 if (!isMSVCEHPersonality(Personality))
437 return false;
438
439 SmallVector LPads;
440 SmallVector Resumes;
441 SmallVector EntryBlocks;
442 bool ForExplicitEH =
443 findExceptionalConstructs(Fn, LPads, Resumes, EntryBlocks);
434444
435445 if (ForExplicitEH)
436446 return prepareExplicitEH(Fn, EntryBlocks);
28772887 }
28782888 }
28792889
2880 void WinEHPrepare::colorFunclets(Function &F,
2881 SmallVectorImpl &EntryBlocks) {
2890 static void
2891 colorFunclets(Function &F, SmallVectorImpl &EntryBlocks,
2892 std::map> &BlockColors,
2893 std::map> &FuncletBlocks,
2894 std::map> &FuncletChildren) {
28822895 SmallVector, 16> Worklist;
28832896 BasicBlock *EntryBlock = &F.getEntryBlock();
28842897
29722985 FuncletChildren[Parent].insert(FuncletEntry);
29732986 ColorMapItem.clear();
29742987 ColorMapItem.insert(FuncletEntry);
2988 }
2989 }
2990
2991 void WinEHPrepare::colorFunclets(Function &F,
2992 SmallVectorImpl &EntryBlocks) {
2993 ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks, FuncletChildren);
2994 }
2995
2996 void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
2997 WinEHFuncInfo &FuncInfo) {
2998 SmallVector LPads;
2999 SmallVector Resumes;
3000 SmallVector EntryBlocks;
3001 // colorFunclets needs the set of EntryBlocks, get them using
3002 // findExceptionalConstructs.
3003 bool ForExplicitEH = findExceptionalConstructs(const_cast(*Fn),
3004 LPads, Resumes, EntryBlocks);
3005 if (!ForExplicitEH)
3006 return;
3007
3008 std::map> BlockColors;
3009 std::map> FuncletBlocks;
3010 std::map> FuncletChildren;
3011 // Figure out which basic blocks belong to which funclets.
3012 colorFunclets(const_cast(*Fn), EntryBlocks, BlockColors,
3013 FuncletBlocks, FuncletChildren);
3014
3015 // We need to find the catchret successors. To do this, we must first find
3016 // all the catchpad funclets.
3017 for (auto &Funclet : FuncletBlocks) {
3018 // Figure out what kind of funclet we are looking at; We only care about
3019 // catchpads.
3020 BasicBlock *FuncletPadBB = Funclet.first;
3021 Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI();
3022 auto *CatchPad = dyn_cast(FirstNonPHI);
3023 if (!CatchPad)
3024 continue;
3025
3026 // The users of a catchpad are always catchrets.
3027 for (User *Exit : CatchPad->users()) {
3028 auto *CatchReturn = cast(Exit);
3029 BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor();
3030 std::set &SuccessorColors = BlockColors[CatchRetSuccessor];
3031 assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!");
3032 BasicBlock *Color = *SuccessorColors.begin();
3033 if (auto *CPI = dyn_cast(Color->getFirstNonPHI()))
3034 Color = CPI->getNormalDest();
3035 // Record the catchret successor's funclet membership.
3036 FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color;
3037 }
29753038 }
29763039 }
29773040
11191119 BuildMI(*RestoreMBB, RestoreMBBI, DL, TII.get(X86::JMP_4))
11201120 .addMBB(TargetMBB);
11211121 }
1122 // Replace CATCHRET with the appropriate RET.
1123 unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
1124 MachineBasicBlock::iterator NewExit =
1125 BuildMI(MBB, MBBI, DL, TII.get(RetOp)).addReg(ReturnReg);
1126 MBBI->eraseFromParent();
1127 MBBI = NewExit;
11281122 } else if (MBBI->getOpcode() == X86::CLEANUPRET) {
11291123 NumBytes = MFI->getMaxCallFrameSize();
11301124 assert(hasFP(MF) && "EH funclets without FP not yet implemented");
11311125 BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r),
11321126 MachineFramePtr)
11331127 .setMIFlag(MachineInstr::FrameDestroy);
1134 // Replace CLEANUPRET with the appropriate RET.
1135 unsigned RetOp = STI.is64Bit() ? X86::RETQ : X86::RETL;
1136 MachineBasicBlock::iterator NewExit =
1137 BuildMI(MBB, MBBI, DL, TII.get(RetOp));
1138 MBBI->eraseFromParent();
1139 MBBI = NewExit;
11401128 } else if (hasFP(MF)) {
11411129 // Calculate required stack adjustment.
11421130 uint64_t FrameSize = StackSize - SlotSize;
151151
152152 }
153153
154 let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
155 def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst),
156 "# CATCHRET",
157 [(catchret bb:$dst)]>;
154 let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in {
155 def CATCHRET : I<0, Pseudo, (outs), (ins brtarget32:$dst, brtarget32:$from),
156 "# CATCHRET",
157 [(catchret bb:$dst, bb:$from)]>;
158158 def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
159159 }
160160
100100 void X86InstrInfo::anchor() {}
101101
102102 X86InstrInfo::X86InstrInfo(X86Subtarget &STI)
103 : X86GenInstrInfo(
104 (STI.isTarget64BitLP64() ? X86::ADJCALLSTACKDOWN64 : X86::ADJCALLSTACKDOWN32),
105 (STI.isTarget64BitLP64() ? X86::ADJCALLSTACKUP64 : X86::ADJCALLSTACKUP32)),
103 : X86GenInstrInfo((STI.isTarget64BitLP64() ? X86::ADJCALLSTACKDOWN64
104 : X86::ADJCALLSTACKDOWN32),
105 (STI.isTarget64BitLP64() ? X86::ADJCALLSTACKUP64
106 : X86::ADJCALLSTACKUP32),
107 X86::CATCHRET),
106108 Subtarget(STI), RI(STI.getTargetTriple()) {
107109
108110 static const X86MemoryFoldTableEntry MemoryFoldTable2Addr[] = {
527527 case X86::EH_RETURN64: {
528528 OutMI = MCInst();
529529 OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
530 break;
531 }
532
533 case X86::CLEANUPRET: {
534 // Replace CATCHRET with the appropriate RET.
535 OutMI = MCInst();
536 OutMI.setOpcode(getRetOpcode(AsmPrinter.getSubtarget()));
537 break;
538 }
539
540 case X86::CATCHRET: {
541 // Replace CATCHRET with the appropriate RET.
542 const X86Subtarget &Subtarget = AsmPrinter.getSubtarget();
543 unsigned ReturnReg = Subtarget.is64Bit() ? X86::RAX : X86::EAX;
544 OutMI = MCInst();
545 OutMI.setOpcode(getRetOpcode(Subtarget));
546 OutMI.addOperand(MCOperand::createReg(ReturnReg));
530547 break;
531548 }
532549
10751092 X86ATTInstPrinter::getRegisterName(Reg));
10761093 break;
10771094 }
1095 case X86::CLEANUPRET: {
1096 // Lower these as normal, but add some comments.
1097 OutStreamer->AddComment("CLEANUPRET");
1098 break;
1099 }
1100
1101 case X86::CATCHRET: {
1102 // Lower these as normal, but add some comments.
1103 OutStreamer->AddComment("CATCHRET");
1104 break;
1105 }
1106
10781107 case X86::TAILJMPr:
10791108 case X86::TAILJMPm:
10801109 case X86::TAILJMPd:
22 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
33 target triple = "x86_64-pc-windows-msvc"
44
5 define void @f(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
5 %eh.ThrowInfo = type { i32, i32, i32, i32 }
6
7 define void @test1(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
68 entry:
79 invoke void @g()
810 to label %unreachable unwind label %catch.dispatch
2729 unreachable
2830 }
2931
30 ; CHECK-LABEL: f:
32 ; CHECK-LABEL: test1:
3133
3234 ; The entry funclet contains %entry and %try.cont
3335 ; CHECK: # %entry
4143
4244 declare void @g()
4345
46
47 define i32 @test2(i1 %B) personality i32 (...)* @__CxxFrameHandler3 {
48 entry:
49 invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
50 to label %unreachable unwind label %catch.dispatch
51
52 catch.dispatch: ; preds = %entry
53 %0 = catchpad [i8* null, i32 64, i8* null]
54 to label %catch unwind label %catchendblock
55
56 catch: ; preds = %catch.dispatch
57 invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null) #1
58 to label %unreachable unwind label %catch.dispatch.1
59
60 catch.dispatch.1: ; preds = %catch
61 %1 = catchpad [i8* null, i32 64, i8* null]
62 to label %catch.3 unwind label %catchendblock.2
63
64 catch.3: ; preds = %catch.dispatch.1
65 catchret %1 to label %try.cont
66
67 try.cont: ; preds = %catch.3
68 catchret %0 to label %try.cont.5
69
70 try.cont.5: ; preds = %try.cont
71 ret i32 0
72
73 catchendblock.2: ; preds = %catch.dispatch.1
74 catchendpad unwind label %catchendblock
75
76 catchendblock: ; preds = %catchendblock.2, %catch.dispatch
77 catchendpad unwind to caller
78
79 unreachable: ; preds = %catch, %entry
80 unreachable
81
82 }
83
84 ; CHECK-LABEL: test2:
85
86 ; The entry funclet contains %entry and %try.cont.5
87 ; CHECK: # %entry
88 ; CHECK: # %try.cont.5
89 ; CHECK: retq
90
91 ; The inner catch funclet contains %catch.3
92 ; CHECK: # %catch.3
93 ; CHECK: retq
94
95 ; The outer catch funclet contains %catch and %try.cont
96 ; CHECK: # %catch
97 ; CHECK: # %try.cont
98 ; CHECK: retq
99
100 declare void @_CxxThrowException(i8*, %eh.ThrowInfo*)
44101 declare i32 @__CxxFrameHandler3(...)
429429 OS << "namespace llvm {\n";
430430 OS << "struct " << ClassName << " : public TargetInstrInfo {\n"
431431 << " explicit " << ClassName
432 << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1);\n"
432 << "(int CFSetupOpcode = -1, int CFDestroyOpcode = -1, int CatchRetOpcode = -1);\n"
433433 << " ~" << ClassName << "() override {}\n"
434434 << "};\n";
435435 OS << "} // end llvm namespace \n";
444444 OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n";
445445 OS << "extern const char " << TargetName << "InstrNameData[];\n";
446446 OS << ClassName << "::" << ClassName
447 << "(int CFSetupOpcode, int CFDestroyOpcode)\n"
448 << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode) {\n"
447 << "(int CFSetupOpcode, int CFDestroyOpcode, int CatchRetOpcode)\n"
448 << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode) {\n"
449449 << " InitMCInstrInfo(" << TargetName << "Insts, " << TargetName
450450 << "InstrNameIndices, " << TargetName << "InstrNameData, "
451451 << NumberedInstructions.size() << ");\n}\n";