41 #define DEBUG_TYPE "winehprepare"
46 "Clone multicolor basic blocks but do not demote cross scopes"),
51 cl::desc(
"Do not remove implausible terminators or other similar cleanups"),
63 WinEHPrepare(
bool DemoteCatchSwitchPHIOnly =
false)
64 :
FunctionPass(
ID), DemoteCatchSwitchPHIOnly(DemoteCatchSwitchPHIOnly) {}
68 bool doFinalization(
Module &M)
override;
73 return "Windows exception handling preparation";
87 void demotePHIsOnFunclets(
Function &
F,
bool DemoteCatchSwitchPHIOnly);
89 void removeImplausibleInstructions(
Function &
F);
90 void cleanupPreparedFunclets(
Function &
F);
93 bool DemoteCatchSwitchPHIOnly;
110 return new WinEHPrepare(DemoteCatchSwitchPHIOnly);
125 return prepareExplicitEH(Fn);
128 bool WinEHPrepare::doFinalization(
Module &M) {
return false; }
130 void WinEHPrepare::getAnalysisUsage(
AnalysisUsage &AU)
const {}
142 int TryHigh,
int CatchHigh,
151 Constant *TypeInfo = cast<Constant>(CPI->getArgOperand(0));
156 HT.
Adjectives = cast<ConstantInt>(CPI->getArgOperand(1))->getZExtValue();
159 dyn_cast<AllocaInst>(CPI->getArgOperand(2)->stripPointerCasts()))
169 for (
const User *U : CleanupPad->
users())
170 if (
const auto *CRI = dyn_cast<CleanupReturnInst>(U))
171 return CRI->getUnwindDest();
180 auto *II = dyn_cast<InvokeInst>(
BB.getTerminator());
184 auto &BBColors = BlockColors[&
BB];
185 assert(BBColors.size() == 1 &&
"multi-color BB not removed by preparation");
193 FuncletUnwindDest =
nullptr;
194 else if (
auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPad))
195 FuncletUnwindDest = CatchPad->getCatchSwitch()->getUnwindDest();
196 else if (
auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPad))
201 BasicBlock *InvokeUnwindDest = II->getUnwindDest();
203 if (FuncletUnwindDest == InvokeUnwindDest) {
206 BaseState = BaseStateI->second;
209 if (BaseState != -1) {
224 if (isa<InvokeInst>(TI))
226 if (
auto *CatchSwitch = dyn_cast<CatchSwitchInst>(TI)) {
227 if (CatchSwitch->getParentPad() != ParentPad)
232 auto *CleanupPad = cast<CleanupReturnInst>(TI)->getCleanupPad();
233 if (CleanupPad->getParentPad() != ParentPad)
235 return CleanupPad->getParent();
245 assert(
BB->isEHPad() &&
"not a funclet!");
247 if (
auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) {
249 "shouldn't revist catch funclets!");
252 for (
const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
253 auto *CatchPad = cast<CatchPadInst>(CatchPadBB->getFirstNonPHI());
254 Handlers.push_back(CatchPad);
260 CatchSwitch->getParentPad())))
266 int TryHigh = CatchLow - 1;
275 unsigned TBMEIdx = FuncInfo.
TryBlockMap.size() - 1;
277 for (
const auto *CatchPad : Handlers) {
279 for (
const User *U : CatchPad->
users()) {
280 const auto *UserI = cast<Instruction>(U);
281 if (
auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) {
282 BasicBlock *UnwindDest = InnerCatchSwitch->getUnwindDest();
283 if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest())
286 if (
auto *InnerCleanupPad = dyn_cast<CleanupPadInst>(UserI)) {
291 if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest())
299 FuncInfo.
TryBlockMap[TBMEIdx].CatchHigh = CatchHigh;
303 LLVM_DEBUG(
dbgs() <<
"TryLow[" <<
BB->getName() <<
"]: " << TryLow <<
'\n');
309 auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI);
318 LLVM_DEBUG(
dbgs() <<
"Assigning state #" << CleanupState <<
" to BB "
319 <<
BB->getName() <<
'\n');
322 CleanupPad->getParentPad()))) {
327 for (
const User *U : CleanupPad->
users()) {
328 const auto *UserI = cast<Instruction>(U);
329 if (UserI->isEHPad())
331 "contain exceptional actions");
339 Entry.ToState = ParentState;
340 Entry.IsFinally =
false;
342 Entry.Handler = Handler;
350 Entry.ToState = ParentState;
351 Entry.IsFinally =
true;
352 Entry.Filter =
nullptr;
353 Entry.Handler = Handler;
365 assert(
BB->isEHPad() &&
"no a funclet!");
367 if (
auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) {
369 "shouldn't revist catch funclets!");
373 assert(CatchSwitch->getNumHandlers() == 1 &&
374 "SEH doesn't have multiple handlers per __try");
375 const auto *CatchPad =
376 cast<CatchPadInst>((*CatchSwitch->handler_begin())->getFirstNonPHI());
379 cast<Constant>(CatchPad->getArgOperand(0)->stripPointerCasts());
382 "unexpected filter value");
388 << CatchPadBB->
getName() <<
'\n');
391 CatchSwitch->getParentPad())))
397 for (
const User *U : CatchPad->
users()) {
398 const auto *UserI = cast<Instruction>(U);
399 if (
auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) {
400 BasicBlock *UnwindDest = InnerCatchSwitch->getUnwindDest();
401 if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest())
404 if (
auto *InnerCleanupPad = dyn_cast<CleanupPadInst>(UserI)) {
409 if (!UnwindDest || UnwindDest == CatchSwitch->getUnwindDest())
414 auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI);
423 LLVM_DEBUG(
dbgs() <<
"Assigning state #" << CleanupState <<
" to BB "
424 <<
BB->getName() <<
'\n');
430 for (
const User *U : CleanupPad->
users()) {
431 const auto *UserI = cast<Instruction>(U);
432 if (UserI->isEHPad())
434 "contain exceptional actions");
440 if (
auto *CatchSwitch = dyn_cast<CatchSwitchInst>(EHPad))
441 return isa<ConstantTokenNone>(CatchSwitch->getParentPad()) &&
442 CatchSwitch->unwindsToCaller();
443 if (
auto *CleanupPad = dyn_cast<CleanupPadInst>(EHPad))
444 return isa<ConstantTokenNone>(CleanupPad->getParentPad()) &&
446 if (isa<CatchPadInst>(EHPad))
491 Entry.HandlerParentState = HandlerParentState;
492 Entry.TryParentState = TryParentState;
493 Entry.Handler = Handler;
494 Entry.HandlerType = HandlerType;
495 Entry.TypeToken = TypeToken;
533 const Value *ParentPad;
534 if (
const auto *CPI = dyn_cast<CleanupPadInst>(FirstNonPHI))
535 ParentPad = CPI->getParentPad();
536 else if (
const auto *CSI = dyn_cast<CatchSwitchInst>(FirstNonPHI))
537 ParentPad = CSI->getParentPad();
540 if (isa<ConstantTokenNone>(ParentPad))
550 while (!Worklist.empty()) {
552 int HandlerParentState;
553 std::tie(Pad, HandlerParentState) = Worklist.
pop_back_val();
555 if (
const auto *
Cleanup = dyn_cast<CleanupPadInst>(Pad)) {
565 if (
const auto *
I = dyn_cast<Instruction>(U))
573 const auto *CatchSwitch = cast<CatchSwitchInst>(Pad);
574 int CatchState = -1, FollowerState = -1;
579 const auto *
Catch = cast<CatchPadInst>(CatchBlock->getFirstNonPHI());
581 cast<ConstantInt>(
Catch->getArgOperand(0))->getZExtValue());
587 if (
const auto *
I = dyn_cast<Instruction>(U))
592 FollowerState = CatchState;
595 assert(CatchSwitch->getNumHandlers());
605 Entry.Handler.get<
const BasicBlock *>()->getFirstNonPHI();
609 if (
const auto *
Catch = dyn_cast<CatchPadInst>(Pad)) {
615 if (Entry.TryParentState != -1)
618 UnwindDest =
Catch->getCatchSwitch()->getUnwindDest();
620 const auto *
Cleanup = cast<CleanupPadInst>(Pad);
621 UnwindDest =
nullptr;
623 if (
auto *CleanupRet = dyn_cast<CleanupReturnInst>(U)) {
626 UnwindDest = CleanupRet->getUnwindDest();
632 if (
auto *Invoke = dyn_cast<InvokeInst>(U)) {
633 UserUnwindDest = Invoke->getUnwindDest();
634 }
else if (
auto *CatchSwitch = dyn_cast<CatchSwitchInst>(U)) {
635 UserUnwindDest = CatchSwitch->getUnwindDest();
636 }
else if (
auto *ChildCleanup = dyn_cast<CleanupPadInst>(U)) {
638 int UserUnwindState =
640 if (UserUnwindState != -1)
655 const Value *UserUnwindParent;
656 if (
auto *CSI = dyn_cast<CatchSwitchInst>(UserUnwindPad))
657 UserUnwindParent = CSI->getParentPad();
660 cast<CleanupPadInst>(UserUnwindPad)->getParentPad();
664 if (UserUnwindParent ==
Cleanup)
668 UnwindDest = UserUnwindDest;
687 UnwindDestState = -1;
692 Entry.TryParentState = UnwindDestState;
699 void WinEHPrepare::colorFunclets(
Function &
F) {
710 void WinEHPrepare::demotePHIsOnFunclets(
Function &
F,
711 bool DemoteCatchSwitchPHIOnly) {
717 if (DemoteCatchSwitchPHIOnly && !isa<CatchSwitchInst>(
BB.getFirstNonPHI()))
721 auto *PN = dyn_cast<PHINode>(&
I);
728 insertPHIStores(PN, SpillSlot);
730 PHINodes.push_back(PN);
734 for (
auto *PN : PHINodes) {
737 PN->eraseFromParent();
741 void WinEHPrepare::cloneCommonBlocks(
Function &
F) {
745 for (
auto &Funclets : FuncletBlocks) {
747 std::vector<BasicBlock *> &BlocksInFunclet = Funclets.second;
749 if (FuncletPadBB == &
F.getEntryBlock())
754 std::vector<std::pair<BasicBlock *, BasicBlock *>> Orig2Clone;
759 size_t NumColorsForBB = ColorsForBB.
size();
760 if (NumColorsForBB == 1)
764 dbgs() <<
" Cloning block \'" <<
BB->getName()
765 <<
"\' for funclet \'" << FuncletPadBB->
getName()
779 Orig2Clone.emplace_back(
BB, CBB);
783 if (Orig2Clone.empty())
788 for (
auto &BBMapping : Orig2Clone) {
792 BlocksInFunclet.push_back(NewBlock);
794 assert(NewColors.
empty() &&
"A new block should only have one color!");
798 dbgs() <<
" Assigned color \'" << FuncletPadBB->
getName()
799 <<
"\' to block \'" << NewBlock->
getName()
807 dbgs() <<
" Removed color \'" << FuncletPadBB->
getName()
808 <<
"\' from block \'" << OldBlock->
getName()
823 for (
auto &BBMapping : Orig2Clone) {
827 FixupCatchrets.
clear();
829 if (
auto *CatchRet = dyn_cast<CatchReturnInst>(Pred->getTerminator()))
830 if (CatchRet->getCatchSwitchParentPad() == FuncletToken)
831 FixupCatchrets.push_back(CatchRet);
834 CatchRet->setSuccessor(NewBlock);
837 auto UpdatePHIOnClonedBlock = [&](
PHINode *PN,
bool IsForOldBlock) {
839 for (
unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd;
842 bool EdgeTargetsFunclet;
845 EdgeTargetsFunclet = (CRI->getCatchSwitchParentPad() == FuncletToken);
847 ColorVector &IncomingColors = BlockColors[IncomingBlock];
848 assert(!IncomingColors.
empty() &&
"Block not colored!");
852 return Color != FuncletPadBB;
854 "Cloning should leave this funclet's blocks monochromatic");
855 EdgeTargetsFunclet = (IncomingColors.
front() == FuncletPadBB);
857 if (IsForOldBlock != EdgeTargetsFunclet)
866 for (
auto &BBMapping : Orig2Clone) {
870 UpdatePHIOnClonedBlock(&OldPN,
true);
873 UpdatePHIOnClonedBlock(&NewPN,
false);
879 for (
auto &BBMapping : Orig2Clone) {
883 for (
PHINode &SuccPN : SuccBB->phis()) {
886 int OldBlockIdx = SuccPN.getBasicBlockIndex(OldBlock);
887 if (OldBlockIdx == -1)
889 Value *
IV = SuccPN.getIncomingValue(OldBlockIdx);
892 if (
auto *Inst = dyn_cast<Instruction>(
IV)) {
898 SuccPN.addIncoming(
IV, NewBlock);
911 auto *OldI = dyn_cast<Instruction>(
const_cast<Value *
>(VT.first));
914 auto *NewI = cast<Instruction>(VT.second);
918 Instruction *UserI = cast<Instruction>(U.getUser());
920 ColorVector &ColorsForUserBB = BlockColors[UserBB];
922 if (ColorsForUserBB.
size() > 1 ||
923 *ColorsForUserBB.
begin() != FuncletPadBB)
924 UsesToRename.push_back(&U);
929 if (UsesToRename.empty())
936 SSAUpdate.
Initialize(OldI->getType(), OldI->getName());
940 while (!UsesToRename.empty())
946 void WinEHPrepare::removeImplausibleInstructions(
Function &
F) {
948 for (
auto &Funclet : FuncletBlocks) {
950 std::vector<BasicBlock *> &BlocksInFunclet = Funclet.second;
952 auto *FuncletPad = dyn_cast<FuncletPadInst>(FirstNonPHI);
953 auto *CatchPad = dyn_cast_or_null<CatchPadInst>(FuncletPad);
954 auto *CleanupPad = dyn_cast_or_null<CleanupPadInst>(FuncletPad);
958 auto *CB = dyn_cast<CallBase>(&
I);
962 Value *FuncletBundleOperand =
nullptr;
964 FuncletBundleOperand = BU->Inputs.front();
966 if (FuncletBundleOperand == FuncletPad)
971 dyn_cast<Function>(CB->getCalledOperand()->stripPointerCasts());
972 if (CalledFn && ((CalledFn->isIntrinsic() && CB->doesNotThrow()) ||
977 if (isa<InvokeInst>(CB)) {
982 std::prev(
BB->getTerminator()->getIterator());
983 auto *CI = cast<CallInst>(&*CallI);
996 bool IsUnreachableRet = isa<ReturnInst>(TI) && FuncletPad;
998 bool IsUnreachableCatchret =
false;
999 if (
auto *CRI = dyn_cast<CatchReturnInst>(TI))
1000 IsUnreachableCatchret = CRI->getCatchPad() != CatchPad;
1002 bool IsUnreachableCleanupret =
false;
1003 if (
auto *CRI = dyn_cast<CleanupReturnInst>(TI))
1004 IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad;
1005 if (IsUnreachableRet || IsUnreachableCatchret ||
1006 IsUnreachableCleanupret) {
1008 }
else if (isa<InvokeInst>(TI)) {
1020 void WinEHPrepare::cleanupPreparedFunclets(
Function &
F) {
1035 void WinEHPrepare::verifyPreparedFunclets(
Function &
F) {
1037 size_t NumColors = BlockColors[&
BB].size();
1038 assert(NumColors == 1 &&
"Expected monochromatic BB!");
1044 "EH Pad still has a PHI!");
1049 bool WinEHPrepare::prepareExplicitEH(
Function &
F) {
1058 cloneCommonBlocks(
F);
1061 demotePHIsOnFunclets(
F, DemoteCatchSwitchPHIOnly ||
1066 removeImplausibleInstructions(
F);
1069 cleanupPreparedFunclets(
F);
1077 BlockColors.clear();
1078 FuncletBlocks.clear();
1095 &
F.getEntryBlock().front());
1107 auto *UsingInst = cast<Instruction>(U.getUser());
1108 if (isa<PHINode>(UsingInst) && UsingInst->getParent()->isEHPad()) {
1113 replaceUseWithLoad(PN, U, SpillSlot, Loads,
F);
1122 void WinEHPrepare::insertPHIStores(
PHINode *OriginalPHI,
1128 Worklist.push_back({OriginalPHI->
getParent(), OriginalPHI});
1130 while (!Worklist.empty()) {
1135 PHINode *PN = dyn_cast<PHINode>(InVal);
1144 if (isa<UndefValue>(PredVal))
1153 insertPHIStore(PredBlock, InVal, SpillSlot, Worklist);
1159 void WinEHPrepare::insertPHIStore(
1165 Worklist.push_back({PredBlock, PredVal});
1180 &
F.getEntryBlock().front());
1182 auto *UsingInst = cast<Instruction>(U.
getUser());
1183 if (
auto *UsingPHI = dyn_cast<PHINode>(UsingInst)) {
1193 BasicBlock *IncomingBlock = UsingPHI->getIncomingBlock(U);
1194 if (
auto *CatchRet =
1195 dyn_cast<CatchReturnInst>(IncomingBlock->
getTerminator())) {
1217 CatchRet->removeFromParent();
1221 CatchRet->setSuccessor(NewBlock);
1226 ColorVector &ColorsForNewBlock = BlockColors[NewBlock];
1227 ColorVector &ColorsForPHIBlock = BlockColors[PHIBlock];
1228 ColorsForNewBlock = ColorsForPHIBlock;
1229 for (
BasicBlock *FuncletPad : ColorsForPHIBlock)
1230 FuncletBlocks[FuncletPad].
push_back(NewBlock);
1232 IncomingBlock = NewBlock;
1255 "should get invoke with precomputed state");