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