1 //===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file implements a CFG stacking pass. 11 /// 12 /// This pass inserts BLOCK, LOOP, TRY, and TRY_TABLE markers to mark the start 13 /// of scopes, since scope boundaries serve as the labels for WebAssembly's 14 /// control transfers. 15 /// 16 /// This is sufficient to convert arbitrary CFGs into a form that works on 17 /// WebAssembly, provided that all loops are single-entry. 18 /// 19 /// In case we use exceptions, this pass also fixes mismatches in unwind 20 /// destinations created during transforming CFG into wasm structured format. 21 /// 22 //===----------------------------------------------------------------------===// 23 24 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 25 #include "Utils/WebAssemblyTypeUtilities.h" 26 #include "WebAssembly.h" 27 #include "WebAssemblyExceptionInfo.h" 28 #include "WebAssemblyMachineFunctionInfo.h" 29 #include "WebAssemblySortRegion.h" 30 #include "WebAssemblySubtarget.h" 31 #include "WebAssemblyUtilities.h" 32 #include "llvm/ADT/Statistic.h" 33 #include "llvm/BinaryFormat/Wasm.h" 34 #include "llvm/CodeGen/MachineDominators.h" 35 #include "llvm/CodeGen/MachineInstrBuilder.h" 36 #include "llvm/CodeGen/MachineLoopInfo.h" 37 #include "llvm/CodeGen/WasmEHFuncInfo.h" 38 #include "llvm/MC/MCAsmInfo.h" 39 #include "llvm/Target/TargetMachine.h" 40 using namespace llvm; 41 using WebAssembly::SortRegionInfo; 42 43 #define DEBUG_TYPE "wasm-cfg-stackify" 44 45 STATISTIC(NumCallUnwindMismatches, "Number of call unwind mismatches found"); 46 STATISTIC(NumCatchUnwindMismatches, "Number of catch unwind mismatches found"); 47 48 namespace { 49 class WebAssemblyCFGStackify final : public MachineFunctionPass { 50 MachineDominatorTree *MDT; 51 52 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; } 53 54 void getAnalysisUsage(AnalysisUsage &AU) const override { 55 AU.addRequired<MachineDominatorTreeWrapperPass>(); 56 AU.addRequired<MachineLoopInfoWrapperPass>(); 57 AU.addRequired<WebAssemblyExceptionInfo>(); 58 MachineFunctionPass::getAnalysisUsage(AU); 59 } 60 61 bool runOnMachineFunction(MachineFunction &MF) override; 62 63 // For each block whose label represents the end of a scope, record the block 64 // which holds the beginning of the scope. This will allow us to quickly skip 65 // over scoped regions when walking blocks. 66 SmallVector<MachineBasicBlock *, 8> ScopeTops; 67 void updateScopeTops(MachineBasicBlock *Begin, MachineBasicBlock *End) { 68 int BeginNo = Begin->getNumber(); 69 int EndNo = End->getNumber(); 70 if (!ScopeTops[EndNo] || ScopeTops[EndNo]->getNumber() > BeginNo) 71 ScopeTops[EndNo] = Begin; 72 } 73 74 // Placing markers. 75 void placeMarkers(MachineFunction &MF); 76 void placeBlockMarker(MachineBasicBlock &MBB); 77 void placeLoopMarker(MachineBasicBlock &MBB); 78 void placeTryMarker(MachineBasicBlock &MBB); 79 void placeTryTableMarker(MachineBasicBlock &MBB); 80 81 // Unwind mismatch fixing for exception handling 82 // - Common functions 83 bool fixCallUnwindMismatches(MachineFunction &MF); 84 bool fixCatchUnwindMismatches(MachineFunction &MF); 85 void recalculateScopeTops(MachineFunction &MF); 86 // - Legacy EH 87 void addNestedTryDelegate(MachineInstr *RangeBegin, MachineInstr *RangeEnd, 88 MachineBasicBlock *UnwindDest); 89 void removeUnnecessaryInstrs(MachineFunction &MF); 90 // - Standard EH (exnref) 91 void addNestedTryTable(MachineInstr *RangeBegin, MachineInstr *RangeEnd, 92 MachineBasicBlock *UnwindDest); 93 MachineBasicBlock *getTrampolineBlock(MachineBasicBlock *UnwindDest); 94 95 // Wrap-up 96 using EndMarkerInfo = 97 std::pair<const MachineBasicBlock *, const MachineInstr *>; 98 unsigned getBranchDepth(const SmallVectorImpl<EndMarkerInfo> &Stack, 99 const MachineBasicBlock *MBB); 100 unsigned getDelegateDepth(const SmallVectorImpl<EndMarkerInfo> &Stack, 101 const MachineBasicBlock *MBB); 102 unsigned 103 getRethrowDepth(const SmallVectorImpl<EndMarkerInfo> &Stack, 104 const SmallVectorImpl<const MachineBasicBlock *> &EHPadStack); 105 void rewriteDepthImmediates(MachineFunction &MF); 106 void fixEndsAtEndOfFunction(MachineFunction &MF); 107 void cleanupFunctionData(MachineFunction &MF); 108 109 // For each BLOCK|LOOP|TRY|TRY_TABLE, the corresponding 110 // END_(BLOCK|LOOP|TRY|TRY_TABLE) or DELEGATE (in case of TRY). 111 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd; 112 // For each END_(BLOCK|LOOP|TRY|TRY_TABLE) or DELEGATE, the corresponding 113 // BLOCK|LOOP|TRY|TRY_TABLE. 114 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin; 115 // <TRY marker, EH pad> map 116 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad; 117 // <EH pad, TRY marker> map 118 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry; 119 120 DenseMap<const MachineBasicBlock *, MachineBasicBlock *> 121 UnwindDestToTrampoline; 122 123 // We need an appendix block to place 'end_loop' or 'end_try' marker when the 124 // loop / exception bottom block is the last block in a function 125 MachineBasicBlock *AppendixBB = nullptr; 126 MachineBasicBlock *getAppendixBlock(MachineFunction &MF) { 127 if (!AppendixBB) { 128 AppendixBB = MF.CreateMachineBasicBlock(); 129 // Give it a fake predecessor so that AsmPrinter prints its label. 130 AppendixBB->addSuccessor(AppendixBB); 131 // If the caller trampoline BB exists, insert the appendix BB before it. 132 // Otherwise insert it at the end of the function. 133 if (CallerTrampolineBB) 134 MF.insert(CallerTrampolineBB->getIterator(), AppendixBB); 135 else 136 MF.push_back(AppendixBB); 137 } 138 return AppendixBB; 139 } 140 141 // Create a caller-dedicated trampoline BB to be used for fixing unwind 142 // mismatches where the unwind destination is the caller. 143 MachineBasicBlock *CallerTrampolineBB = nullptr; 144 MachineBasicBlock *getCallerTrampolineBlock(MachineFunction &MF) { 145 if (!CallerTrampolineBB) { 146 CallerTrampolineBB = MF.CreateMachineBasicBlock(); 147 MF.push_back(CallerTrampolineBB); 148 } 149 return CallerTrampolineBB; 150 } 151 152 // Before running rewriteDepthImmediates function, 'delegate' has a BB as its 153 // destination operand. getFakeCallerBlock() returns a fake BB that will be 154 // used for the operand when 'delegate' needs to rethrow to the caller. This 155 // will be rewritten as an immediate value that is the number of block depths 156 // + 1 in rewriteDepthImmediates, and this fake BB will be removed at the end 157 // of the pass. 158 MachineBasicBlock *FakeCallerBB = nullptr; 159 MachineBasicBlock *getFakeCallerBlock(MachineFunction &MF) { 160 if (!FakeCallerBB) 161 FakeCallerBB = MF.CreateMachineBasicBlock(); 162 return FakeCallerBB; 163 } 164 165 // Helper functions to register / unregister scope information created by 166 // marker instructions. 167 void registerScope(MachineInstr *Begin, MachineInstr *End); 168 void registerTryScope(MachineInstr *Begin, MachineInstr *End, 169 MachineBasicBlock *EHPad); 170 void unregisterScope(MachineInstr *Begin); 171 172 public: 173 static char ID; // Pass identification, replacement for typeid 174 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 175 ~WebAssemblyCFGStackify() override { releaseMemory(); } 176 void releaseMemory() override; 177 }; 178 } // end anonymous namespace 179 180 char WebAssemblyCFGStackify::ID = 0; 181 INITIALIZE_PASS( 182 WebAssemblyCFGStackify, DEBUG_TYPE, 183 "Insert BLOCK/LOOP/TRY/TRY_TABLE markers for WebAssembly scopes", false, 184 false) 185 186 FunctionPass *llvm::createWebAssemblyCFGStackify() { 187 return new WebAssemblyCFGStackify(); 188 } 189 190 /// Test whether Pred has any terminators explicitly branching to MBB, as 191 /// opposed to falling through. Note that it's possible (eg. in unoptimized 192 /// code) for a branch instruction to both branch to a block and fallthrough 193 /// to it, so we check the actual branch operands to see if there are any 194 /// explicit mentions. 195 static bool explicitlyBranchesTo(MachineBasicBlock *Pred, 196 MachineBasicBlock *MBB) { 197 for (MachineInstr &MI : Pred->terminators()) 198 for (MachineOperand &MO : MI.explicit_operands()) 199 if (MO.isMBB() && MO.getMBB() == MBB) 200 return true; 201 return false; 202 } 203 204 // Returns an iterator to the earliest position possible within the MBB, 205 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 206 // contains instructions that should go before the marker, and AfterSet contains 207 // ones that should go after the marker. In this function, AfterSet is only 208 // used for validation checking. 209 template <typename Container> 210 static MachineBasicBlock::iterator 211 getEarliestInsertPos(MachineBasicBlock *MBB, const Container &BeforeSet, 212 const Container &AfterSet) { 213 auto InsertPos = MBB->end(); 214 while (InsertPos != MBB->begin()) { 215 if (BeforeSet.count(&*std::prev(InsertPos))) { 216 #ifndef NDEBUG 217 // Validation check 218 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 219 assert(!AfterSet.count(&*std::prev(Pos))); 220 #endif 221 break; 222 } 223 --InsertPos; 224 } 225 return InsertPos; 226 } 227 228 // Returns an iterator to the latest position possible within the MBB, 229 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 230 // contains instructions that should go before the marker, and AfterSet contains 231 // ones that should go after the marker. In this function, BeforeSet is only 232 // used for validation checking. 233 template <typename Container> 234 static MachineBasicBlock::iterator 235 getLatestInsertPos(MachineBasicBlock *MBB, const Container &BeforeSet, 236 const Container &AfterSet) { 237 auto InsertPos = MBB->begin(); 238 while (InsertPos != MBB->end()) { 239 if (AfterSet.count(&*InsertPos)) { 240 #ifndef NDEBUG 241 // Validation check 242 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 243 assert(!BeforeSet.count(&*Pos)); 244 #endif 245 break; 246 } 247 ++InsertPos; 248 } 249 return InsertPos; 250 } 251 252 void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 253 MachineInstr *End) { 254 BeginToEnd[Begin] = End; 255 EndToBegin[End] = Begin; 256 } 257 258 // When 'End' is not an 'end_try' but a 'delegate', EHPad is nullptr. 259 void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 260 MachineInstr *End, 261 MachineBasicBlock *EHPad) { 262 registerScope(Begin, End); 263 TryToEHPad[Begin] = EHPad; 264 EHPadToTry[EHPad] = Begin; 265 } 266 267 void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) { 268 assert(BeginToEnd.count(Begin)); 269 MachineInstr *End = BeginToEnd[Begin]; 270 assert(EndToBegin.count(End)); 271 BeginToEnd.erase(Begin); 272 EndToBegin.erase(End); 273 MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin); 274 if (EHPad) { 275 assert(EHPadToTry.count(EHPad)); 276 TryToEHPad.erase(Begin); 277 EHPadToTry.erase(EHPad); 278 } 279 } 280 281 /// Insert a BLOCK marker for branches to MBB (if needed). 282 // TODO Consider a more generalized way of handling block (and also loop and 283 // try) signatures when we implement the multi-value proposal later. 284 void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 285 assert(!MBB.isEHPad()); 286 MachineFunction &MF = *MBB.getParent(); 287 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 288 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 289 290 // First compute the nearest common dominator of all forward non-fallthrough 291 // predecessors so that we minimize the time that the BLOCK is on the stack, 292 // which reduces overall stack height. 293 MachineBasicBlock *Header = nullptr; 294 bool IsBranchedTo = false; 295 int MBBNumber = MBB.getNumber(); 296 for (MachineBasicBlock *Pred : MBB.predecessors()) { 297 if (Pred->getNumber() < MBBNumber) { 298 Header = Header ? MDT->findNearestCommonDominator(Header, Pred) : Pred; 299 if (explicitlyBranchesTo(Pred, &MBB)) 300 IsBranchedTo = true; 301 } 302 } 303 if (!Header) 304 return; 305 if (!IsBranchedTo) 306 return; 307 308 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 309 MachineBasicBlock *LayoutPred = MBB.getPrevNode(); 310 311 // If the nearest common dominator is inside a more deeply nested context, 312 // walk out to the nearest scope which isn't more deeply nested. 313 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 314 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 315 if (ScopeTop->getNumber() > Header->getNumber()) { 316 // Skip over an intervening scope. 317 I = std::next(ScopeTop->getIterator()); 318 } else { 319 // We found a scope level at an appropriate depth. 320 Header = ScopeTop; 321 break; 322 } 323 } 324 } 325 326 // Decide where in MBB to put the BLOCK. 327 328 // Instructions that should go before the BLOCK. 329 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 330 // Instructions that should go after the BLOCK. 331 SmallPtrSet<const MachineInstr *, 4> AfterSet; 332 for (const auto &MI : *Header) { 333 // If there is a previously placed LOOP marker and the bottom block of the 334 // loop is above MBB, it should be after the BLOCK, because the loop is 335 // nested in this BLOCK. Otherwise it should be before the BLOCK. 336 if (MI.getOpcode() == WebAssembly::LOOP) { 337 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 338 if (MBB.getNumber() > LoopBottom->getNumber()) 339 AfterSet.insert(&MI); 340 #ifndef NDEBUG 341 else 342 BeforeSet.insert(&MI); 343 #endif 344 } 345 346 // If there is a previously placed BLOCK/TRY/TRY_TABLE marker and its 347 // corresponding END marker is before the current BLOCK's END marker, that 348 // should be placed after this BLOCK. Otherwise it should be placed before 349 // this BLOCK marker. 350 if (MI.getOpcode() == WebAssembly::BLOCK || 351 MI.getOpcode() == WebAssembly::TRY || 352 MI.getOpcode() == WebAssembly::TRY_TABLE) { 353 if (BeginToEnd[&MI]->getParent()->getNumber() <= MBB.getNumber()) 354 AfterSet.insert(&MI); 355 #ifndef NDEBUG 356 else 357 BeforeSet.insert(&MI); 358 #endif 359 } 360 361 #ifndef NDEBUG 362 // All END_(BLOCK|LOOP|TRY|TRY_TABLE) markers should be before the BLOCK. 363 if (MI.getOpcode() == WebAssembly::END_BLOCK || 364 MI.getOpcode() == WebAssembly::END_LOOP || 365 MI.getOpcode() == WebAssembly::END_TRY || 366 MI.getOpcode() == WebAssembly::END_TRY_TABLE) 367 BeforeSet.insert(&MI); 368 #endif 369 370 // Terminators should go after the BLOCK. 371 if (MI.isTerminator()) 372 AfterSet.insert(&MI); 373 } 374 375 // Local expression tree should go after the BLOCK. 376 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 377 --I) { 378 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 379 continue; 380 if (WebAssembly::isChild(*std::prev(I), MFI)) 381 AfterSet.insert(&*std::prev(I)); 382 else 383 break; 384 } 385 386 // Add the BLOCK. 387 WebAssembly::BlockType ReturnType = WebAssembly::BlockType::Void; 388 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 389 MachineInstr *Begin = 390 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 391 TII.get(WebAssembly::BLOCK)) 392 .addImm(int64_t(ReturnType)); 393 394 // Decide where in MBB to put the END_BLOCK. 395 BeforeSet.clear(); 396 AfterSet.clear(); 397 for (auto &MI : MBB) { 398 #ifndef NDEBUG 399 // END_BLOCK should precede existing LOOP markers. 400 if (MI.getOpcode() == WebAssembly::LOOP) 401 AfterSet.insert(&MI); 402 #endif 403 404 // If there is a previously placed END_LOOP marker and the header of the 405 // loop is above this block's header, the END_LOOP should be placed after 406 // the END_BLOCK, because the loop contains this block. Otherwise the 407 // END_LOOP should be placed before the END_BLOCK. The same for END_TRY. 408 // 409 // Note that while there can be existing END_TRYs, there can't be 410 // END_TRY_TABLEs; END_TRYs are placed when its corresponding EH pad is 411 // processed, so they are placed below MBB (EH pad) in placeTryMarker. But 412 // END_TRY_TABLE is placed like a END_BLOCK, so they can't be here already. 413 if (MI.getOpcode() == WebAssembly::END_LOOP || 414 MI.getOpcode() == WebAssembly::END_TRY) { 415 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 416 BeforeSet.insert(&MI); 417 #ifndef NDEBUG 418 else 419 AfterSet.insert(&MI); 420 #endif 421 } 422 } 423 424 // Mark the end of the block. 425 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 426 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 427 TII.get(WebAssembly::END_BLOCK)); 428 registerScope(Begin, End); 429 430 // Track the farthest-spanning scope that ends at this point. 431 updateScopeTops(Header, &MBB); 432 } 433 434 /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). 435 void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) { 436 MachineFunction &MF = *MBB.getParent(); 437 const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 438 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 439 SortRegionInfo SRI(MLI, WEI); 440 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 441 442 MachineLoop *Loop = MLI.getLoopFor(&MBB); 443 if (!Loop || Loop->getHeader() != &MBB) 444 return; 445 446 // The operand of a LOOP is the first block after the loop. If the loop is the 447 // bottom of the function, insert a dummy block at the end. 448 MachineBasicBlock *Bottom = SRI.getBottom(Loop); 449 auto Iter = std::next(Bottom->getIterator()); 450 if (Iter == MF.end()) { 451 getAppendixBlock(MF); 452 Iter = std::next(Bottom->getIterator()); 453 } 454 MachineBasicBlock *AfterLoop = &*Iter; 455 456 // Decide where in Header to put the LOOP. 457 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 458 SmallPtrSet<const MachineInstr *, 4> AfterSet; 459 for (const auto &MI : MBB) { 460 // LOOP marker should be after any existing loop that ends here. Otherwise 461 // we assume the instruction belongs to the loop. 462 if (MI.getOpcode() == WebAssembly::END_LOOP) 463 BeforeSet.insert(&MI); 464 #ifndef NDEBUG 465 else 466 AfterSet.insert(&MI); 467 #endif 468 } 469 470 // Mark the beginning of the loop. 471 auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 472 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos), 473 TII.get(WebAssembly::LOOP)) 474 .addImm(int64_t(WebAssembly::BlockType::Void)); 475 476 // Decide where in MBB to put the END_LOOP. 477 BeforeSet.clear(); 478 AfterSet.clear(); 479 #ifndef NDEBUG 480 for (const auto &MI : MBB) 481 // Existing END_LOOP markers belong to parent loops of this loop 482 if (MI.getOpcode() == WebAssembly::END_LOOP) 483 AfterSet.insert(&MI); 484 #endif 485 486 // Mark the end of the loop (using arbitrary debug location that branched to 487 // the loop end as its location). 488 InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet); 489 DebugLoc EndDL = AfterLoop->pred_empty() 490 ? DebugLoc() 491 : (*AfterLoop->pred_rbegin())->findBranchDebugLoc(); 492 MachineInstr *End = 493 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP)); 494 registerScope(Begin, End); 495 496 assert((!ScopeTops[AfterLoop->getNumber()] || 497 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && 498 "With block sorting the outermost loop for a block should be first."); 499 updateScopeTops(&MBB, AfterLoop); 500 } 501 502 void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) { 503 assert(MBB.isEHPad()); 504 MachineFunction &MF = *MBB.getParent(); 505 auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 506 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 507 const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 508 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 509 SortRegionInfo SRI(MLI, WEI); 510 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 511 512 // Compute the nearest common dominator of all unwind predecessors 513 MachineBasicBlock *Header = nullptr; 514 int MBBNumber = MBB.getNumber(); 515 for (auto *Pred : MBB.predecessors()) { 516 if (Pred->getNumber() < MBBNumber) { 517 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 518 assert(!explicitlyBranchesTo(Pred, &MBB) && 519 "Explicit branch to an EH pad!"); 520 } 521 } 522 if (!Header) 523 return; 524 525 // If this try is at the bottom of the function, insert a dummy block at the 526 // end. 527 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 528 assert(WE); 529 MachineBasicBlock *Bottom = SRI.getBottom(WE); 530 auto Iter = std::next(Bottom->getIterator()); 531 if (Iter == MF.end()) { 532 getAppendixBlock(MF); 533 Iter = std::next(Bottom->getIterator()); 534 } 535 MachineBasicBlock *Cont = &*Iter; 536 537 // If the nearest common dominator is inside a more deeply nested context, 538 // walk out to the nearest scope which isn't more deeply nested. 539 for (MachineFunction::iterator I(Bottom), E(Header); I != E; --I) { 540 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 541 if (ScopeTop->getNumber() > Header->getNumber()) { 542 // Skip over an intervening scope. 543 I = std::next(ScopeTop->getIterator()); 544 } else { 545 // We found a scope level at an appropriate depth. 546 Header = ScopeTop; 547 break; 548 } 549 } 550 } 551 552 // Decide where in Header to put the TRY. 553 554 // Instructions that should go before the TRY. 555 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 556 // Instructions that should go after the TRY. 557 SmallPtrSet<const MachineInstr *, 4> AfterSet; 558 for (const auto &MI : *Header) { 559 // If there is a previously placed LOOP marker and the bottom block of the 560 // loop is above MBB, it should be after the TRY, because the loop is nested 561 // in this TRY. Otherwise it should be before the TRY. 562 if (MI.getOpcode() == WebAssembly::LOOP) { 563 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 564 if (MBB.getNumber() > LoopBottom->getNumber()) 565 AfterSet.insert(&MI); 566 #ifndef NDEBUG 567 else 568 BeforeSet.insert(&MI); 569 #endif 570 } 571 572 // All previously inserted BLOCK/TRY markers should be after the TRY because 573 // they are all nested blocks/trys. 574 if (MI.getOpcode() == WebAssembly::BLOCK || 575 MI.getOpcode() == WebAssembly::TRY) 576 AfterSet.insert(&MI); 577 578 #ifndef NDEBUG 579 // All END_(BLOCK/LOOP/TRY) markers should be before the TRY. 580 if (MI.getOpcode() == WebAssembly::END_BLOCK || 581 MI.getOpcode() == WebAssembly::END_LOOP || 582 MI.getOpcode() == WebAssembly::END_TRY) 583 BeforeSet.insert(&MI); 584 #endif 585 586 // Terminators should go after the TRY. 587 if (MI.isTerminator()) 588 AfterSet.insert(&MI); 589 } 590 591 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 592 // contain the call within it. So the call should go after the TRY. The 593 // exception is when the header's terminator is a rethrow instruction, in 594 // which case that instruction, not a call instruction before it, is gonna 595 // throw. 596 MachineInstr *ThrowingCall = nullptr; 597 if (MBB.isPredecessor(Header)) { 598 auto TermPos = Header->getFirstTerminator(); 599 if (TermPos == Header->end() || 600 TermPos->getOpcode() != WebAssembly::RETHROW) { 601 for (auto &MI : reverse(*Header)) { 602 if (MI.isCall()) { 603 AfterSet.insert(&MI); 604 ThrowingCall = &MI; 605 // Possibly throwing calls are usually wrapped by EH_LABEL 606 // instructions. We don't want to split them and the call. 607 if (MI.getIterator() != Header->begin() && 608 std::prev(MI.getIterator())->isEHLabel()) { 609 AfterSet.insert(&*std::prev(MI.getIterator())); 610 ThrowingCall = &*std::prev(MI.getIterator()); 611 } 612 break; 613 } 614 } 615 } 616 } 617 618 // Local expression tree should go after the TRY. 619 // For BLOCK placement, we start the search from the previous instruction of a 620 // BB's terminator, but in TRY's case, we should start from the previous 621 // instruction of a call that can throw, or a EH_LABEL that precedes the call, 622 // because the return values of the call's previous instructions can be 623 // stackified and consumed by the throwing call. 624 auto SearchStartPt = ThrowingCall ? MachineBasicBlock::iterator(ThrowingCall) 625 : Header->getFirstTerminator(); 626 for (auto I = SearchStartPt, E = Header->begin(); I != E; --I) { 627 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 628 continue; 629 if (WebAssembly::isChild(*std::prev(I), MFI)) 630 AfterSet.insert(&*std::prev(I)); 631 else 632 break; 633 } 634 635 // Add the TRY. 636 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 637 MachineInstr *Begin = 638 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 639 TII.get(WebAssembly::TRY)) 640 .addImm(int64_t(WebAssembly::BlockType::Void)); 641 642 // Decide where in Cont to put the END_TRY. 643 BeforeSet.clear(); 644 AfterSet.clear(); 645 for (const auto &MI : *Cont) { 646 #ifndef NDEBUG 647 // END_TRY should precede existing LOOP markers. 648 if (MI.getOpcode() == WebAssembly::LOOP) 649 AfterSet.insert(&MI); 650 651 // All END_TRY markers placed earlier belong to exceptions that contains 652 // this one. 653 if (MI.getOpcode() == WebAssembly::END_TRY) 654 AfterSet.insert(&MI); 655 #endif 656 657 // If there is a previously placed END_LOOP marker and its header is after 658 // where TRY marker is, this loop is contained within the 'catch' part, so 659 // the END_TRY marker should go after that. Otherwise, the whole try-catch 660 // is contained within this loop, so the END_TRY should go before that. 661 if (MI.getOpcode() == WebAssembly::END_LOOP) { 662 // For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they 663 // are in the same BB, LOOP is always before TRY. 664 if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber()) 665 BeforeSet.insert(&MI); 666 #ifndef NDEBUG 667 else 668 AfterSet.insert(&MI); 669 #endif 670 } 671 672 // It is not possible for an END_BLOCK to be already in this block. 673 } 674 675 // Mark the end of the TRY. 676 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet); 677 MachineInstr *End = BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(), 678 TII.get(WebAssembly::END_TRY)); 679 registerTryScope(Begin, End, &MBB); 680 681 // Track the farthest-spanning scope that ends at this point. We create two 682 // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB 683 // with 'try'). We need to create 'catch' -> 'try' mapping here too because 684 // markers should not span across 'catch'. For example, this should not 685 // happen: 686 // 687 // try 688 // block --| (X) 689 // catch | 690 // end_block --| 691 // end_try 692 for (auto *End : {&MBB, Cont}) 693 updateScopeTops(Header, End); 694 } 695 696 void WebAssemblyCFGStackify::placeTryTableMarker(MachineBasicBlock &MBB) { 697 assert(MBB.isEHPad()); 698 MachineFunction &MF = *MBB.getParent(); 699 auto &MDT = getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 700 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 701 const auto &MLI = getAnalysis<MachineLoopInfoWrapperPass>().getLI(); 702 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 703 SortRegionInfo SRI(MLI, WEI); 704 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 705 706 // Compute the nearest common dominator of all unwind predecessors 707 MachineBasicBlock *Header = nullptr; 708 int MBBNumber = MBB.getNumber(); 709 for (auto *Pred : MBB.predecessors()) { 710 if (Pred->getNumber() < MBBNumber) { 711 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 712 assert(!explicitlyBranchesTo(Pred, &MBB) && 713 "Explicit branch to an EH pad!"); 714 } 715 } 716 if (!Header) 717 return; 718 719 // Unlike the end_try marker, we don't place an end marker at the end of 720 // exception bottom, i.e., at the end of the old 'catch' block. But we still 721 // consider the try-catch part as a scope when computing ScopeTops. 722 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 723 assert(WE); 724 MachineBasicBlock *Bottom = SRI.getBottom(WE); 725 auto Iter = std::next(Bottom->getIterator()); 726 if (Iter == MF.end()) 727 Iter--; 728 MachineBasicBlock *Cont = &*Iter; 729 730 // If the nearest common dominator is inside a more deeply nested context, 731 // walk out to the nearest scope which isn't more deeply nested. 732 for (MachineFunction::iterator I(Bottom), E(Header); I != E; --I) { 733 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 734 if (ScopeTop->getNumber() > Header->getNumber()) { 735 // Skip over an intervening scope. 736 I = std::next(ScopeTop->getIterator()); 737 } else { 738 // We found a scope level at an appropriate depth. 739 Header = ScopeTop; 740 break; 741 } 742 } 743 } 744 745 // Decide where in Header to put the TRY_TABLE. 746 747 // Instructions that should go before the TRY_TABLE. 748 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 749 // Instructions that should go after the TRY_TABLE. 750 SmallPtrSet<const MachineInstr *, 4> AfterSet; 751 for (const auto &MI : *Header) { 752 // If there is a previously placed LOOP marker and the bottom block of the 753 // loop is above MBB, it should be after the TRY_TABLE, because the loop is 754 // nested in this TRY_TABLE. Otherwise it should be before the TRY_TABLE. 755 if (MI.getOpcode() == WebAssembly::LOOP) { 756 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 757 if (MBB.getNumber() > LoopBottom->getNumber()) 758 AfterSet.insert(&MI); 759 #ifndef NDEBUG 760 else 761 BeforeSet.insert(&MI); 762 #endif 763 } 764 765 // All previously inserted BLOCK/TRY_TABLE markers should be after the 766 // TRY_TABLE because they are all nested blocks/try_tables. 767 if (MI.getOpcode() == WebAssembly::BLOCK || 768 MI.getOpcode() == WebAssembly::TRY_TABLE) 769 AfterSet.insert(&MI); 770 771 #ifndef NDEBUG 772 // All END_(BLOCK/LOOP/TRY_TABLE) markers should be before the TRY_TABLE. 773 if (MI.getOpcode() == WebAssembly::END_BLOCK || 774 MI.getOpcode() == WebAssembly::END_LOOP || 775 MI.getOpcode() == WebAssembly::END_TRY_TABLE) 776 BeforeSet.insert(&MI); 777 #endif 778 779 // Terminators should go after the TRY_TABLE. 780 if (MI.isTerminator()) 781 AfterSet.insert(&MI); 782 } 783 784 // If Header unwinds to MBB (= Header contains 'invoke'), the try_table block 785 // should contain the call within it. So the call should go after the 786 // TRY_TABLE. The exception is when the header's terminator is a rethrow 787 // instruction, in which case that instruction, not a call instruction before 788 // it, is gonna throw. 789 MachineInstr *ThrowingCall = nullptr; 790 if (MBB.isPredecessor(Header)) { 791 auto TermPos = Header->getFirstTerminator(); 792 if (TermPos == Header->end() || 793 TermPos->getOpcode() != WebAssembly::RETHROW) { 794 for (auto &MI : reverse(*Header)) { 795 if (MI.isCall()) { 796 AfterSet.insert(&MI); 797 ThrowingCall = &MI; 798 // Possibly throwing calls are usually wrapped by EH_LABEL 799 // instructions. We don't want to split them and the call. 800 if (MI.getIterator() != Header->begin() && 801 std::prev(MI.getIterator())->isEHLabel()) { 802 AfterSet.insert(&*std::prev(MI.getIterator())); 803 ThrowingCall = &*std::prev(MI.getIterator()); 804 } 805 break; 806 } 807 } 808 } 809 } 810 811 // Local expression tree should go after the TRY_TABLE. 812 // For BLOCK placement, we start the search from the previous instruction of a 813 // BB's terminator, but in TRY_TABLE's case, we should start from the previous 814 // instruction of a call that can throw, or a EH_LABEL that precedes the call, 815 // because the return values of the call's previous instructions can be 816 // stackified and consumed by the throwing call. 817 auto SearchStartPt = ThrowingCall ? MachineBasicBlock::iterator(ThrowingCall) 818 : Header->getFirstTerminator(); 819 for (auto I = SearchStartPt, E = Header->begin(); I != E; --I) { 820 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 821 continue; 822 if (WebAssembly::isChild(*std::prev(I), MFI)) 823 AfterSet.insert(&*std::prev(I)); 824 else 825 break; 826 } 827 828 // Add the TRY_TABLE and a BLOCK for the catch destination. We currently 829 // generate only one CATCH clause for a TRY_TABLE, so we need one BLOCK for 830 // its destination. 831 // 832 // Header: 833 // block 834 // try_table (catch ... $MBB) 835 // ... 836 // 837 // MBB: 838 // end_try_table 839 // end_block ;; destination of (catch ...) 840 // ... catch handler body ... 841 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 842 MachineInstrBuilder BlockMIB = 843 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 844 TII.get(WebAssembly::BLOCK)); 845 auto *Block = BlockMIB.getInstr(); 846 MachineInstrBuilder TryTableMIB = 847 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 848 TII.get(WebAssembly::TRY_TABLE)) 849 .addImm(int64_t(WebAssembly::BlockType::Void)) 850 .addImm(1); // # of catch clauses 851 auto *TryTable = TryTableMIB.getInstr(); 852 853 // Add a CATCH_*** clause to the TRY_TABLE. These are pseudo instructions 854 // following the destination END_BLOCK to simulate block return values, 855 // because we currently don't support them. 856 auto *Catch = WebAssembly::findCatch(&MBB); 857 switch (Catch->getOpcode()) { 858 case WebAssembly::CATCH: 859 // CATCH's destination block's return type is the extracted value type, 860 // which is currently i32 for all supported tags. 861 BlockMIB.addImm(int64_t(WebAssembly::BlockType::I32)); 862 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH); 863 for (const auto &Use : Catch->uses()) { 864 // The only use operand a CATCH can have is the tag symbol. 865 TryTableMIB.addExternalSymbol(Use.getSymbolName()); 866 break; 867 } 868 TryTableMIB.addMBB(&MBB); 869 break; 870 case WebAssembly::CATCH_REF: 871 // CATCH_REF's destination block's return type is the extracted value type 872 // followed by an exnref, which is (i32, exnref) in our case. We assign the 873 // actual multiavlue signature in MCInstLower. MO_CATCH_BLOCK_SIG signals 874 // that this operand is used for catch_ref's multivalue destination. 875 BlockMIB.addImm(int64_t(WebAssembly::BlockType::Multivalue)); 876 Block->getOperand(0).setTargetFlags(WebAssemblyII::MO_CATCH_BLOCK_SIG); 877 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH_REF); 878 for (const auto &Use : Catch->uses()) { 879 TryTableMIB.addExternalSymbol(Use.getSymbolName()); 880 break; 881 } 882 TryTableMIB.addMBB(&MBB); 883 break; 884 case WebAssembly::CATCH_ALL: 885 // CATCH_ALL's destination block's return type is void. 886 BlockMIB.addImm(int64_t(WebAssembly::BlockType::Void)); 887 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH_ALL); 888 TryTableMIB.addMBB(&MBB); 889 break; 890 case WebAssembly::CATCH_ALL_REF: 891 // CATCH_ALL_REF's destination block's return type is exnref. 892 BlockMIB.addImm(int64_t(WebAssembly::BlockType::Exnref)); 893 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH_ALL_REF); 894 TryTableMIB.addMBB(&MBB); 895 break; 896 } 897 898 // Decide where in MBB to put the END_TRY_TABLE, and the END_BLOCK for the 899 // CATCH destination. 900 BeforeSet.clear(); 901 AfterSet.clear(); 902 for (const auto &MI : MBB) { 903 #ifndef NDEBUG 904 // END_TRY_TABLE should precede existing LOOP markers. 905 if (MI.getOpcode() == WebAssembly::LOOP) 906 AfterSet.insert(&MI); 907 #endif 908 909 // If there is a previously placed END_LOOP marker and the header of the 910 // loop is above this try_table's header, the END_LOOP should be placed 911 // after the END_TRY_TABLE, because the loop contains this block. Otherwise 912 // the END_LOOP should be placed before the END_TRY_TABLE. 913 if (MI.getOpcode() == WebAssembly::END_LOOP) { 914 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 915 BeforeSet.insert(&MI); 916 #ifndef NDEBUG 917 else 918 AfterSet.insert(&MI); 919 #endif 920 } 921 922 #ifndef NDEBUG 923 // CATCH, CATCH_REF, CATCH_ALL, and CATCH_ALL_REF are pseudo-instructions 924 // that simulate the block return value, so they should be placed after the 925 // END_TRY_TABLE. 926 if (WebAssembly::isCatch(MI.getOpcode())) 927 AfterSet.insert(&MI); 928 #endif 929 } 930 931 // Mark the end of the TRY_TABLE and the BLOCK. 932 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 933 MachineInstr *EndTryTable = 934 BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 935 TII.get(WebAssembly::END_TRY_TABLE)); 936 registerTryScope(TryTable, EndTryTable, &MBB); 937 MachineInstr *EndBlock = 938 BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 939 TII.get(WebAssembly::END_BLOCK)); 940 registerScope(Block, EndBlock); 941 942 // Track the farthest-spanning scope that ends at this point. 943 // Unlike the end_try, even if we don't put a end marker at the end of catch 944 // block, we still have to create two mappings: (BB with 'end_try_table' -> BB 945 // with 'try_table') and (BB after the (conceptual) catch block -> BB with 946 // 'try_table'). 947 // 948 // This is what can happen if we don't create the latter mapping: 949 // 950 // Suppoe in the legacy EH we have this code: 951 // try 952 // try 953 // code1 954 // catch (a) 955 // end_try 956 // code2 957 // catch (b) 958 // end_try 959 // 960 // If we don't create the latter mapping, try_table markers would be placed 961 // like this: 962 // try_table 963 // code1 964 // end_try_table (a) 965 // try_table 966 // code2 967 // end_try_table (b) 968 // 969 // This does not reflect the original structure, and more important problem 970 // is, in case 'code1' has an unwind mismatch and should unwind to 971 // 'end_try_table (b)' rather than 'end_try_table (a)', we don't have a way to 972 // make it jump after 'end_try_table (b)' without creating another block. So 973 // even if we don't place 'end_try' marker at the end of 'catch' block 974 // anymore, we create ScopeTops mapping the same way as the legacy exception, 975 // so the resulting code will look like: 976 // try_table 977 // try_table 978 // code1 979 // end_try_table (a) 980 // code2 981 // end_try_table (b) 982 for (auto *End : {&MBB, Cont}) 983 updateScopeTops(Header, End); 984 } 985 986 void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) { 987 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 988 989 // When there is an unconditional branch right before a catch instruction and 990 // it branches to the end of end_try marker, we don't need the branch, because 991 // if there is no exception, the control flow transfers to that point anyway. 992 // bb0: 993 // try 994 // ... 995 // br bb2 <- Not necessary 996 // bb1 (ehpad): 997 // catch 998 // ... 999 // bb2: <- Continuation BB 1000 // end 1001 // 1002 // A more involved case: When the BB where 'end' is located is an another EH 1003 // pad, the Cont (= continuation) BB is that EH pad's 'end' BB. For example, 1004 // bb0: 1005 // try 1006 // try 1007 // ... 1008 // br bb3 <- Not necessary 1009 // bb1 (ehpad): 1010 // catch 1011 // bb2 (ehpad): 1012 // end 1013 // catch 1014 // ... 1015 // bb3: <- Continuation BB 1016 // end 1017 // 1018 // When the EH pad at hand is bb1, its matching end_try is in bb2. But it is 1019 // another EH pad, so bb0's continuation BB becomes bb3. So 'br bb3' in the 1020 // code can be deleted. This is why we run 'while' until 'Cont' is not an EH 1021 // pad. 1022 for (auto &MBB : MF) { 1023 if (!MBB.isEHPad()) 1024 continue; 1025 1026 MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 1027 SmallVector<MachineOperand, 4> Cond; 1028 MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode(); 1029 1030 MachineBasicBlock *Cont = &MBB; 1031 while (Cont->isEHPad()) { 1032 MachineInstr *Try = EHPadToTry[Cont]; 1033 MachineInstr *EndTry = BeginToEnd[Try]; 1034 // We started from an EH pad, so the end marker cannot be a delegate 1035 assert(EndTry->getOpcode() != WebAssembly::DELEGATE); 1036 Cont = EndTry->getParent(); 1037 } 1038 1039 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 1040 // This condition means either 1041 // 1. This BB ends with a single unconditional branch whose destinaion is 1042 // Cont. 1043 // 2. This BB ends with a conditional branch followed by an unconditional 1044 // branch, and the unconditional branch's destination is Cont. 1045 // In both cases, we want to remove the last (= unconditional) branch. 1046 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) || 1047 (!Cond.empty() && FBB && FBB == Cont))) { 1048 bool ErasedUncondBr = false; 1049 (void)ErasedUncondBr; 1050 for (auto I = EHPadLayoutPred->end(), E = EHPadLayoutPred->begin(); 1051 I != E; --I) { 1052 auto PrevI = std::prev(I); 1053 if (PrevI->isTerminator()) { 1054 assert(PrevI->getOpcode() == WebAssembly::BR); 1055 PrevI->eraseFromParent(); 1056 ErasedUncondBr = true; 1057 break; 1058 } 1059 } 1060 assert(ErasedUncondBr && "Unconditional branch not erased!"); 1061 } 1062 } 1063 1064 // When there are block / end_block markers that overlap with try / end_try 1065 // markers, and the block and try markers' return types are the same, the 1066 // block /end_block markers are not necessary, because try / end_try markers 1067 // also can serve as boundaries for branches. 1068 // block <- Not necessary 1069 // try 1070 // ... 1071 // catch 1072 // ... 1073 // end 1074 // end <- Not necessary 1075 SmallVector<MachineInstr *, 32> ToDelete; 1076 for (auto &MBB : MF) { 1077 for (auto &MI : MBB) { 1078 if (MI.getOpcode() != WebAssembly::TRY) 1079 continue; 1080 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try]; 1081 if (EndTry->getOpcode() == WebAssembly::DELEGATE) 1082 continue; 1083 1084 MachineBasicBlock *TryBB = Try->getParent(); 1085 MachineBasicBlock *Cont = EndTry->getParent(); 1086 int64_t RetType = Try->getOperand(0).getImm(); 1087 for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator()); 1088 B != TryBB->begin() && E != Cont->end() && 1089 std::prev(B)->getOpcode() == WebAssembly::BLOCK && 1090 E->getOpcode() == WebAssembly::END_BLOCK && 1091 std::prev(B)->getOperand(0).getImm() == RetType; 1092 --B, ++E) { 1093 ToDelete.push_back(&*std::prev(B)); 1094 ToDelete.push_back(&*E); 1095 } 1096 } 1097 } 1098 for (auto *MI : ToDelete) { 1099 if (MI->getOpcode() == WebAssembly::BLOCK) 1100 unregisterScope(MI); 1101 MI->eraseFromParent(); 1102 } 1103 } 1104 1105 // When MBB is split into MBB and Split, we should unstackify defs in MBB that 1106 // have their uses in Split. 1107 static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, 1108 MachineBasicBlock &Split) { 1109 MachineFunction &MF = *MBB.getParent(); 1110 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1111 auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1112 auto &MRI = MF.getRegInfo(); 1113 1114 for (auto &MI : Split) { 1115 for (auto &MO : MI.explicit_uses()) { 1116 if (!MO.isReg() || MO.getReg().isPhysical()) 1117 continue; 1118 if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg())) 1119 if (Def->getParent() == &MBB) 1120 MFI.unstackifyVReg(MO.getReg()); 1121 } 1122 } 1123 1124 // In RegStackify, when a register definition is used multiple times, 1125 // Reg = INST ... 1126 // INST ..., Reg, ... 1127 // INST ..., Reg, ... 1128 // INST ..., Reg, ... 1129 // 1130 // we introduce a TEE, which has the following form: 1131 // DefReg = INST ... 1132 // TeeReg, Reg = TEE_... DefReg 1133 // INST ..., TeeReg, ... 1134 // INST ..., Reg, ... 1135 // INST ..., Reg, ... 1136 // with DefReg and TeeReg stackified but Reg not stackified. 1137 // 1138 // But the invariant that TeeReg should be stackified can be violated while we 1139 // unstackify registers in the split BB above. In this case, we convert TEEs 1140 // into two COPYs. This COPY will be eventually eliminated in ExplicitLocals. 1141 // DefReg = INST ... 1142 // TeeReg = COPY DefReg 1143 // Reg = COPY DefReg 1144 // INST ..., TeeReg, ... 1145 // INST ..., Reg, ... 1146 // INST ..., Reg, ... 1147 for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { 1148 if (!WebAssembly::isTee(MI.getOpcode())) 1149 continue; 1150 Register TeeReg = MI.getOperand(0).getReg(); 1151 Register Reg = MI.getOperand(1).getReg(); 1152 Register DefReg = MI.getOperand(2).getReg(); 1153 if (!MFI.isVRegStackified(TeeReg)) { 1154 // Now we are not using TEE anymore, so unstackify DefReg too 1155 MFI.unstackifyVReg(DefReg); 1156 unsigned CopyOpc = 1157 WebAssembly::getCopyOpcodeForRegClass(MRI.getRegClass(DefReg)); 1158 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), TeeReg) 1159 .addReg(DefReg); 1160 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), Reg).addReg(DefReg); 1161 MI.eraseFromParent(); 1162 } 1163 } 1164 } 1165 1166 // Wrap the given range of instructions with a try-delegate that targets 1167 // 'UnwindDest'. RangeBegin and RangeEnd are inclusive. 1168 void WebAssemblyCFGStackify::addNestedTryDelegate( 1169 MachineInstr *RangeBegin, MachineInstr *RangeEnd, 1170 MachineBasicBlock *UnwindDest) { 1171 auto *BeginBB = RangeBegin->getParent(); 1172 auto *EndBB = RangeEnd->getParent(); 1173 MachineFunction &MF = *BeginBB->getParent(); 1174 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1175 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1176 1177 // Local expression tree before the first call of this range should go 1178 // after the nested TRY. 1179 SmallPtrSet<const MachineInstr *, 4> AfterSet; 1180 AfterSet.insert(RangeBegin); 1181 for (auto I = MachineBasicBlock::iterator(RangeBegin), E = BeginBB->begin(); 1182 I != E; --I) { 1183 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 1184 continue; 1185 if (WebAssembly::isChild(*std::prev(I), MFI)) 1186 AfterSet.insert(&*std::prev(I)); 1187 else 1188 break; 1189 } 1190 1191 // Create the nested try instruction. 1192 auto TryPos = getLatestInsertPos( 1193 BeginBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet); 1194 MachineInstr *Try = BuildMI(*BeginBB, TryPos, RangeBegin->getDebugLoc(), 1195 TII.get(WebAssembly::TRY)) 1196 .addImm(int64_t(WebAssembly::BlockType::Void)); 1197 1198 // Create a BB to insert the 'delegate' instruction. 1199 MachineBasicBlock *DelegateBB = MF.CreateMachineBasicBlock(); 1200 // If the destination of 'delegate' is not the caller, adds the destination to 1201 // the BB's successors. 1202 if (UnwindDest != FakeCallerBB) 1203 DelegateBB->addSuccessor(UnwindDest); 1204 1205 auto SplitPos = std::next(RangeEnd->getIterator()); 1206 if (SplitPos == EndBB->end()) { 1207 // If the range's end instruction is at the end of the BB, insert the new 1208 // delegate BB after the current BB. 1209 MF.insert(std::next(EndBB->getIterator()), DelegateBB); 1210 EndBB->addSuccessor(DelegateBB); 1211 1212 } else { 1213 // When the split pos is in the middle of a BB, we split the BB into two and 1214 // put the 'delegate' BB in between. We normally create a split BB and make 1215 // it a successor of the original BB (CatchAfterSplit == false), but in case 1216 // the BB is an EH pad and there is a 'catch' after the split pos 1217 // (CatchAfterSplit == true), we should preserve the BB's property, 1218 // including that it is an EH pad, in the later part of the BB, where the 1219 // 'catch' is. 1220 bool CatchAfterSplit = false; 1221 if (EndBB->isEHPad()) { 1222 for (auto I = MachineBasicBlock::iterator(SplitPos), E = EndBB->end(); 1223 I != E; ++I) { 1224 if (WebAssembly::isCatch(I->getOpcode())) { 1225 CatchAfterSplit = true; 1226 break; 1227 } 1228 } 1229 } 1230 1231 MachineBasicBlock *PreBB = nullptr, *PostBB = nullptr; 1232 if (!CatchAfterSplit) { 1233 // If the range's end instruction is in the middle of the BB, we split the 1234 // BB into two and insert the delegate BB in between. 1235 // - Before: 1236 // bb: 1237 // range_end 1238 // other_insts 1239 // 1240 // - After: 1241 // pre_bb: (previous 'bb') 1242 // range_end 1243 // delegate_bb: (new) 1244 // delegate 1245 // post_bb: (new) 1246 // other_insts 1247 PreBB = EndBB; 1248 PostBB = MF.CreateMachineBasicBlock(); 1249 MF.insert(std::next(PreBB->getIterator()), PostBB); 1250 MF.insert(std::next(PreBB->getIterator()), DelegateBB); 1251 PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->end()); 1252 PostBB->transferSuccessors(PreBB); 1253 } else { 1254 // - Before: 1255 // ehpad: 1256 // range_end 1257 // catch 1258 // ... 1259 // 1260 // - After: 1261 // pre_bb: (new) 1262 // range_end 1263 // delegate_bb: (new) 1264 // delegate 1265 // post_bb: (previous 'ehpad') 1266 // catch 1267 // ... 1268 assert(EndBB->isEHPad()); 1269 PreBB = MF.CreateMachineBasicBlock(); 1270 PostBB = EndBB; 1271 MF.insert(PostBB->getIterator(), PreBB); 1272 MF.insert(PostBB->getIterator(), DelegateBB); 1273 PreBB->splice(PreBB->end(), PostBB, PostBB->begin(), SplitPos); 1274 // We don't need to transfer predecessors of the EH pad to 'PreBB', 1275 // because an EH pad's predecessors are all through unwind edges and they 1276 // should still unwind to the EH pad, not PreBB. 1277 } 1278 unstackifyVRegsUsedInSplitBB(*PreBB, *PostBB); 1279 PreBB->addSuccessor(DelegateBB); 1280 PreBB->addSuccessor(PostBB); 1281 } 1282 1283 // Add a 'delegate' instruction in the delegate BB created above. 1284 MachineInstr *Delegate = BuildMI(DelegateBB, RangeEnd->getDebugLoc(), 1285 TII.get(WebAssembly::DELEGATE)) 1286 .addMBB(UnwindDest); 1287 registerTryScope(Try, Delegate, nullptr); 1288 } 1289 1290 // Given an unwind destination, return a trampoline BB. A trampoline BB is a 1291 // destination of a nested try_table inserted to fix an unwind mismatch. It 1292 // contains an end_block, which is the target of the try_table, and a throw_ref, 1293 // to rethrow the exception to the right try_table. 1294 // try_table (catch ... ) 1295 // block exnref 1296 // ... 1297 // try_table (catch_all_ref N) 1298 // some code 1299 // end_try_table 1300 // ... 1301 // end_block ;; Trampoline BB 1302 // throw_ref 1303 // end_try_table 1304 MachineBasicBlock * 1305 WebAssemblyCFGStackify::getTrampolineBlock(MachineBasicBlock *UnwindDest) { 1306 // We need one trampoline BB per unwind destination, even though there are 1307 // multiple try_tables target the same unwind destination. If we have already 1308 // created one for the given UnwindDest, return it. 1309 auto It = UnwindDestToTrampoline.find(UnwindDest); 1310 if (It != UnwindDestToTrampoline.end()) 1311 return It->second; 1312 1313 auto &MF = *UnwindDest->getParent(); 1314 auto &MRI = MF.getRegInfo(); 1315 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1316 1317 MachineInstr *Block = nullptr; 1318 MachineBasicBlock *TrampolineBB = nullptr; 1319 DebugLoc EndDebugLoc; 1320 1321 if (UnwindDest == getFakeCallerBlock(MF)) { 1322 // If the unwind destination is the caller, create a caller-dedicated 1323 // trampoline BB at the end of the function and wrap the whole function with 1324 // a block. 1325 auto BeginPos = MF.begin()->begin(); 1326 while (WebAssembly::isArgument(BeginPos->getOpcode())) 1327 BeginPos++; 1328 Block = BuildMI(*MF.begin(), BeginPos, MF.begin()->begin()->getDebugLoc(), 1329 TII.get(WebAssembly::BLOCK)) 1330 .addImm(int64_t(WebAssembly::BlockType::Exnref)); 1331 TrampolineBB = getCallerTrampolineBlock(MF); 1332 MachineBasicBlock *PrevBB = &*std::prev(CallerTrampolineBB->getIterator()); 1333 EndDebugLoc = PrevBB->findPrevDebugLoc(PrevBB->end()); 1334 } else { 1335 // If the unwind destination is another EH pad, create a trampoline BB for 1336 // the unwind dest and insert a block instruction right after the target 1337 // try_table. 1338 auto *TargetBeginTry = EHPadToTry[UnwindDest]; 1339 auto *TargetEndTry = BeginToEnd[TargetBeginTry]; 1340 auto *TargetBeginBB = TargetBeginTry->getParent(); 1341 auto *TargetEndBB = TargetEndTry->getParent(); 1342 1343 Block = BuildMI(*TargetBeginBB, std::next(TargetBeginTry->getIterator()), 1344 TargetBeginTry->getDebugLoc(), TII.get(WebAssembly::BLOCK)) 1345 .addImm(int64_t(WebAssembly::BlockType::Exnref)); 1346 TrampolineBB = MF.CreateMachineBasicBlock(); 1347 EndDebugLoc = TargetEndTry->getDebugLoc(); 1348 MF.insert(TargetEndBB->getIterator(), TrampolineBB); 1349 TrampolineBB->addSuccessor(UnwindDest); 1350 } 1351 1352 // Insert an end_block, catch_all_ref (pseudo instruction), and throw_ref 1353 // instructions in the trampoline BB. 1354 MachineInstr *EndBlock = 1355 BuildMI(TrampolineBB, EndDebugLoc, TII.get(WebAssembly::END_BLOCK)); 1356 auto ExnReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass); 1357 BuildMI(TrampolineBB, EndDebugLoc, TII.get(WebAssembly::CATCH_ALL_REF)) 1358 .addDef(ExnReg); 1359 BuildMI(TrampolineBB, EndDebugLoc, TII.get(WebAssembly::THROW_REF)) 1360 .addReg(ExnReg); 1361 1362 registerScope(Block, EndBlock); 1363 UnwindDestToTrampoline[UnwindDest] = TrampolineBB; 1364 return TrampolineBB; 1365 } 1366 1367 // Wrap the given range of instructions with a try_table-end_try_table that 1368 // targets 'UnwindDest'. RangeBegin and RangeEnd are inclusive. 1369 void WebAssemblyCFGStackify::addNestedTryTable(MachineInstr *RangeBegin, 1370 MachineInstr *RangeEnd, 1371 MachineBasicBlock *UnwindDest) { 1372 auto *BeginBB = RangeBegin->getParent(); 1373 auto *EndBB = RangeEnd->getParent(); 1374 1375 MachineFunction &MF = *BeginBB->getParent(); 1376 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1377 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1378 1379 // Get the trampoline BB that the new try_table will unwind to. 1380 auto *TrampolineBB = getTrampolineBlock(UnwindDest); 1381 1382 // Local expression tree before the first call of this range should go 1383 // after the nested TRY_TABLE. 1384 SmallPtrSet<const MachineInstr *, 4> AfterSet; 1385 AfterSet.insert(RangeBegin); 1386 for (auto I = MachineBasicBlock::iterator(RangeBegin), E = BeginBB->begin(); 1387 I != E; --I) { 1388 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 1389 continue; 1390 if (WebAssembly::isChild(*std::prev(I), MFI)) 1391 AfterSet.insert(&*std::prev(I)); 1392 else 1393 break; 1394 } 1395 1396 // Create the nested try_table instruction. 1397 auto TryTablePos = getLatestInsertPos( 1398 BeginBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet); 1399 MachineInstr *TryTable = 1400 BuildMI(*BeginBB, TryTablePos, RangeBegin->getDebugLoc(), 1401 TII.get(WebAssembly::TRY_TABLE)) 1402 .addImm(int64_t(WebAssembly::BlockType::Void)) 1403 .addImm(1) // # of catch clauses 1404 .addImm(wasm::WASM_OPCODE_CATCH_ALL_REF) 1405 .addMBB(TrampolineBB); 1406 1407 // Create a BB to insert the 'end_try_table' instruction. 1408 MachineBasicBlock *EndTryTableBB = MF.CreateMachineBasicBlock(); 1409 EndTryTableBB->addSuccessor(TrampolineBB); 1410 1411 auto SplitPos = std::next(RangeEnd->getIterator()); 1412 if (SplitPos == EndBB->end()) { 1413 // If the range's end instruction is at the end of the BB, insert the new 1414 // end_try_table BB after the current BB. 1415 MF.insert(std::next(EndBB->getIterator()), EndTryTableBB); 1416 EndBB->addSuccessor(EndTryTableBB); 1417 1418 } else { 1419 // When the split pos is in the middle of a BB, we split the BB into two and 1420 // put the 'end_try_table' BB in between. We normally create a split BB and 1421 // make it a successor of the original BB (CatchAfterSplit == false), but in 1422 // case the BB is an EH pad and there is a 'catch' after split pos 1423 // (CatchAfterSplit == true), we should preserve the BB's property, 1424 // including that it is an EH pad, in the later part of the BB, where the 1425 // 'catch' is. 1426 bool CatchAfterSplit = false; 1427 if (EndBB->isEHPad()) { 1428 for (auto I = MachineBasicBlock::iterator(SplitPos), E = EndBB->end(); 1429 I != E; ++I) { 1430 if (WebAssembly::isCatch(I->getOpcode())) { 1431 CatchAfterSplit = true; 1432 break; 1433 } 1434 } 1435 } 1436 1437 MachineBasicBlock *PreBB = nullptr, *PostBB = nullptr; 1438 if (!CatchAfterSplit) { 1439 // If the range's end instruction is in the middle of the BB, we split the 1440 // BB into two and insert the end_try_table BB in between. 1441 // - Before: 1442 // bb: 1443 // range_end 1444 // other_insts 1445 // 1446 // - After: 1447 // pre_bb: (previous 'bb') 1448 // range_end 1449 // end_try_table_bb: (new) 1450 // end_try_table 1451 // post_bb: (new) 1452 // other_insts 1453 PreBB = EndBB; 1454 PostBB = MF.CreateMachineBasicBlock(); 1455 MF.insert(std::next(PreBB->getIterator()), PostBB); 1456 MF.insert(std::next(PreBB->getIterator()), EndTryTableBB); 1457 PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->end()); 1458 PostBB->transferSuccessors(PreBB); 1459 } else { 1460 // - Before: 1461 // ehpad: 1462 // range_end 1463 // catch 1464 // ... 1465 // 1466 // - After: 1467 // pre_bb: (new) 1468 // range_end 1469 // end_try_table: (new) 1470 // end_try_table 1471 // post_bb: (previous 'ehpad') 1472 // catch 1473 // ... 1474 assert(EndBB->isEHPad()); 1475 PreBB = MF.CreateMachineBasicBlock(); 1476 PostBB = EndBB; 1477 MF.insert(PostBB->getIterator(), PreBB); 1478 MF.insert(PostBB->getIterator(), EndTryTableBB); 1479 PreBB->splice(PreBB->end(), PostBB, PostBB->begin(), SplitPos); 1480 // We don't need to transfer predecessors of the EH pad to 'PreBB', 1481 // because an EH pad's predecessors are all through unwind edges and they 1482 // should still unwind to the EH pad, not PreBB. 1483 } 1484 unstackifyVRegsUsedInSplitBB(*PreBB, *PostBB); 1485 PreBB->addSuccessor(EndTryTableBB); 1486 PreBB->addSuccessor(PostBB); 1487 } 1488 1489 // Add a 'end_try_table' instruction in the EndTryTable BB created above. 1490 MachineInstr *EndTryTable = BuildMI(EndTryTableBB, RangeEnd->getDebugLoc(), 1491 TII.get(WebAssembly::END_TRY_TABLE)); 1492 registerTryScope(TryTable, EndTryTable, nullptr); 1493 } 1494 1495 // In the standard (exnref) EH, we fix unwind mismatches by adding a new 1496 // block~end_block inside of the unwind destination try_table~end_try_table: 1497 // try_table ... 1498 // block exnref ;; (new) 1499 // ... 1500 // try_table (catch_all_ref N) ;; (new) to trampoline BB 1501 // code 1502 // end_try_table ;; (new) 1503 // ... 1504 // end_block ;; (new) trampoline BB 1505 // throw_ref ;; (new) 1506 // end_try_table 1507 // 1508 // To do this, we will create a new BB that will contain the new 'end_block' and 1509 // 'throw_ref' and insert it before the 'end_try_table' BB. 1510 // 1511 // But there are cases when there are 'end_loop'(s) before the 'end_try_table' 1512 // in the same BB. (There can't be 'end_block' before 'end_try_table' in the 1513 // same BB because EH pads can't be directly branched to.) Then after fixing 1514 // unwind mismatches this will create the mismatching markers like below: 1515 // bb0: 1516 // try_table 1517 // block exnref 1518 // ... 1519 // loop 1520 // ... 1521 // new_bb: 1522 // end_block 1523 // end_try_table_bb: 1524 // end_loop 1525 // end_try_table 1526 // 1527 // So if the unwind dest BB has a end_loop before an end_try_table, we split the 1528 // BB with the end_loop as a separate BB before the end_try_table BB, so that 1529 // after we fix the unwind mismatch, the code will be like: 1530 // bb0: 1531 // try_table 1532 // block exnref 1533 // ... 1534 // loop 1535 // ... 1536 // end_loop_bb: 1537 // end_loop 1538 // new_bb: 1539 // end_block 1540 // end_try_table_bb: 1541 // end_try_table 1542 static void splitEndLoopBB(MachineBasicBlock *UnwindDest) { 1543 auto &MF = *UnwindDest->getParent(); 1544 MachineInstr *EndTryTable = nullptr, *EndLoop = nullptr; 1545 for (auto &MI : reverse(*UnwindDest)) { 1546 if (MI.getOpcode() == WebAssembly::END_TRY_TABLE) { 1547 EndTryTable = &MI; 1548 continue; 1549 } 1550 if (EndTryTable && MI.getOpcode() == WebAssembly::END_LOOP) { 1551 EndLoop = &MI; 1552 break; 1553 } 1554 } 1555 if (!EndLoop) 1556 return; 1557 1558 auto *EndLoopBB = MF.CreateMachineBasicBlock(); 1559 MF.insert(UnwindDest->getIterator(), EndLoopBB); 1560 auto SplitPos = std::next(EndLoop->getIterator()); 1561 EndLoopBB->splice(EndLoopBB->end(), UnwindDest, UnwindDest->begin(), 1562 SplitPos); 1563 EndLoopBB->addSuccessor(UnwindDest); 1564 } 1565 1566 bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) { 1567 // This function is used for both the legacy EH and the standard (exnref) EH, 1568 // and the reason we have unwind mismatches is the same for the both of them, 1569 // but the code examples in the comments are going to be different. To make 1570 // the description less confusing, we write the basically same comments twice, 1571 // once for the legacy EH and the standard EH. 1572 // 1573 // -- Legacy EH -------------------------------------------------------------- 1574 // 1575 // Linearizing the control flow by placing TRY / END_TRY markers can create 1576 // mismatches in unwind destinations for throwing instructions, such as calls. 1577 // 1578 // We use the 'delegate' instruction to fix the unwind mismatches. 'delegate' 1579 // instruction delegates an exception to an outer 'catch'. It can target not 1580 // only 'catch' but all block-like structures including another 'delegate', 1581 // but with slightly different semantics than branches. When it targets a 1582 // 'catch', it will delegate the exception to that catch. It is being 1583 // discussed how to define the semantics when 'delegate''s target is a non-try 1584 // block: it will either be a validation failure or it will target the next 1585 // outer try-catch. But anyway our LLVM backend currently does not generate 1586 // such code. The example below illustrates where the 'delegate' instruction 1587 // in the middle will delegate the exception to, depending on the value of N. 1588 // try 1589 // try 1590 // block 1591 // try 1592 // try 1593 // call @foo 1594 // delegate N ;; Where will this delegate to? 1595 // catch ;; N == 0 1596 // end 1597 // end ;; N == 1 (invalid; will not be generated) 1598 // delegate ;; N == 2 1599 // catch ;; N == 3 1600 // end 1601 // ;; N == 4 (to caller) 1602 // 1603 // 1. When an instruction may throw, but the EH pad it will unwind to can be 1604 // different from the original CFG. 1605 // 1606 // Example: we have the following CFG: 1607 // bb0: 1608 // call @foo ; if it throws, unwind to bb2 1609 // bb1: 1610 // call @bar ; if it throws, unwind to bb3 1611 // bb2 (ehpad): 1612 // catch 1613 // ... 1614 // bb3 (ehpad) 1615 // catch 1616 // ... 1617 // 1618 // And the CFG is sorted in this order. Then after placing TRY markers, it 1619 // will look like: (BB markers are omitted) 1620 // try 1621 // try 1622 // call @foo 1623 // call @bar ;; if it throws, unwind to bb3 1624 // catch ;; ehpad (bb2) 1625 // ... 1626 // end_try 1627 // catch ;; ehpad (bb3) 1628 // ... 1629 // end_try 1630 // 1631 // Now if bar() throws, it is going to end up in bb2, not bb3, where it is 1632 // supposed to end up. We solve this problem by wrapping the mismatching call 1633 // with an inner try-delegate that rethrows the exception to the right 1634 // 'catch'. 1635 // 1636 // try 1637 // try 1638 // call @foo 1639 // try ;; (new) 1640 // call @bar 1641 // delegate 1 (bb3) ;; (new) 1642 // catch ;; ehpad (bb2) 1643 // ... 1644 // end_try 1645 // catch ;; ehpad (bb3) 1646 // ... 1647 // end_try 1648 // 1649 // --- 1650 // 2. The same as 1, but in this case an instruction unwinds to a caller 1651 // function and not another EH pad. 1652 // 1653 // Example: we have the following CFG: 1654 // bb0: 1655 // call @foo ; if it throws, unwind to bb2 1656 // bb1: 1657 // call @bar ; if it throws, unwind to caller 1658 // bb2 (ehpad): 1659 // catch 1660 // ... 1661 // 1662 // And the CFG is sorted in this order. Then after placing TRY markers, it 1663 // will look like: 1664 // try 1665 // call @foo 1666 // call @bar ;; if it throws, unwind to caller 1667 // catch ;; ehpad (bb2) 1668 // ... 1669 // end_try 1670 // 1671 // Now if bar() throws, it is going to end up in bb2, when it is supposed 1672 // throw up to the caller. We solve this problem in the same way, but in this 1673 // case 'delegate's immediate argument is the number of block depths + 1, 1674 // which means it rethrows to the caller. 1675 // try 1676 // call @foo 1677 // try ;; (new) 1678 // call @bar 1679 // delegate 1 (caller) ;; (new) 1680 // catch ;; ehpad (bb2) 1681 // ... 1682 // end_try 1683 // 1684 // Before rewriteDepthImmediates, delegate's argument is a BB. In case of the 1685 // caller, it will take a fake BB generated by getFakeCallerBlock(), which 1686 // will be converted to a correct immediate argument later. 1687 // 1688 // In case there are multiple calls in a BB that may throw to the caller, they 1689 // can be wrapped together in one nested try-delegate scope. (In 1, this 1690 // couldn't happen, because may-throwing instruction there had an unwind 1691 // destination, i.e., it was an invoke before, and there could be only one 1692 // invoke within a BB.) 1693 // 1694 // -- Standard EH ------------------------------------------------------------ 1695 // 1696 // Linearizing the control flow by placing TRY / END_TRY_TABLE markers can 1697 // create mismatches in unwind destinations for throwing instructions, such as 1698 // calls. 1699 // 1700 // We use the a nested 'try_table'~'end_try_table' instruction to fix the 1701 // unwind mismatches. try_table's catch clauses take an immediate argument 1702 // that specifics which block we should branch to. 1703 // 1704 // 1. When an instruction may throw, but the EH pad it will unwind to can be 1705 // different from the original CFG. 1706 // 1707 // Example: we have the following CFG: 1708 // bb0: 1709 // call @foo ; if it throws, unwind to bb2 1710 // bb1: 1711 // call @bar ; if it throws, unwind to bb3 1712 // bb2 (ehpad): 1713 // catch 1714 // ... 1715 // bb3 (ehpad) 1716 // catch 1717 // ... 1718 // 1719 // And the CFG is sorted in this order. Then after placing TRY_TABLE markers 1720 // (and BLOCK markers for the TRY_TABLE's destinations), it will look like: 1721 // (BB markers are omitted) 1722 // block 1723 // try_table (catch ... 0) 1724 // block 1725 // try_table (catch ... 0) 1726 // call @foo 1727 // call @bar ;; if it throws, unwind to bb3 1728 // end_try_table 1729 // end_block ;; ehpad (bb2) 1730 // ... 1731 // end_try_table 1732 // end_block ;; ehpad (bb3) 1733 // ... 1734 // 1735 // Now if bar() throws, it is going to end up in bb2, not bb3, where it is 1736 // supposed to end up. We solve this problem by wrapping the mismatching call 1737 // with an inner try_table~end_try_table that sends the exception to the the 1738 // 'trampoline' block, which rethrows, or 'bounces' it to the right 1739 // end_try_table: 1740 // block 1741 // try_table (catch ... 0) 1742 // block exnref ;; (new) 1743 // block 1744 // try_table (catch ... 0) 1745 // call @foo 1746 // try_table (catch_all_ref 2) ;; (new) to trampoline BB 1747 // call @bar 1748 // end_try_table ;; (new) 1749 // end_try_table 1750 // end_block ;; ehpad (bb2) 1751 // ... 1752 // end_block ;; (new) trampoline BB 1753 // throw_ref ;; (new) 1754 // end_try_table 1755 // end_block ;; ehpad (bb3) 1756 // 1757 // --- 1758 // 2. The same as 1, but in this case an instruction unwinds to a caller 1759 // function and not another EH pad. 1760 // 1761 // Example: we have the following CFG: 1762 // bb0: 1763 // call @foo ; if it throws, unwind to bb2 1764 // bb1: 1765 // call @bar ; if it throws, unwind to caller 1766 // bb2 (ehpad): 1767 // catch 1768 // ... 1769 // 1770 // And the CFG is sorted in this order. Then after placing TRY_TABLE markers 1771 // (and BLOCK markers for the TRY_TABLE's destinations), it will look like: 1772 // block 1773 // try_table (catch ... 0) 1774 // call @foo 1775 // call @bar ;; if it throws, unwind to caller 1776 // end_try_table 1777 // end_block ;; ehpad (bb2) 1778 // ... 1779 // 1780 // Now if bar() throws, it is going to end up in bb2, when it is supposed 1781 // throw up to the caller. We solve this problem in the same way, but in this 1782 // case 'delegate's immediate argument is the number of block depths + 1, 1783 // which means it rethrows to the caller. 1784 // block exnref ;; (new) 1785 // block 1786 // try_table (catch ... 0) 1787 // call @foo 1788 // try_table (catch_all_ref 2) ;; (new) to trampoline BB 1789 // call @bar 1790 // end_try_table ;; (new) 1791 // end_try_table 1792 // end_block ;; ehpad (bb2) 1793 // ... 1794 // end_block ;; (new) caller trampoline BB 1795 // throw_ref ;; (new) throw to the caller 1796 // 1797 // Before rewriteDepthImmediates, try_table's catch clauses' argument is a 1798 // trampoline BB from which we throw_ref the exception to the right 1799 // end_try_table. In case of the caller, it will take a new caller-dedicated 1800 // trampoline BB generated by getCallerTrampolineBlock(), which throws the 1801 // exception to the caller. 1802 // 1803 // In case there are multiple calls in a BB that may throw to the caller, they 1804 // can be wrapped together in one nested try_table-end_try_table scope. (In 1, 1805 // this couldn't happen, because may-throwing instruction there had an unwind 1806 // destination, i.e., it was an invoke before, and there could be only one 1807 // invoke within a BB.) 1808 1809 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 1810 // Range of intructions to be wrapped in a new nested try~delegate or 1811 // try_table~end_try_table. A range exists in a single BB and does not span 1812 // multiple BBs. 1813 using TryRange = std::pair<MachineInstr *, MachineInstr *>; 1814 // In original CFG, <unwind destination BB, a vector of try/try_table ranges> 1815 DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges; 1816 1817 // Gather possibly throwing calls (i.e., previously invokes) whose current 1818 // unwind destination is not the same as the original CFG. (Case 1) 1819 1820 for (auto &MBB : reverse(MF)) { 1821 bool SeenThrowableInstInBB = false; 1822 for (auto &MI : reverse(MBB)) { 1823 if (WebAssembly::isTry(MI.getOpcode())) 1824 EHPadStack.pop_back(); 1825 else if (WebAssembly::isCatch(MI.getOpcode())) 1826 EHPadStack.push_back(MI.getParent()); 1827 1828 // In this loop we only gather calls that have an EH pad to unwind. So 1829 // there will be at most 1 such call (= invoke) in a BB, so after we've 1830 // seen one, we can skip the rest of BB. Also if MBB has no EH pad 1831 // successor or MI does not throw, this is not an invoke. 1832 if (SeenThrowableInstInBB || !MBB.hasEHPadSuccessor() || 1833 !WebAssembly::mayThrow(MI)) 1834 continue; 1835 SeenThrowableInstInBB = true; 1836 1837 // If the EH pad on the stack top is where this instruction should unwind 1838 // next, we're good. 1839 MachineBasicBlock *UnwindDest = getFakeCallerBlock(MF); 1840 for (auto *Succ : MBB.successors()) { 1841 // Even though semantically a BB can have multiple successors in case an 1842 // exception is not caught by a catchpad, in our backend implementation 1843 // it is guaranteed that a BB can have at most one EH pad successor. For 1844 // details, refer to comments in findWasmUnwindDestinations function in 1845 // SelectionDAGBuilder.cpp. 1846 if (Succ->isEHPad()) { 1847 UnwindDest = Succ; 1848 break; 1849 } 1850 } 1851 if (EHPadStack.back() == UnwindDest) 1852 continue; 1853 1854 // Include EH_LABELs in the range before and after the invoke 1855 MachineInstr *RangeBegin = &MI, *RangeEnd = &MI; 1856 if (RangeBegin->getIterator() != MBB.begin() && 1857 std::prev(RangeBegin->getIterator())->isEHLabel()) 1858 RangeBegin = &*std::prev(RangeBegin->getIterator()); 1859 if (std::next(RangeEnd->getIterator()) != MBB.end() && 1860 std::next(RangeEnd->getIterator())->isEHLabel()) 1861 RangeEnd = &*std::next(RangeEnd->getIterator()); 1862 1863 // If not, record the range. 1864 UnwindDestToTryRanges[UnwindDest].push_back( 1865 TryRange(RangeBegin, RangeEnd)); 1866 LLVM_DEBUG(dbgs() << "- Call unwind mismatch: MBB = " << MBB.getName() 1867 << "\nCall = " << MI 1868 << "\nOriginal dest = " << UnwindDest->getName() 1869 << " Current dest = " << EHPadStack.back()->getName() 1870 << "\n\n"); 1871 } 1872 } 1873 1874 assert(EHPadStack.empty()); 1875 1876 // Gather possibly throwing calls that are supposed to unwind up to the caller 1877 // if they throw, but currently unwind to an incorrect destination. Unlike the 1878 // loop above, there can be multiple calls within a BB that unwind to the 1879 // caller, which we should group together in a range. (Case 2) 1880 1881 MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; // inclusive 1882 1883 // Record the range. 1884 auto RecordCallerMismatchRange = [&](const MachineBasicBlock *CurrentDest) { 1885 UnwindDestToTryRanges[getFakeCallerBlock(MF)].push_back( 1886 TryRange(RangeBegin, RangeEnd)); 1887 LLVM_DEBUG(dbgs() << "- Call unwind mismatch: MBB = " 1888 << RangeBegin->getParent()->getName() 1889 << "\nRange begin = " << *RangeBegin 1890 << "Range end = " << *RangeEnd 1891 << "\nOriginal dest = caller Current dest = " 1892 << CurrentDest->getName() << "\n\n"); 1893 RangeBegin = RangeEnd = nullptr; // Reset range pointers 1894 }; 1895 1896 for (auto &MBB : reverse(MF)) { 1897 bool SeenThrowableInstInBB = false; 1898 for (auto &MI : reverse(MBB)) { 1899 bool MayThrow = WebAssembly::mayThrow(MI); 1900 1901 // If MBB has an EH pad successor and this is the last instruction that 1902 // may throw, this instruction unwinds to the EH pad and not to the 1903 // caller. 1904 if (MBB.hasEHPadSuccessor() && MayThrow && !SeenThrowableInstInBB) 1905 SeenThrowableInstInBB = true; 1906 1907 // We wrap up the current range when we see a marker even if we haven't 1908 // finished a BB. 1909 else if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) 1910 RecordCallerMismatchRange(EHPadStack.back()); 1911 1912 // If EHPadStack is empty, that means it correctly unwinds to the caller 1913 // if it throws, so we're good. If MI does not throw, we're good too. 1914 else if (EHPadStack.empty() || !MayThrow) { 1915 } 1916 1917 // We found an instruction that unwinds to the caller but currently has an 1918 // incorrect unwind destination. Create a new range or increment the 1919 // currently existing range. 1920 else { 1921 if (!RangeEnd) 1922 RangeBegin = RangeEnd = &MI; 1923 else 1924 RangeBegin = &MI; 1925 } 1926 1927 // Update EHPadStack. 1928 if (WebAssembly::isTry(MI.getOpcode())) 1929 EHPadStack.pop_back(); 1930 else if (WebAssembly::isCatch(MI.getOpcode())) 1931 EHPadStack.push_back(MI.getParent()); 1932 } 1933 1934 if (RangeEnd) 1935 RecordCallerMismatchRange(EHPadStack.back()); 1936 } 1937 1938 assert(EHPadStack.empty()); 1939 1940 // We don't have any unwind destination mismatches to resolve. 1941 if (UnwindDestToTryRanges.empty()) 1942 return false; 1943 1944 // When end_loop is before end_try_table within the same BB in unwind 1945 // destinations, we should split the end_loop into another BB. 1946 if (WebAssembly::WasmEnableExnref) 1947 for (auto &[UnwindDest, _] : UnwindDestToTryRanges) 1948 splitEndLoopBB(UnwindDest); 1949 1950 // Now we fix the mismatches by wrapping calls with inner try-delegates. 1951 for (auto &P : UnwindDestToTryRanges) { 1952 NumCallUnwindMismatches += P.second.size(); 1953 MachineBasicBlock *UnwindDest = P.first; 1954 auto &TryRanges = P.second; 1955 1956 for (auto Range : TryRanges) { 1957 MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; 1958 std::tie(RangeBegin, RangeEnd) = Range; 1959 auto *MBB = RangeBegin->getParent(); 1960 1961 // If this BB has an EH pad successor, i.e., ends with an 'invoke', and if 1962 // the current range contains the invoke, now we are going to wrap the 1963 // invoke with try-delegate or try_table-end_try_table, making the 1964 // 'delegate' or 'end_try_table' BB the new successor instead, so remove 1965 // the EH pad succesor here. The BB may not have an EH pad successor if 1966 // calls in this BB throw to the caller. 1967 if (UnwindDest != getFakeCallerBlock(MF)) { 1968 MachineBasicBlock *EHPad = nullptr; 1969 for (auto *Succ : MBB->successors()) { 1970 if (Succ->isEHPad()) { 1971 EHPad = Succ; 1972 break; 1973 } 1974 } 1975 if (EHPad) 1976 MBB->removeSuccessor(EHPad); 1977 } 1978 1979 if (WebAssembly::WasmEnableExnref) 1980 addNestedTryTable(RangeBegin, RangeEnd, UnwindDest); 1981 else 1982 addNestedTryDelegate(RangeBegin, RangeEnd, UnwindDest); 1983 } 1984 } 1985 1986 return true; 1987 } 1988 1989 // Returns the single destination of try_table, if there is one. All try_table 1990 // we generate in this pass has a single destination, i.e., a single catch 1991 // clause. 1992 static MachineBasicBlock *getSingleUnwindDest(const MachineInstr *TryTable) { 1993 if (TryTable->getOperand(1).getImm() != 1) 1994 return nullptr; 1995 switch (TryTable->getOperand(2).getImm()) { 1996 case wasm::WASM_OPCODE_CATCH: 1997 case wasm::WASM_OPCODE_CATCH_REF: 1998 return TryTable->getOperand(4).getMBB(); 1999 case wasm::WASM_OPCODE_CATCH_ALL: 2000 case wasm::WASM_OPCODE_CATCH_ALL_REF: 2001 return TryTable->getOperand(3).getMBB(); 2002 default: 2003 llvm_unreachable("try_table: Invalid catch clause\n"); 2004 } 2005 } 2006 2007 bool WebAssemblyCFGStackify::fixCatchUnwindMismatches(MachineFunction &MF) { 2008 // This function is used for both the legacy EH and the standard (exnref) EH, 2009 // and the reason we have unwind mismatches is the same for the both of them, 2010 // but the code examples in the comments are going to be different. To make 2011 // the description less confusing, we write the basically same comments twice, 2012 // once for the legacy EH and the standard EH. 2013 // 2014 // -- Legacy EH -------------------------------------------------------------- 2015 // 2016 // There is another kind of unwind destination mismatches besides call unwind 2017 // mismatches, which we will call "catch unwind mismatches". See this example 2018 // after the marker placement: 2019 // try 2020 // try 2021 // call @foo 2022 // catch __cpp_exception ;; ehpad A (next unwind dest: caller) 2023 // ... 2024 // end_try 2025 // catch_all ;; ehpad B 2026 // ... 2027 // end_try 2028 // 2029 // 'call @foo's unwind destination is the ehpad A. But suppose 'call @foo' 2030 // throws a foreign exception that is not caught by ehpad A, and its next 2031 // destination should be the caller. But after control flow linearization, 2032 // another EH pad can be placed in between (e.g. ehpad B here), making the 2033 // next unwind destination incorrect. In this case, the foreign exception will 2034 // instead go to ehpad B and will be caught there instead. In this example the 2035 // correct next unwind destination is the caller, but it can be another outer 2036 // catch in other cases. 2037 // 2038 // There is no specific 'call' or 'throw' instruction to wrap with a 2039 // try-delegate, so we wrap the whole try-catch-end with a try-delegate and 2040 // make it rethrow to the right destination, which is the caller in the 2041 // example below: 2042 // try 2043 // try ;; (new) 2044 // try 2045 // call @foo 2046 // catch __cpp_exception ;; ehpad A (next unwind dest: caller) 2047 // ... 2048 // end_try 2049 // delegate 1 (caller) ;; (new) 2050 // catch_all ;; ehpad B 2051 // ... 2052 // end_try 2053 // 2054 // The right destination may be another EH pad or the caller. (The example 2055 // here shows the case it is the caller.) 2056 // 2057 // -- Standard EH ------------------------------------------------------------ 2058 // 2059 // There is another kind of unwind destination mismatches besides call unwind 2060 // mismatches, which we will call "catch unwind mismatches". See this example 2061 // after the marker placement: 2062 // block 2063 // try_table (catch_all_ref 0) 2064 // block 2065 // try_table (catch ... 0) 2066 // call @foo 2067 // end_try_table 2068 // end_block ;; ehpad A (next unwind dest: caller) 2069 // ... 2070 // end_try_table 2071 // end_block ;; ehpad B 2072 // ... 2073 // 2074 // 'call @foo's unwind destination is the ehpad A. But suppose 'call @foo' 2075 // throws a foreign exception that is not caught by ehpad A, and its next 2076 // destination should be the caller. But after control flow linearization, 2077 // another EH pad can be placed in between (e.g. ehpad B here), making the 2078 // next unwind destination incorrect. In this case, the foreign exception will 2079 // instead go to ehpad B and will be caught there instead. In this example the 2080 // correct next unwind destination is the caller, but it can be another outer 2081 // catch in other cases. 2082 // 2083 // There is no specific 'call' or 'throw' instruction to wrap with an inner 2084 // try_table-end_try_table, so we wrap the whole try_table-end_try_table with 2085 // an inner try_table-end_try_table that sends the exception to a trampoline 2086 // BB. We rethrow the sent exception using a throw_ref to the right 2087 // destination, which is the caller in the example below: 2088 // block exnref 2089 // block 2090 // try_table (catch_all_ref 0) 2091 // try_table (catch_all_ref 2) ;; (new) to trampoline 2092 // block 2093 // try_table (catch ... 0) 2094 // call @foo 2095 // end_try_table 2096 // end_block ;; ehpad A (next unwind dest: caller) 2097 // end_try_table ;; (new) 2098 // ... 2099 // end_try_table 2100 // end_block ;; ehpad B 2101 // ... 2102 // end_block ;; (new) caller trampoline BB 2103 // throw_ref ;; (new) throw to the caller 2104 // 2105 // The right destination may be another EH pad or the caller. (The example 2106 // here shows the case it is the caller.) 2107 2108 const auto *EHInfo = MF.getWasmEHFuncInfo(); 2109 assert(EHInfo); 2110 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 2111 // For EH pads that have catch unwind mismatches, a map of <EH pad, its 2112 // correct unwind destination>. 2113 DenseMap<MachineBasicBlock *, MachineBasicBlock *> EHPadToUnwindDest; 2114 2115 for (auto &MBB : reverse(MF)) { 2116 for (auto &MI : reverse(MBB)) { 2117 if (MI.getOpcode() == WebAssembly::TRY) 2118 EHPadStack.pop_back(); 2119 else if (MI.getOpcode() == WebAssembly::TRY_TABLE) { 2120 // We want to exclude try_tables created in fixCallUnwindMismatches. 2121 // Check if the try_table's unwind destination matches the EH pad stack 2122 // top. If it is created in fixCallUnwindMismatches, it wouldn't. 2123 if (getSingleUnwindDest(&MI) == EHPadStack.back()) 2124 EHPadStack.pop_back(); 2125 } else if (MI.getOpcode() == WebAssembly::DELEGATE) 2126 EHPadStack.push_back(&MBB); 2127 else if (WebAssembly::isCatch(MI.getOpcode())) { 2128 auto *EHPad = &MBB; 2129 2130 // If the BB has a catch pseudo instruction but is not marked as an EH 2131 // pad, it's a trampoline BB we created in fixCallUnwindMismatches. Skip 2132 // it. 2133 if (!EHPad->isEHPad()) 2134 continue; 2135 2136 // catch_all always catches an exception, so we don't need to do 2137 // anything 2138 if (WebAssembly::isCatchAll(MI.getOpcode())) { 2139 } 2140 2141 // This can happen when the unwind dest was removed during the 2142 // optimization, e.g. because it was unreachable. 2143 else if (EHPadStack.empty() && EHInfo->hasUnwindDest(EHPad)) { 2144 LLVM_DEBUG(dbgs() << "EHPad (" << EHPad->getName() 2145 << "'s unwind destination does not exist anymore" 2146 << "\n\n"); 2147 } 2148 2149 // The EHPad's next unwind destination is the caller, but we incorrectly 2150 // unwind to another EH pad. 2151 else if (!EHPadStack.empty() && !EHInfo->hasUnwindDest(EHPad)) { 2152 EHPadToUnwindDest[EHPad] = getFakeCallerBlock(MF); 2153 LLVM_DEBUG(dbgs() 2154 << "- Catch unwind mismatch:\nEHPad = " << EHPad->getName() 2155 << " Original dest = caller Current dest = " 2156 << EHPadStack.back()->getName() << "\n\n"); 2157 } 2158 2159 // The EHPad's next unwind destination is an EH pad, whereas we 2160 // incorrectly unwind to another EH pad. 2161 else if (!EHPadStack.empty() && EHInfo->hasUnwindDest(EHPad)) { 2162 auto *UnwindDest = EHInfo->getUnwindDest(EHPad); 2163 if (EHPadStack.back() != UnwindDest) { 2164 EHPadToUnwindDest[EHPad] = UnwindDest; 2165 LLVM_DEBUG(dbgs() << "- Catch unwind mismatch:\nEHPad = " 2166 << EHPad->getName() << " Original dest = " 2167 << UnwindDest->getName() << " Current dest = " 2168 << EHPadStack.back()->getName() << "\n\n"); 2169 } 2170 } 2171 2172 EHPadStack.push_back(EHPad); 2173 } 2174 } 2175 } 2176 2177 assert(EHPadStack.empty()); 2178 if (EHPadToUnwindDest.empty()) 2179 return false; 2180 2181 // When end_loop is before end_try_table within the same BB in unwind 2182 // destinations, we should split the end_loop into another BB. 2183 for (auto &[_, UnwindDest] : EHPadToUnwindDest) 2184 splitEndLoopBB(UnwindDest); 2185 2186 NumCatchUnwindMismatches += EHPadToUnwindDest.size(); 2187 SmallPtrSet<MachineBasicBlock *, 4> NewEndTryBBs; 2188 2189 for (auto &[EHPad, UnwindDest] : EHPadToUnwindDest) { 2190 MachineInstr *Try = EHPadToTry[EHPad]; 2191 MachineInstr *EndTry = BeginToEnd[Try]; 2192 if (WebAssembly::WasmEnableExnref) { 2193 addNestedTryTable(Try, EndTry, UnwindDest); 2194 } else { 2195 addNestedTryDelegate(Try, EndTry, UnwindDest); 2196 NewEndTryBBs.insert(EndTry->getParent()); 2197 } 2198 } 2199 2200 if (WebAssembly::WasmEnableExnref) 2201 return true; 2202 2203 // Adding a try-delegate wrapping an existing try-catch-end can make existing 2204 // branch destination BBs invalid. For example, 2205 // 2206 // - Before: 2207 // bb0: 2208 // block 2209 // br bb3 2210 // bb1: 2211 // try 2212 // ... 2213 // bb2: (ehpad) 2214 // catch 2215 // bb3: 2216 // end_try 2217 // end_block ;; 'br bb3' targets here 2218 // 2219 // Suppose this try-catch-end has a catch unwind mismatch, so we need to wrap 2220 // this with a try-delegate. Then this becomes: 2221 // 2222 // - After: 2223 // bb0: 2224 // block 2225 // br bb3 ;; invalid destination! 2226 // bb1: 2227 // try ;; (new instruction) 2228 // try 2229 // ... 2230 // bb2: (ehpad) 2231 // catch 2232 // bb3: 2233 // end_try ;; 'br bb3' still incorrectly targets here! 2234 // delegate_bb: ;; (new BB) 2235 // delegate ;; (new instruction) 2236 // split_bb: ;; (new BB) 2237 // end_block 2238 // 2239 // Now 'br bb3' incorrectly branches to an inner scope. 2240 // 2241 // As we can see in this case, when branches target a BB that has both 2242 // 'end_try' and 'end_block' and the BB is split to insert a 'delegate', we 2243 // have to remap existing branch destinations so that they target not the 2244 // 'end_try' BB but the new 'end_block' BB. There can be multiple 'delegate's 2245 // in between, so we try to find the next BB with 'end_block' instruction. In 2246 // this example, the 'br bb3' instruction should be remapped to 'br split_bb'. 2247 for (auto &MBB : MF) { 2248 for (auto &MI : MBB) { 2249 if (MI.isTerminator()) { 2250 for (auto &MO : MI.operands()) { 2251 if (MO.isMBB() && NewEndTryBBs.count(MO.getMBB())) { 2252 auto *BrDest = MO.getMBB(); 2253 bool FoundEndBlock = false; 2254 for (; std::next(BrDest->getIterator()) != MF.end(); 2255 BrDest = BrDest->getNextNode()) { 2256 for (const auto &MI : *BrDest) { 2257 if (MI.getOpcode() == WebAssembly::END_BLOCK) { 2258 FoundEndBlock = true; 2259 break; 2260 } 2261 } 2262 if (FoundEndBlock) 2263 break; 2264 } 2265 assert(FoundEndBlock); 2266 MO.setMBB(BrDest); 2267 } 2268 } 2269 } 2270 } 2271 } 2272 2273 return true; 2274 } 2275 2276 void WebAssemblyCFGStackify::recalculateScopeTops(MachineFunction &MF) { 2277 // Renumber BBs and recalculate ScopeTop info because new BBs might have been 2278 // created and inserted during fixing unwind mismatches. 2279 MF.RenumberBlocks(); 2280 MDT->updateBlockNumbers(); 2281 ScopeTops.clear(); 2282 ScopeTops.resize(MF.getNumBlockIDs()); 2283 for (auto &MBB : reverse(MF)) { 2284 for (auto &MI : reverse(MBB)) { 2285 if (ScopeTops[MBB.getNumber()]) 2286 break; 2287 switch (MI.getOpcode()) { 2288 case WebAssembly::END_BLOCK: 2289 case WebAssembly::END_LOOP: 2290 case WebAssembly::END_TRY: 2291 case WebAssembly::END_TRY_TABLE: 2292 case WebAssembly::DELEGATE: 2293 updateScopeTops(EndToBegin[&MI]->getParent(), &MBB); 2294 break; 2295 case WebAssembly::CATCH_LEGACY: 2296 case WebAssembly::CATCH_ALL_LEGACY: 2297 updateScopeTops(EHPadToTry[&MBB]->getParent(), &MBB); 2298 break; 2299 } 2300 } 2301 } 2302 } 2303 2304 /// In normal assembly languages, when the end of a function is unreachable, 2305 /// because the function ends in an infinite loop or a noreturn call or similar, 2306 /// it isn't necessary to worry about the function return type at the end of 2307 /// the function, because it's never reached. However, in WebAssembly, blocks 2308 /// that end at the function end need to have a return type signature that 2309 /// matches the function signature, even though it's unreachable. This function 2310 /// checks for such cases and fixes up the signatures. 2311 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 2312 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 2313 2314 if (MFI.getResults().empty()) 2315 return; 2316 2317 // MCInstLower will add the proper types to multivalue signatures based on the 2318 // function return type 2319 WebAssembly::BlockType RetType = 2320 MFI.getResults().size() > 1 2321 ? WebAssembly::BlockType::Multivalue 2322 : WebAssembly::BlockType( 2323 WebAssembly::toValType(MFI.getResults().front())); 2324 2325 SmallVector<MachineBasicBlock::reverse_iterator, 4> Worklist; 2326 Worklist.push_back(MF.rbegin()->rbegin()); 2327 2328 auto Process = [&](MachineBasicBlock::reverse_iterator It) { 2329 auto *MBB = It->getParent(); 2330 while (It != MBB->rend()) { 2331 MachineInstr &MI = *It++; 2332 if (MI.isPosition() || MI.isDebugInstr()) 2333 continue; 2334 switch (MI.getOpcode()) { 2335 case WebAssembly::END_TRY: { 2336 // If a 'try''s return type is fixed, both its try body and catch body 2337 // should satisfy the return type, so we need to search 'end' 2338 // instructions before its corresponding 'catch' too. 2339 auto *EHPad = TryToEHPad.lookup(EndToBegin[&MI]); 2340 assert(EHPad); 2341 auto NextIt = 2342 std::next(WebAssembly::findCatch(EHPad)->getReverseIterator()); 2343 if (NextIt != EHPad->rend()) 2344 Worklist.push_back(NextIt); 2345 [[fallthrough]]; 2346 } 2347 case WebAssembly::END_BLOCK: 2348 case WebAssembly::END_LOOP: 2349 case WebAssembly::END_TRY_TABLE: 2350 case WebAssembly::DELEGATE: 2351 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 2352 continue; 2353 default: 2354 // Something other than an `end`. We're done for this BB. 2355 return; 2356 } 2357 } 2358 // We've reached the beginning of a BB. Continue the search in the previous 2359 // BB. 2360 Worklist.push_back(MBB->getPrevNode()->rbegin()); 2361 }; 2362 2363 while (!Worklist.empty()) 2364 Process(Worklist.pop_back_val()); 2365 } 2366 2367 // WebAssembly functions end with an end instruction, as if the function body 2368 // were a block. 2369 static void appendEndToFunction(MachineFunction &MF, 2370 const WebAssemblyInstrInfo &TII) { 2371 BuildMI(MF.back(), MF.back().end(), 2372 MF.back().findPrevDebugLoc(MF.back().end()), 2373 TII.get(WebAssembly::END_FUNCTION)); 2374 } 2375 2376 /// Insert BLOCK/LOOP/TRY/TRY_TABLE markers at appropriate places. 2377 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 2378 // We allocate one more than the number of blocks in the function to 2379 // accommodate for the possible fake block we may insert at the end. 2380 ScopeTops.resize(MF.getNumBlockIDs() + 1); 2381 // Place the LOOP for MBB if MBB is the header of a loop. 2382 for (auto &MBB : MF) 2383 placeLoopMarker(MBB); 2384 2385 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 2386 for (auto &MBB : MF) { 2387 if (MBB.isEHPad()) { 2388 // Place the TRY/TRY_TABLE for MBB if MBB is the EH pad of an exception. 2389 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 2390 MF.getFunction().hasPersonalityFn()) { 2391 if (WebAssembly::WasmEnableExnref) 2392 placeTryTableMarker(MBB); 2393 else 2394 placeTryMarker(MBB); 2395 } 2396 } else { 2397 // Place the BLOCK for MBB if MBB is branched to from above. 2398 placeBlockMarker(MBB); 2399 } 2400 } 2401 2402 // Fix mismatches in unwind destinations induced by linearizing the code. 2403 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 2404 MF.getFunction().hasPersonalityFn()) { 2405 bool MismatchFixed = fixCallUnwindMismatches(MF); 2406 MismatchFixed |= fixCatchUnwindMismatches(MF); 2407 if (MismatchFixed) 2408 recalculateScopeTops(MF); 2409 } 2410 } 2411 2412 unsigned WebAssemblyCFGStackify::getBranchDepth( 2413 const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) { 2414 unsigned Depth = 0; 2415 for (auto X : reverse(Stack)) { 2416 if (X.first == MBB) 2417 break; 2418 ++Depth; 2419 } 2420 assert(Depth < Stack.size() && "Branch destination should be in scope"); 2421 return Depth; 2422 } 2423 2424 unsigned WebAssemblyCFGStackify::getDelegateDepth( 2425 const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) { 2426 if (MBB == FakeCallerBB) 2427 return Stack.size(); 2428 // Delegate's destination is either a catch or a another delegate BB. When the 2429 // destination is another delegate, we can compute the argument in the same 2430 // way as branches, because the target delegate BB only contains the single 2431 // delegate instruction. 2432 if (!MBB->isEHPad()) // Target is a delegate BB 2433 return getBranchDepth(Stack, MBB); 2434 2435 // When the delegate's destination is a catch BB, we need to use its 2436 // corresponding try's end_try BB because Stack contains each marker's end BB. 2437 // Also we need to check if the end marker instruction matches, because a 2438 // single BB can contain multiple end markers, like this: 2439 // bb: 2440 // END_BLOCK 2441 // END_TRY 2442 // END_BLOCK 2443 // END_TRY 2444 // ... 2445 // 2446 // In case of branches getting the immediate that targets any of these is 2447 // fine, but delegate has to exactly target the correct try. 2448 unsigned Depth = 0; 2449 const MachineInstr *EndTry = BeginToEnd[EHPadToTry[MBB]]; 2450 for (auto X : reverse(Stack)) { 2451 if (X.first == EndTry->getParent() && X.second == EndTry) 2452 break; 2453 ++Depth; 2454 } 2455 assert(Depth < Stack.size() && "Delegate destination should be in scope"); 2456 return Depth; 2457 } 2458 2459 unsigned WebAssemblyCFGStackify::getRethrowDepth( 2460 const SmallVectorImpl<EndMarkerInfo> &Stack, 2461 const SmallVectorImpl<const MachineBasicBlock *> &EHPadStack) { 2462 unsigned Depth = 0; 2463 // In our current implementation, rethrows always rethrow the exception caught 2464 // by the innermost enclosing catch. This means while traversing Stack in the 2465 // reverse direction, when we encounter END_TRY, we should check if the 2466 // END_TRY corresponds to the current innermost EH pad. For example: 2467 // try 2468 // ... 2469 // catch ;; (a) 2470 // try 2471 // rethrow 1 ;; (b) 2472 // catch ;; (c) 2473 // rethrow 0 ;; (d) 2474 // end ;; (e) 2475 // end ;; (f) 2476 // 2477 // When we are at 'rethrow' (d), while reversely traversing Stack the first 2478 // 'end' we encounter is the 'end' (e), which corresponds to the 'catch' (c). 2479 // And 'rethrow' (d) rethrows the exception caught by 'catch' (c), so we stop 2480 // there and the depth should be 0. But when we are at 'rethrow' (b), it 2481 // rethrows the exception caught by 'catch' (a), so when traversing Stack 2482 // reversely, we should skip the 'end' (e) and choose 'end' (f), which 2483 // corresponds to 'catch' (a). 2484 for (auto X : reverse(Stack)) { 2485 const MachineInstr *End = X.second; 2486 if (End->getOpcode() == WebAssembly::END_TRY) { 2487 auto *EHPad = TryToEHPad[EndToBegin[End]]; 2488 if (EHPadStack.back() == EHPad) 2489 break; 2490 } 2491 ++Depth; 2492 } 2493 assert(Depth < Stack.size() && "Rethrow destination should be in scope"); 2494 return Depth; 2495 } 2496 2497 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 2498 // Now rewrite references to basic blocks to be depth immediates. 2499 SmallVector<EndMarkerInfo, 8> Stack; 2500 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 2501 2502 auto RewriteOperands = [&](MachineInstr &MI) { 2503 // Rewrite MBB operands to be depth immediates. 2504 SmallVector<MachineOperand, 4> Ops(MI.operands()); 2505 while (MI.getNumOperands() > 0) 2506 MI.removeOperand(MI.getNumOperands() - 1); 2507 for (auto MO : Ops) { 2508 if (MO.isMBB()) { 2509 if (MI.getOpcode() == WebAssembly::DELEGATE) 2510 MO = MachineOperand::CreateImm(getDelegateDepth(Stack, MO.getMBB())); 2511 else 2512 MO = MachineOperand::CreateImm(getBranchDepth(Stack, MO.getMBB())); 2513 } 2514 MI.addOperand(MF, MO); 2515 } 2516 }; 2517 2518 for (auto &MBB : reverse(MF)) { 2519 for (MachineInstr &MI : llvm::reverse(MBB)) { 2520 switch (MI.getOpcode()) { 2521 case WebAssembly::BLOCK: 2522 case WebAssembly::TRY: 2523 assert(ScopeTops[Stack.back().first->getNumber()]->getNumber() <= 2524 MBB.getNumber() && 2525 "Block/try/try_table marker should be balanced"); 2526 Stack.pop_back(); 2527 break; 2528 2529 case WebAssembly::TRY_TABLE: 2530 assert(ScopeTops[Stack.back().first->getNumber()]->getNumber() <= 2531 MBB.getNumber() && 2532 "Block/try/try_table marker should be balanced"); 2533 Stack.pop_back(); 2534 RewriteOperands(MI); 2535 break; 2536 2537 case WebAssembly::LOOP: 2538 assert(Stack.back().first == &MBB && "Loop top should be balanced"); 2539 Stack.pop_back(); 2540 break; 2541 2542 case WebAssembly::END_TRY: { 2543 auto *EHPad = TryToEHPad[EndToBegin[&MI]]; 2544 EHPadStack.push_back(EHPad); 2545 [[fallthrough]]; 2546 } 2547 case WebAssembly::END_BLOCK: 2548 case WebAssembly::END_TRY_TABLE: 2549 Stack.push_back(std::make_pair(&MBB, &MI)); 2550 break; 2551 2552 case WebAssembly::END_LOOP: 2553 Stack.push_back(std::make_pair(EndToBegin[&MI]->getParent(), &MI)); 2554 break; 2555 2556 case WebAssembly::CATCH_LEGACY: 2557 case WebAssembly::CATCH_ALL_LEGACY: 2558 EHPadStack.pop_back(); 2559 break; 2560 2561 case WebAssembly::RETHROW: 2562 MI.getOperand(0).setImm(getRethrowDepth(Stack, EHPadStack)); 2563 break; 2564 2565 case WebAssembly::DELEGATE: 2566 RewriteOperands(MI); 2567 Stack.push_back(std::make_pair(&MBB, &MI)); 2568 break; 2569 2570 default: 2571 if (MI.isTerminator()) 2572 RewriteOperands(MI); 2573 break; 2574 } 2575 } 2576 } 2577 assert(Stack.empty() && "Control flow should be balanced"); 2578 } 2579 2580 void WebAssemblyCFGStackify::cleanupFunctionData(MachineFunction &MF) { 2581 if (FakeCallerBB) 2582 MF.deleteMachineBasicBlock(FakeCallerBB); 2583 AppendixBB = FakeCallerBB = CallerTrampolineBB = nullptr; 2584 } 2585 2586 void WebAssemblyCFGStackify::releaseMemory() { 2587 ScopeTops.clear(); 2588 BeginToEnd.clear(); 2589 EndToBegin.clear(); 2590 TryToEHPad.clear(); 2591 EHPadToTry.clear(); 2592 UnwindDestToTrampoline.clear(); 2593 } 2594 2595 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 2596 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 2597 "********** Function: " 2598 << MF.getName() << '\n'); 2599 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 2600 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 2601 2602 releaseMemory(); 2603 2604 // Liveness is not tracked for VALUE_STACK physreg. 2605 MF.getRegInfo().invalidateLiveness(); 2606 2607 // Place the BLOCK/LOOP/TRY/TRY_TABLE markers to indicate the beginnings of 2608 // scopes. 2609 placeMarkers(MF); 2610 2611 // Remove unnecessary instructions possibly introduced by try/end_trys. 2612 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 2613 MF.getFunction().hasPersonalityFn() && !WebAssembly::WasmEnableExnref) 2614 removeUnnecessaryInstrs(MF); 2615 2616 // Convert MBB operands in terminators to relative depth immediates. 2617 rewriteDepthImmediates(MF); 2618 2619 // Fix up block/loop/try/try_table signatures at the end of the function to 2620 // conform to WebAssembly's rules. 2621 fixEndsAtEndOfFunction(MF); 2622 2623 // Add an end instruction at the end of the function body. 2624 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2625 appendEndToFunction(MF, TII); 2626 2627 cleanupFunctionData(MF); 2628 2629 MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified(); 2630 return true; 2631 } 2632