43#define DEBUG_TYPE "wasm-cfg-stackify"
45STATISTIC(NumCallUnwindMismatches,
"Number of call unwind mismatches found");
46STATISTIC(NumCatchUnwindMismatches,
"Number of catch unwind mismatches found");
69 int EndNo =
End->getNumber();
70 if (!ScopeTops[EndNo] || ScopeTops[EndNo]->getNumber() > BeginNo)
71 ScopeTops[EndNo] = Begin;
97 std::pair<const MachineBasicBlock *, const MachineInstr *>;
120 UnwindDestToTrampoline;
132 if (CallerTrampolineBB)
133 MF.
insert(CallerTrampolineBB->getIterator(), AppendixBB);
144 if (!CallerTrampolineBB) {
148 return CallerTrampolineBB;
179char WebAssemblyCFGStackify::ID = 0;
182 "Insert BLOCK/LOOP/TRY/TRY_TABLE markers for WebAssembly scopes",
false,
186 return new WebAssemblyCFGStackify();
198 if (MO.isMBB() && MO.getMBB() ==
MBB)
208template <
typename Container>
211 const Container &AfterSet) {
212 auto InsertPos =
MBB->
end();
214 if (BeforeSet.count(&*std::prev(InsertPos))) {
217 for (
auto Pos = InsertPos, E =
MBB->
begin(); Pos != E; --Pos)
218 assert(!AfterSet.count(&*std::prev(Pos)));
232template <
typename Container>
235 const Container &AfterSet) {
237 while (InsertPos !=
MBB->
end()) {
238 if (AfterSet.count(&*InsertPos)) {
241 for (
auto Pos = InsertPos, E =
MBB->
end(); Pos != E; ++Pos)
242 assert(!BeforeSet.count(&*Pos));
251void WebAssemblyCFGStackify::registerScope(
MachineInstr *Begin,
253 BeginToEnd[Begin] =
End;
254 EndToBegin[
End] = Begin;
258void WebAssemblyCFGStackify::registerTryScope(
MachineInstr *Begin,
261 registerScope(Begin,
End);
262 TryToEHPad[Begin] = EHPad;
263 EHPadToTry[EHPad] = Begin;
266void WebAssemblyCFGStackify::unregisterScope(
MachineInstr *Begin) {
270 BeginToEnd.
erase(Begin);
275 TryToEHPad.
erase(Begin);
276 EHPadToTry.
erase(EHPad);
293 bool IsBranchedTo =
false;
296 if (Pred->getNumber() < MBBNumber) {
297 Header = Header ? MDT->findNearestCommonDominator(Header, Pred) : Pred;
307 assert(&
MBB != &MF.
front() &&
"Header blocks shouldn't have predecessors");
314 if (ScopeTop->getNumber() > Header->getNumber()) {
316 I = std::next(ScopeTop->getIterator());
331 for (
const auto &
MI : *Header) {
335 if (
MI.getOpcode() == WebAssembly::LOOP) {
336 auto *LoopBottom = BeginToEnd[&
MI]->getParent()->getPrevNode();
349 if (
MI.getOpcode() == WebAssembly::BLOCK ||
350 MI.getOpcode() == WebAssembly::TRY ||
351 MI.getOpcode() == WebAssembly::TRY_TABLE) {
362 if (
MI.getOpcode() == WebAssembly::END_BLOCK ||
363 MI.getOpcode() == WebAssembly::END_LOOP ||
364 MI.getOpcode() == WebAssembly::END_TRY ||
365 MI.getOpcode() == WebAssembly::END_TRY_TABLE)
370 if (
MI.isTerminator())
375 for (
auto I = Header->getFirstTerminator(), E = Header->begin();
I != E;
377 if (std::prev(
I)->isDebugInstr() || std::prev(
I)->isPosition())
380 AfterSet.
insert(&*std::prev(
I));
389 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
390 TII.get(WebAssembly::BLOCK))
391 .
addImm(int64_t(ReturnType));
396 for (
auto &
MI :
MBB) {
399 if (
MI.getOpcode() == WebAssembly::LOOP)
412 if (
MI.getOpcode() == WebAssembly::END_LOOP ||
413 MI.getOpcode() == WebAssembly::END_TRY) {
414 if (EndToBegin[&
MI]->
getParent()->getNumber() >= Header->getNumber())
426 TII.get(WebAssembly::END_BLOCK));
427 registerScope(Begin,
End);
430 updateScopeTops(Header, &
MBB);
436 const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
437 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
449 if (Iter == MF.
end()) {
450 getAppendixBlock(MF);
458 for (
const auto &
MI :
MBB) {
461 if (
MI.getOpcode() == WebAssembly::END_LOOP)
472 TII.get(WebAssembly::LOOP))
473 .
addImm(int64_t(WebAssembly::BlockType::Void));
479 for (
const auto &
MI :
MBB)
481 if (
MI.getOpcode() == WebAssembly::END_LOOP)
490 : (*AfterLoop->pred_rbegin())->findBranchDebugLoc();
492 BuildMI(*AfterLoop, InsertPos, EndDL,
TII.get(WebAssembly::END_LOOP));
493 registerScope(Begin,
End);
497 "With block sorting the outermost loop for a block should be first.");
498 updateScopeTops(&
MBB, AfterLoop);
504 auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
506 const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
507 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
515 if (Pred->getNumber() < MBBNumber) {
516 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
518 "Explicit branch to an EH pad!");
530 if (Iter == MF.
end()) {
531 getAppendixBlock(MF);
540 if (ScopeTop->getNumber() > Header->getNumber()) {
542 I = std::next(ScopeTop->getIterator());
557 for (
const auto &
MI : *Header) {
561 if (
MI.getOpcode() == WebAssembly::LOOP) {
562 auto *LoopBottom = BeginToEnd[&
MI]->getParent()->getPrevNode();
573 if (
MI.getOpcode() == WebAssembly::BLOCK ||
574 MI.getOpcode() == WebAssembly::TRY)
579 if (
MI.getOpcode() == WebAssembly::END_BLOCK ||
580 MI.getOpcode() == WebAssembly::END_LOOP ||
581 MI.getOpcode() == WebAssembly::END_TRY)
586 if (
MI.isTerminator())
597 auto TermPos = Header->getFirstTerminator();
598 if (TermPos == Header->end() ||
599 TermPos->getOpcode() != WebAssembly::RETHROW) {
606 if (
MI.getIterator() != Header->begin() &&
607 std::prev(
MI.getIterator())->isEHLabel()) {
608 AfterSet.
insert(&*std::prev(
MI.getIterator()));
609 ThrowingCall = &*std::prev(
MI.getIterator());
624 : Header->getFirstTerminator();
625 for (
auto I = SearchStartPt, E = Header->begin();
I != E; --
I) {
626 if (std::prev(
I)->isDebugInstr() || std::prev(
I)->isPosition())
629 AfterSet.
insert(&*std::prev(
I));
637 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
638 TII.get(WebAssembly::TRY))
639 .
addImm(int64_t(WebAssembly::BlockType::Void));
644 for (
const auto &
MI : *Cont) {
647 if (
MI.getOpcode() == WebAssembly::LOOP)
652 if (
MI.getOpcode() == WebAssembly::END_TRY)
660 if (
MI.getOpcode() == WebAssembly::END_LOOP) {
663 if (EndToBegin[&
MI]->
getParent()->getNumber() > Header->getNumber())
677 TII.get(WebAssembly::END_TRY));
678 registerTryScope(Begin,
End, &
MBB);
691 for (
auto *
End : {&
MBB, Cont})
692 updateScopeTops(Header,
End);
698 auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
700 const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI();
701 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
709 if (Pred->getNumber() < MBBNumber) {
710 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
712 "Explicit branch to an EH pad!");
725 if (Iter == MF.
end())
733 if (ScopeTop->getNumber() > Header->getNumber()) {
735 I = std::next(ScopeTop->getIterator());
750 for (
const auto &
MI : *Header) {
754 if (
MI.getOpcode() == WebAssembly::LOOP) {
755 auto *LoopBottom = BeginToEnd[&
MI]->getParent()->getPrevNode();
766 if (
MI.getOpcode() == WebAssembly::BLOCK ||
767 MI.getOpcode() == WebAssembly::TRY_TABLE)
772 if (
MI.getOpcode() == WebAssembly::END_BLOCK ||
773 MI.getOpcode() == WebAssembly::END_LOOP ||
774 MI.getOpcode() == WebAssembly::END_TRY_TABLE)
779 if (
MI.isTerminator())
790 auto TermPos = Header->getFirstTerminator();
791 if (TermPos == Header->end() ||
792 TermPos->getOpcode() != WebAssembly::RETHROW) {
799 if (
MI.getIterator() != Header->begin() &&
800 std::prev(
MI.getIterator())->isEHLabel()) {
801 AfterSet.
insert(&*std::prev(
MI.getIterator()));
802 ThrowingCall = &*std::prev(
MI.getIterator());
817 : Header->getFirstTerminator();
818 for (
auto I = SearchStartPt, E = Header->begin();
I != E; --
I) {
819 if (std::prev(
I)->isDebugInstr() || std::prev(
I)->isPosition())
822 AfterSet.
insert(&*std::prev(
I));
842 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
843 TII.get(WebAssembly::BLOCK));
846 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
847 TII.get(WebAssembly::TRY_TABLE))
848 .
addImm(int64_t(WebAssembly::BlockType::Void))
850 auto *TryTable = TryTableMIB.
getInstr();
859 ? WebAssembly::BlockType::I32
860 : WebAssembly::BlockType::I64;
862 switch (
Catch->getOpcode()) {
863 case WebAssembly::CATCH:
867 BlockMIB.
addImm(int64_t(PtrTy));
869 for (
const auto &
Use :
Catch->uses()) {
876 case WebAssembly::CATCH_REF:
881 BlockMIB.
addImm(int64_t(WebAssembly::BlockType::Multivalue));
884 for (
const auto &
Use :
Catch->uses()) {
890 case WebAssembly::CATCH_ALL:
892 BlockMIB.
addImm(int64_t(WebAssembly::BlockType::Void));
896 case WebAssembly::CATCH_ALL_REF:
898 BlockMIB.
addImm(int64_t(WebAssembly::BlockType::Exnref));
908 for (
const auto &
MI :
MBB) {
911 if (
MI.getOpcode() == WebAssembly::LOOP)
919 if (
MI.getOpcode() == WebAssembly::END_LOOP) {
920 if (EndToBegin[&
MI]->
getParent()->getNumber() >= Header->getNumber())
941 TII.get(WebAssembly::END_TRY_TABLE));
942 registerTryScope(TryTable, EndTryTable, &
MBB);
945 TII.get(WebAssembly::END_BLOCK));
946 registerScope(
Block, EndBlock);
988 for (
auto *
End : {&
MBB, Cont})
989 updateScopeTops(Header,
End);
992void WebAssemblyCFGStackify::removeUnnecessaryInstrs(
MachineFunction &MF) {
1028 for (
auto &
MBB : MF) {
1052 if (Analyzable && ((
Cond.empty() &&
TBB &&
TBB == Cont) ||
1053 (!
Cond.empty() && FBB && FBB == Cont))) {
1054 bool ErasedUncondBr =
false;
1055 (void)ErasedUncondBr;
1056 for (
auto I = EHPadLayoutPred->
end(), E = EHPadLayoutPred->
begin();
1058 auto PrevI = std::prev(
I);
1059 if (PrevI->isTerminator()) {
1060 assert(PrevI->getOpcode() == WebAssembly::BR);
1061 PrevI->eraseFromParent();
1062 ErasedUncondBr =
true;
1066 assert(ErasedUncondBr &&
"Unconditional branch not erased!");
1082 for (
auto &
MBB : MF) {
1083 for (
auto &
MI :
MBB) {
1084 if (
MI.getOpcode() != WebAssembly::TRY)
1087 if (EndTry->getOpcode() == WebAssembly::DELEGATE)
1093 for (
auto B = Try->
getIterator(), E = std::next(EndTry->getIterator());
1094 B != TryBB->
begin() && E != Cont->
end() &&
1095 std::prev(
B)->getOpcode() == WebAssembly::BLOCK &&
1096 E->getOpcode() == WebAssembly::END_BLOCK &&
1097 std::prev(
B)->getOperand(0).getImm() == RetType;
1104 for (
auto *
MI : ToDelete) {
1105 if (
MI->getOpcode() == WebAssembly::BLOCK)
1106 unregisterScope(
MI);
1107 MI->eraseFromParent();
1120 for (
auto &
MI : Split) {
1121 for (
auto &MO :
MI.explicit_uses()) {
1122 if (!MO.isReg() || MO.getReg().isPhysical())
1125 if (Def->getParent() == &
MBB)
1126 MFI.unstackifyVReg(MO.getReg());
1159 if (!MFI.isVRegStackified(TeeReg)) {
1161 MFI.unstackifyVReg(DefReg);
1167 MI.eraseFromParent();
1174void WebAssemblyCFGStackify::addNestedTryDelegate(
1177 auto *BeginBB = RangeBegin->
getParent();
1186 AfterSet.
insert(RangeBegin);
1189 if (std::prev(
I)->isDebugInstr() || std::prev(
I)->isPosition())
1192 AfterSet.
insert(&*std::prev(
I));
1201 TII.get(WebAssembly::TRY))
1202 .
addImm(int64_t(WebAssembly::BlockType::Void));
1208 if (UnwindDest != FakeCallerBB)
1211 auto SplitPos = std::next(RangeEnd->
getIterator());
1212 if (SplitPos == EndBB->end()) {
1215 MF.
insert(std::next(EndBB->getIterator()), DelegateBB);
1216 EndBB->addSuccessor(DelegateBB);
1226 bool CatchAfterSplit =
false;
1227 if (EndBB->isEHPad()) {
1231 CatchAfterSplit =
true;
1238 if (!CatchAfterSplit) {
1257 PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->
end());
1258 PostBB->transferSuccessors(PreBB);
1274 assert(EndBB->isEHPad());
1277 MF.
insert(PostBB->getIterator(), PreBB);
1278 MF.
insert(PostBB->getIterator(), DelegateBB);
1279 PreBB->
splice(PreBB->
end(), PostBB, PostBB->begin(), SplitPos);
1291 TII.get(WebAssembly::DELEGATE))
1293 registerTryScope(Try, Delegate,
nullptr);
1316 auto It = UnwindDestToTrampoline.
find(UnwindDest);
1317 if (It != UnwindDestToTrampoline.
end())
1328 if (UnwindDest == getFakeCallerBlock(MF)) {
1332 auto BeginPos = MF.
begin()->begin();
1336 TII.get(WebAssembly::BLOCK))
1337 .
addImm(int64_t(WebAssembly::BlockType::Exnref));
1338 TrampolineBB = getCallerTrampolineBlock(MF);
1345 auto *TargetBeginTry = EHPadToTry[UnwindDest];
1346 auto *TargetEndTry = BeginToEnd[TargetBeginTry];
1347 auto *TargetBeginBB = TargetBeginTry->getParent();
1348 auto *TargetEndBB = TargetEndTry->getParent();
1350 Block =
BuildMI(*TargetBeginBB, std::next(TargetBeginTry->getIterator()),
1351 TargetBeginTry->getDebugLoc(),
TII.get(WebAssembly::BLOCK))
1352 .
addImm(int64_t(WebAssembly::BlockType::Exnref));
1354 EndDebugLoc = TargetEndTry->getDebugLoc();
1355 MF.
insert(TargetEndBB->getIterator(), TrampolineBB);
1362 BuildMI(TrampolineBB, EndDebugLoc,
TII.get(WebAssembly::END_BLOCK));
1363 auto ExnReg =
MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass);
1364 BuildMI(TrampolineBB, EndDebugLoc,
TII.get(WebAssembly::CATCH_ALL_REF))
1366 BuildMI(TrampolineBB, EndDebugLoc,
TII.get(WebAssembly::THROW_REF))
1374 TII.get(WebAssembly::UNREACHABLE));
1376 registerScope(
Block, EndBlock);
1377 UnwindDestToTrampoline[UnwindDest] = TrampolineBB;
1378 return TrampolineBB;
1383void WebAssemblyCFGStackify::addNestedTryTable(
MachineInstr *RangeBegin,
1386 auto *BeginBB = RangeBegin->
getParent();
1394 auto *TrampolineBB = getTrampolineBlock(UnwindDest);
1399 AfterSet.
insert(RangeBegin);
1402 if (std::prev(
I)->isDebugInstr() || std::prev(
I)->isPosition())
1405 AfterSet.
insert(&*std::prev(
I));
1415 TII.get(WebAssembly::TRY_TABLE))
1416 .
addImm(int64_t(WebAssembly::BlockType::Void))
1425 auto SplitPos = std::next(RangeEnd->
getIterator());
1426 if (SplitPos == EndBB->end()) {
1429 MF.
insert(std::next(EndBB->getIterator()), EndTryTableBB);
1430 EndBB->addSuccessor(EndTryTableBB);
1440 bool CatchAfterSplit =
false;
1441 if (EndBB->isEHPad()) {
1445 CatchAfterSplit =
true;
1452 if (!CatchAfterSplit) {
1471 PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->
end());
1472 PostBB->transferSuccessors(PreBB);
1488 assert(EndBB->isEHPad());
1491 MF.
insert(PostBB->getIterator(), PreBB);
1492 MF.
insert(PostBB->getIterator(), EndTryTableBB);
1493 PreBB->
splice(PreBB->
end(), PostBB, PostBB->begin(), SplitPos);
1505 TII.get(WebAssembly::END_TRY_TABLE));
1506 registerTryScope(TryTable, EndTryTable,
nullptr);
1558 MachineInstr *EndTryTable =
nullptr, *EndLoop =
nullptr;
1559 for (
auto &
MI :
reverse(*EndTryTableBB)) {
1560 if (
MI.getOpcode() == WebAssembly::END_TRY_TABLE) {
1564 if (EndTryTable &&
MI.getOpcode() == WebAssembly::END_LOOP) {
1574 auto SplitPos = std::next(EndLoop->getIterator());
1575 EndLoopBB->splice(EndLoopBB->end(), EndTryTableBB, EndTryTableBB->
begin(),
1577 EndLoopBB->addSuccessor(EndTryTableBB);
1580bool WebAssemblyCFGStackify::fixCallUnwindMismatches(
MachineFunction &MF) {
1827 using TryRange = std::pair<MachineInstr *, MachineInstr *>;
1835 bool SeenThrowableInstInBB =
false;
1849 SeenThrowableInstInBB =
true;
1860 if (Succ->isEHPad()) {
1865 if (EHPadStack.
back() == UnwindDest)
1871 std::prev(RangeBegin->
getIterator())->isEHLabel())
1872 RangeBegin = &*std::prev(RangeBegin->
getIterator());
1873 if (std::next(RangeEnd->getIterator()) !=
MBB.
end() &&
1874 std::next(RangeEnd->getIterator())->isEHLabel())
1875 RangeEnd = &*std::next(RangeEnd->getIterator());
1878 UnwindDestToTryRanges[UnwindDest].push_back(
1879 TryRange(RangeBegin, RangeEnd));
1881 <<
"\nCall = " <<
MI
1882 <<
"\nOriginal dest = " << UnwindDest->
getName()
1883 <<
" Current dest = " << EHPadStack.
back()->getName()
1895 MachineInstr *RangeBegin =
nullptr, *RangeEnd =
nullptr;
1899 UnwindDestToTryRanges[getFakeCallerBlock(MF)].push_back(
1900 TryRange(RangeBegin, RangeEnd));
1903 <<
"\nRange begin = " << *RangeBegin
1904 <<
"Range end = " << *RangeEnd
1905 <<
"\nOriginal dest = caller Current dest = "
1906 << CurrentDest->getName() <<
"\n\n");
1907 RangeBegin = RangeEnd =
nullptr;
1911 bool SeenThrowableInstInBB =
false;
1919 SeenThrowableInstInBB =
true;
1924 RecordCallerMismatchRange(EHPadStack.
back());
1928 else if (EHPadStack.
empty() || !MayThrow) {
1936 RangeBegin = RangeEnd = &
MI;
1949 RecordCallerMismatchRange(EHPadStack.
back());
1955 if (UnwindDestToTryRanges.
empty())
1961 for (
auto &[UnwindDest,
_] : UnwindDestToTryRanges) {
1962 auto It = EHPadToTry.
find(UnwindDest);
1965 if (It != EHPadToTry.
end()) {
1966 auto *TryTable = It->second;
1967 auto *EndTryTable = BeginToEnd[TryTable];
1973 for (
auto &
P : UnwindDestToTryRanges) {
1974 NumCallUnwindMismatches +=
P.second.size();
1976 auto &TryRanges =
P.second;
1978 for (
auto Range : TryRanges) {
1979 MachineInstr *RangeBegin =
nullptr, *RangeEnd =
nullptr;
1980 std::tie(RangeBegin, RangeEnd) =
Range;
1989 if (UnwindDest != getFakeCallerBlock(MF)) {
1992 if (Succ->isEHPad()) {
2002 addNestedTryDelegate(RangeBegin, RangeEnd, UnwindDest);
2004 addNestedTryTable(RangeBegin, RangeEnd, UnwindDest);
2029bool WebAssemblyCFGStackify::fixCatchUnwindMismatches(
MachineFunction &MF) {
2139 if (
MI.getOpcode() == WebAssembly::TRY)
2141 else if (
MI.getOpcode() == WebAssembly::TRY_TABLE) {
2147 }
else if (
MI.getOpcode() == WebAssembly::DELEGATE)
2165 else if (EHPadStack.
empty() && EHInfo->hasUnwindDest(EHPad)) {
2167 <<
"'s unwind destination does not exist anymore"
2173 else if (!EHPadStack.
empty() && !EHInfo->hasUnwindDest(EHPad)) {
2174 EHPadToUnwindDest[EHPad] = getFakeCallerBlock(MF);
2176 <<
"- Catch unwind mismatch:\nEHPad = " << EHPad->
getName()
2177 <<
" Original dest = caller Current dest = "
2178 << EHPadStack.
back()->getName() <<
"\n\n");
2183 else if (!EHPadStack.
empty() && EHInfo->hasUnwindDest(EHPad)) {
2184 auto *UnwindDest = EHInfo->getUnwindDest(EHPad);
2185 if (EHPadStack.
back() != UnwindDest) {
2186 EHPadToUnwindDest[EHPad] = UnwindDest;
2188 << EHPad->
getName() <<
" Original dest = "
2189 << UnwindDest->
getName() <<
" Current dest = "
2190 << EHPadStack.
back()->getName() <<
"\n\n");
2200 if (EHPadToUnwindDest.
empty())
2205 for (
auto &[
_, UnwindDest] : EHPadToUnwindDest) {
2206 auto It = EHPadToTry.
find(UnwindDest);
2208 if (It != EHPadToTry.
end()) {
2209 auto *TryTable = It->second;
2210 auto *EndTryTable = BeginToEnd[TryTable];
2215 NumCatchUnwindMismatches += EHPadToUnwindDest.size();
2218 for (
auto &[EHPad, UnwindDest] : EHPadToUnwindDest) {
2222 addNestedTryDelegate(Try, EndTry, UnwindDest);
2225 addNestedTryTable(Try, EndTry, UnwindDest);
2276 for (
auto &
MBB : MF) {
2277 for (
auto &
MI :
MBB) {
2278 if (
MI.isTerminator()) {
2279 for (
auto &MO :
MI.operands()) {
2280 if (MO.isMBB() && NewEndTryBBs.
count(MO.getMBB())) {
2281 auto *BrDest = MO.getMBB();
2282 bool FoundEndBlock =
false;
2283 for (; std::next(BrDest->getIterator()) != MF.end();
2284 BrDest = BrDest->getNextNode()) {
2285 for (
const auto &
MI : *BrDest) {
2286 if (
MI.getOpcode() == WebAssembly::END_BLOCK) {
2287 FoundEndBlock =
true;
2305void WebAssemblyCFGStackify::recalculateScopeTops(
MachineFunction &MF) {
2309 MDT->updateBlockNumbers();
2316 switch (
MI.getOpcode()) {
2317 case WebAssembly::END_BLOCK:
2318 case WebAssembly::END_LOOP:
2319 case WebAssembly::END_TRY:
2320 case WebAssembly::END_TRY_TABLE:
2321 case WebAssembly::DELEGATE:
2324 case WebAssembly::CATCH_LEGACY:
2325 case WebAssembly::CATCH_ALL_LEGACY:
2340void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(
MachineFunction &MF) {
2343 if (MFI.getResults().empty())
2350 ? WebAssembly::BlockType::Multivalue
2361 if (
MI.isPosition() ||
MI.isDebugInstr())
2363 switch (
MI.getOpcode()) {
2364 case WebAssembly::END_TRY: {
2368 auto *EHPad = TryToEHPad.
lookup(EndToBegin[&
MI]);
2372 if (NextIt != EHPad->
rend())
2376 case WebAssembly::END_BLOCK:
2377 case WebAssembly::END_LOOP:
2378 case WebAssembly::END_TRY_TABLE:
2379 case WebAssembly::DELEGATE:
2380 EndToBegin[&
MI]->getOperand(0).setImm(int32_t(RetType));
2392 while (!Worklist.
empty())
2402 TII.get(WebAssembly::END_FUNCTION));
2428 std::vector<MachineInstr *> EndTryTables;
2429 for (
auto &
MBB : MF)
2430 for (
auto &
MI :
MBB)
2431 if (
MI.getOpcode() == WebAssembly::END_TRY_TABLE)
2432 EndTryTables.push_back(&
MI);
2434 for (
auto *EndTryTable : EndTryTables) {
2438 auto SplitPos = std::next(EndTryTable->
getIterator());
2439 NewEndTryTableBB->splice(NewEndTryTableBB->end(),
MBB,
MBB->
begin(),
2441 NewEndTryTableBB->addSuccessor(
MBB);
2443 TII.get(WebAssembly::UNREACHABLE));
2453 for (
auto &
MBB : MF)
2454 placeLoopMarker(
MBB);
2456 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
2457 for (
auto &
MBB : MF) {
2461 MF.getFunction().hasPersonalityFn()) {
2463 placeTryMarker(
MBB);
2465 placeTryTableMarker(
MBB);
2469 placeBlockMarker(
MBB);
2474 MF.getFunction().hasPersonalityFn()) {
2479 fixCallUnwindMismatches(MF);
2480 fixCatchUnwindMismatches(MF);
2483 recalculateScopeTops(MF);
2487unsigned WebAssemblyCFGStackify::getBranchDepth(
2499unsigned WebAssemblyCFGStackify::getDelegateDepth(
2501 if (
MBB == FakeCallerBB)
2502 return Stack.size();
2508 return getBranchDepth(Stack,
MBB);
2526 if (
X.first == EndTry->
getParent() &&
X.second == EndTry)
2534unsigned WebAssemblyCFGStackify::getRethrowDepth(
2540 if (
End->getOpcode() == WebAssembly::END_TRY) {
2541 auto *EHPad = TryToEHPad[EndToBegin[
End]];
2542 if (EHPadToRethrow == EHPad)
2551void WebAssemblyCFGStackify::rewriteDepthImmediates(
MachineFunction &MF) {
2558 while (
MI.getNumOperands() > 0)
2559 MI.removeOperand(
MI.getNumOperands() - 1);
2560 for (
auto MO : Ops) {
2562 if (
MI.getOpcode() == WebAssembly::DELEGATE)
2564 else if (
MI.getOpcode() == WebAssembly::RETHROW)
2569 MI.addOperand(MF, MO);
2575 switch (
MI.getOpcode()) {
2576 case WebAssembly::BLOCK:
2577 case WebAssembly::TRY:
2578 assert(ScopeTops[
Stack.back().first->getNumber()]->getNumber() <=
2580 "Block/try/try_table marker should be balanced");
2584 case WebAssembly::TRY_TABLE:
2585 assert(ScopeTops[
Stack.back().first->getNumber()]->getNumber() <=
2587 "Block/try/try_table marker should be balanced");
2589 RewriteOperands(
MI);
2592 case WebAssembly::LOOP:
2593 assert(
Stack.back().first == &
MBB &&
"Loop top should be balanced");
2597 case WebAssembly::END_BLOCK:
2598 case WebAssembly::END_TRY:
2599 case WebAssembly::END_TRY_TABLE:
2603 case WebAssembly::END_LOOP:
2607 case WebAssembly::DELEGATE:
2608 RewriteOperands(
MI);
2613 if (
MI.isTerminator())
2614 RewriteOperands(
MI);
2619 assert(
Stack.empty() &&
"Control flow should be balanced");
2622void WebAssemblyCFGStackify::cleanupFunctionData(
MachineFunction &MF) {
2625 AppendixBB = FakeCallerBB = CallerTrampolineBB =
nullptr;
2628void WebAssemblyCFGStackify::releaseMemory() {
2634 UnwindDestToTrampoline.
clear();
2637bool WebAssemblyCFGStackify::runOnMachineFunction(
MachineFunction &MF) {
2639 "********** Function: "
2642 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
2656 removeUnnecessaryInstrs(MF);
2659 rewriteDepthImmediates(MF);
2663 fixEndsAtEndOfFunction(MF);
2669 cleanupFunctionData(MF);
unsigned const MachineRegisterInfo * MRI
static const Function * getParent(const Value *V)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
const HexagonInstrInfo * TII
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
const SmallVectorImpl< MachineOperand > & Cond
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static bool explicitlyBranchesTo(MachineBasicBlock *Pred, MachineBasicBlock *MBB)
Test whether Pred has any terminators explicitly branching to MBB, as opposed to falling through.
static void addUnreachableAfterTryTables(MachineFunction &MF, const WebAssemblyInstrInfo &TII)
static MachineBasicBlock::iterator getLatestInsertPos(MachineBasicBlock *MBB, const Container &BeforeSet, const Container &AfterSet)
static void splitEndLoopBB(MachineBasicBlock *EndTryTableBB)
static void appendEndToFunction(MachineFunction &MF, const WebAssemblyInstrInfo &TII)
static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, MachineBasicBlock &Split)
static MachineBasicBlock * getSingleUnwindDest(const MachineInstr *TryTable)
static MachineBasicBlock::iterator getEarliestInsertPos(MachineBasicBlock *MBB, const Container &BeforeSet, const Container &AfterSet)
This file implements WebAssemblyException information analysis.
This file provides WebAssembly-specific target descriptions.
This file declares WebAssembly-specific per-machine-function information.
This file implements regions used in CFGSort and CFGStackify.
This file declares the WebAssembly-specific subclass of TargetSubtarget.
This file contains the declaration of the WebAssembly-specific type parsing utility functions.
This file contains the declaration of the WebAssembly-specific utility functions.
This file contains the entry points for global functions defined in the LLVM WebAssembly back-end.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
iterator find(const_arg_type_t< KeyT > Val)
bool erase(const KeyT &Val)
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
FunctionPass class - This class is used to implement most global optimizations.
bool hasPersonalityFn() const
Check whether this function has a personality function.
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
Analyze the branching code at the end of MBB, returning true if it cannot be understood (e....
BlockT * getHeader() const
Represents a single loop in the control flow graph.
This class is intended to be used as a base class for asm properties and features specific to the tar...
ExceptionHandling getExceptionHandlingType() const
bool hasEHPadSuccessor() const
bool isEHPad() const
Returns true if the block is a landing pad.
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
bool isPredecessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB is a predecessor of this block.
DebugLoc findDebugLoc(instr_iterator MBBI)
Find the next valid DebugLoc starting at MBBI, skipping any debug instructions.
DebugLoc findPrevDebugLoc(instr_iterator MBBI)
Find the previous valid DebugLoc preceding MBBI, skipping any debug instructions.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
iterator_range< iterator > terminators()
DebugLoc findBranchDebugLoc()
Find and return the merged DebugLoc of the branch instructions of the block.
iterator_range< succ_iterator > successors()
reverse_iterator rbegin()
iterator_range< pred_iterator > predecessors()
void splice(iterator Where, MachineBasicBlock *Other, iterator From)
Take an instruction from MBB 'Other' at the position From, and insert it into this MBB right before '...
MachineInstrBundleIterator< MachineInstr > iterator
StringRef getName() const
Return the name of the corresponding LLVM basic block, or an empty string.
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
virtual bool runOnMachineFunction(MachineFunction &MF)=0
runOnMachineFunction - This method must be overloaded to perform the desired machine code transformat...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
void push_back(MachineBasicBlock *MBB)
reverse_iterator rbegin()
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
void deleteMachineBasicBlock(MachineBasicBlock *MBB)
DeleteMachineBasicBlock - Delete the given MachineBasicBlock.
Function & getFunction()
Return the LLVM function that this machine code represents.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const MachineBasicBlock & back() const
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
const WasmEHFuncInfo * getWasmEHFuncInfo() const
getWasmEHFuncInfo - Return information about how the current function uses Wasm exception handling.
void RenumberBlocks(MachineBasicBlock *MBBFrom=nullptr)
RenumberBlocks - This discards all of the MachineBasicBlock numbers and recomputes them.
const MachineBasicBlock & front() const
MachineBasicBlock * CreateMachineBasicBlock(const BasicBlock *BB=nullptr, std::optional< UniqueBBID > BBID=std::nullopt)
CreateMachineBasicBlock - Allocate a new MachineBasicBlock.
void insert(iterator MBBI, MachineBasicBlock *MBB)
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
MachineBasicBlock * getMBB() const
static MachineOperand CreateImm(int64_t Val)
void invalidateLiveness()
invalidateLiveness - Indicates that register liveness is no longer being tracked accurately.
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
virtual void releaseMemory()
releaseMemory() - This member can be implemented by a pass if it wants to be able to release its memo...
Wrapper class representing virtual and physical registers.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
A Use represents the edge between a Value definition and its users.
This class is derived from MachineFunctionInfo and contains private WebAssembly-specific information ...
const std::vector< MVT > & getResults() const
self_iterator getIterator()
A collection of legacy interfaces for querying information about the current executing process.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI)
Test whether MI is a child of some other node in an expression tree.
bool isArgument(unsigned Opc)
bool isCatchAll(unsigned Opc)
bool isMarker(unsigned Opc)
unsigned getCopyOpcodeForRegClass(const TargetRegisterClass *RC)
Returns the appropriate copy opcode for the given register class.
wasm::ValType toValType(MVT Type)
cl::opt< bool > WasmUseLegacyEH
MachineInstr * findCatch(MachineBasicBlock *EHPad)
Find a catch instruction from an EH pad.
bool isCatch(unsigned Opc)
BlockType
Used as immediate MachineOperands for block signatures.
bool mayThrow(const MachineInstr &MI)
@ WASM_OPCODE_CATCH_ALL_REF
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
auto reverse(ContainerTy &&C)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionPass * createWebAssemblyCFGStackify()