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 const auto &TLI = 856 *MF.getSubtarget<WebAssemblySubtarget>().getTargetLowering(); 857 WebAssembly::BlockType PtrTy = 858 TLI.getPointerTy(MF.getDataLayout()) == MVT::i32 859 ? WebAssembly::BlockType::I32 860 : WebAssembly::BlockType::I64; 861 auto *Catch = WebAssembly::findCatch(&MBB); 862 switch (Catch->getOpcode()) { 863 case WebAssembly::CATCH: 864 // CATCH's destination block's return type is the extracted value type, 865 // which is currently the thrown value's pointer type for all supported 866 // tags. 867 BlockMIB.addImm(int64_t(PtrTy)); 868 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH); 869 for (const auto &Use : Catch->uses()) { 870 // The only use operand a CATCH can have is the tag symbol. 871 TryTableMIB.addExternalSymbol(Use.getSymbolName()); 872 break; 873 } 874 TryTableMIB.addMBB(&MBB); 875 break; 876 case WebAssembly::CATCH_REF: 877 // CATCH_REF's destination block's return type is the extracted value type 878 // followed by an exnref, which is (i32, exnref) in our case. We assign the 879 // actual multiavlue signature in MCInstLower. MO_CATCH_BLOCK_SIG signals 880 // that this operand is used for catch_ref's multivalue destination. 881 BlockMIB.addImm(int64_t(WebAssembly::BlockType::Multivalue)); 882 Block->getOperand(0).setTargetFlags(WebAssemblyII::MO_CATCH_BLOCK_SIG); 883 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH_REF); 884 for (const auto &Use : Catch->uses()) { 885 TryTableMIB.addExternalSymbol(Use.getSymbolName()); 886 break; 887 } 888 TryTableMIB.addMBB(&MBB); 889 break; 890 case WebAssembly::CATCH_ALL: 891 // CATCH_ALL's destination block's return type is void. 892 BlockMIB.addImm(int64_t(WebAssembly::BlockType::Void)); 893 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH_ALL); 894 TryTableMIB.addMBB(&MBB); 895 break; 896 case WebAssembly::CATCH_ALL_REF: 897 // CATCH_ALL_REF's destination block's return type is exnref. 898 BlockMIB.addImm(int64_t(WebAssembly::BlockType::Exnref)); 899 TryTableMIB.addImm(wasm::WASM_OPCODE_CATCH_ALL_REF); 900 TryTableMIB.addMBB(&MBB); 901 break; 902 } 903 904 // Decide where in MBB to put the END_TRY_TABLE, and the END_BLOCK for the 905 // CATCH destination. 906 BeforeSet.clear(); 907 AfterSet.clear(); 908 for (const auto &MI : MBB) { 909 #ifndef NDEBUG 910 // END_TRY_TABLE should precede existing LOOP markers. 911 if (MI.getOpcode() == WebAssembly::LOOP) 912 AfterSet.insert(&MI); 913 #endif 914 915 // If there is a previously placed END_LOOP marker and the header of the 916 // loop is above this try_table's header, the END_LOOP should be placed 917 // after the END_TRY_TABLE, because the loop contains this block. Otherwise 918 // the END_LOOP should be placed before the END_TRY_TABLE. 919 if (MI.getOpcode() == WebAssembly::END_LOOP) { 920 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 921 BeforeSet.insert(&MI); 922 #ifndef NDEBUG 923 else 924 AfterSet.insert(&MI); 925 #endif 926 } 927 928 #ifndef NDEBUG 929 // CATCH, CATCH_REF, CATCH_ALL, and CATCH_ALL_REF are pseudo-instructions 930 // that simulate the block return value, so they should be placed after the 931 // END_TRY_TABLE. 932 if (WebAssembly::isCatch(MI.getOpcode())) 933 AfterSet.insert(&MI); 934 #endif 935 } 936 937 // Mark the end of the TRY_TABLE and the BLOCK. 938 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 939 MachineInstr *EndTryTable = 940 BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 941 TII.get(WebAssembly::END_TRY_TABLE)); 942 registerTryScope(TryTable, EndTryTable, &MBB); 943 MachineInstr *EndBlock = 944 BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 945 TII.get(WebAssembly::END_BLOCK)); 946 registerScope(Block, EndBlock); 947 948 // Track the farthest-spanning scope that ends at this point. 949 // Unlike the end_try, even if we don't put a end marker at the end of catch 950 // block, we still have to create two mappings: (BB with 'end_try_table' -> BB 951 // with 'try_table') and (BB after the (conceptual) catch block -> BB with 952 // 'try_table'). 953 // 954 // This is what can happen if we don't create the latter mapping: 955 // 956 // Suppoe in the legacy EH we have this code: 957 // try 958 // try 959 // code1 960 // catch (a) 961 // end_try 962 // code2 963 // catch (b) 964 // end_try 965 // 966 // If we don't create the latter mapping, try_table markers would be placed 967 // like this: 968 // try_table 969 // code1 970 // end_try_table (a) 971 // try_table 972 // code2 973 // end_try_table (b) 974 // 975 // This does not reflect the original structure, and more important problem 976 // is, in case 'code1' has an unwind mismatch and should unwind to 977 // 'end_try_table (b)' rather than 'end_try_table (a)', we don't have a way to 978 // make it jump after 'end_try_table (b)' without creating another block. So 979 // even if we don't place 'end_try' marker at the end of 'catch' block 980 // anymore, we create ScopeTops mapping the same way as the legacy exception, 981 // so the resulting code will look like: 982 // try_table 983 // try_table 984 // code1 985 // end_try_table (a) 986 // code2 987 // end_try_table (b) 988 for (auto *End : {&MBB, Cont}) 989 updateScopeTops(Header, End); 990 } 991 992 void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) { 993 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 994 995 // When there is an unconditional branch right before a catch instruction and 996 // it branches to the end of end_try marker, we don't need the branch, because 997 // if there is no exception, the control flow transfers to that point anyway. 998 // bb0: 999 // try 1000 // ... 1001 // br bb2 <- Not necessary 1002 // bb1 (ehpad): 1003 // catch 1004 // ... 1005 // bb2: <- Continuation BB 1006 // end 1007 // 1008 // A more involved case: When the BB where 'end' is located is an another EH 1009 // pad, the Cont (= continuation) BB is that EH pad's 'end' BB. For example, 1010 // bb0: 1011 // try 1012 // try 1013 // ... 1014 // br bb3 <- Not necessary 1015 // bb1 (ehpad): 1016 // catch 1017 // bb2 (ehpad): 1018 // end 1019 // catch 1020 // ... 1021 // bb3: <- Continuation BB 1022 // end 1023 // 1024 // When the EH pad at hand is bb1, its matching end_try is in bb2. But it is 1025 // another EH pad, so bb0's continuation BB becomes bb3. So 'br bb3' in the 1026 // code can be deleted. This is why we run 'while' until 'Cont' is not an EH 1027 // pad. 1028 for (auto &MBB : MF) { 1029 if (!MBB.isEHPad()) 1030 continue; 1031 1032 MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 1033 SmallVector<MachineOperand, 4> Cond; 1034 MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode(); 1035 1036 MachineBasicBlock *Cont = &MBB; 1037 while (Cont->isEHPad()) { 1038 MachineInstr *Try = EHPadToTry[Cont]; 1039 MachineInstr *EndTry = BeginToEnd[Try]; 1040 // We started from an EH pad, so the end marker cannot be a delegate 1041 assert(EndTry->getOpcode() != WebAssembly::DELEGATE); 1042 Cont = EndTry->getParent(); 1043 } 1044 1045 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 1046 // This condition means either 1047 // 1. This BB ends with a single unconditional branch whose destinaion is 1048 // Cont. 1049 // 2. This BB ends with a conditional branch followed by an unconditional 1050 // branch, and the unconditional branch's destination is Cont. 1051 // In both cases, we want to remove the last (= unconditional) branch. 1052 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) || 1053 (!Cond.empty() && FBB && FBB == Cont))) { 1054 bool ErasedUncondBr = false; 1055 (void)ErasedUncondBr; 1056 for (auto I = EHPadLayoutPred->end(), E = EHPadLayoutPred->begin(); 1057 I != E; --I) { 1058 auto PrevI = std::prev(I); 1059 if (PrevI->isTerminator()) { 1060 assert(PrevI->getOpcode() == WebAssembly::BR); 1061 PrevI->eraseFromParent(); 1062 ErasedUncondBr = true; 1063 break; 1064 } 1065 } 1066 assert(ErasedUncondBr && "Unconditional branch not erased!"); 1067 } 1068 } 1069 1070 // When there are block / end_block markers that overlap with try / end_try 1071 // markers, and the block and try markers' return types are the same, the 1072 // block /end_block markers are not necessary, because try / end_try markers 1073 // also can serve as boundaries for branches. 1074 // block <- Not necessary 1075 // try 1076 // ... 1077 // catch 1078 // ... 1079 // end 1080 // end <- Not necessary 1081 SmallVector<MachineInstr *, 32> ToDelete; 1082 for (auto &MBB : MF) { 1083 for (auto &MI : MBB) { 1084 if (MI.getOpcode() != WebAssembly::TRY) 1085 continue; 1086 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try]; 1087 if (EndTry->getOpcode() == WebAssembly::DELEGATE) 1088 continue; 1089 1090 MachineBasicBlock *TryBB = Try->getParent(); 1091 MachineBasicBlock *Cont = EndTry->getParent(); 1092 int64_t RetType = Try->getOperand(0).getImm(); 1093 for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator()); 1094 B != TryBB->begin() && E != Cont->end() && 1095 std::prev(B)->getOpcode() == WebAssembly::BLOCK && 1096 E->getOpcode() == WebAssembly::END_BLOCK && 1097 std::prev(B)->getOperand(0).getImm() == RetType; 1098 --B, ++E) { 1099 ToDelete.push_back(&*std::prev(B)); 1100 ToDelete.push_back(&*E); 1101 } 1102 } 1103 } 1104 for (auto *MI : ToDelete) { 1105 if (MI->getOpcode() == WebAssembly::BLOCK) 1106 unregisterScope(MI); 1107 MI->eraseFromParent(); 1108 } 1109 } 1110 1111 // When MBB is split into MBB and Split, we should unstackify defs in MBB that 1112 // have their uses in Split. 1113 static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, 1114 MachineBasicBlock &Split) { 1115 MachineFunction &MF = *MBB.getParent(); 1116 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1117 auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1118 auto &MRI = MF.getRegInfo(); 1119 1120 for (auto &MI : Split) { 1121 for (auto &MO : MI.explicit_uses()) { 1122 if (!MO.isReg() || MO.getReg().isPhysical()) 1123 continue; 1124 if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg())) 1125 if (Def->getParent() == &MBB) 1126 MFI.unstackifyVReg(MO.getReg()); 1127 } 1128 } 1129 1130 // In RegStackify, when a register definition is used multiple times, 1131 // Reg = INST ... 1132 // INST ..., Reg, ... 1133 // INST ..., Reg, ... 1134 // INST ..., Reg, ... 1135 // 1136 // we introduce a TEE, which has the following form: 1137 // DefReg = INST ... 1138 // TeeReg, Reg = TEE_... DefReg 1139 // INST ..., TeeReg, ... 1140 // INST ..., Reg, ... 1141 // INST ..., Reg, ... 1142 // with DefReg and TeeReg stackified but Reg not stackified. 1143 // 1144 // But the invariant that TeeReg should be stackified can be violated while we 1145 // unstackify registers in the split BB above. In this case, we convert TEEs 1146 // into two COPYs. This COPY will be eventually eliminated in ExplicitLocals. 1147 // DefReg = INST ... 1148 // TeeReg = COPY DefReg 1149 // Reg = COPY DefReg 1150 // INST ..., TeeReg, ... 1151 // INST ..., Reg, ... 1152 // INST ..., Reg, ... 1153 for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { 1154 if (!WebAssembly::isTee(MI.getOpcode())) 1155 continue; 1156 Register TeeReg = MI.getOperand(0).getReg(); 1157 Register Reg = MI.getOperand(1).getReg(); 1158 Register DefReg = MI.getOperand(2).getReg(); 1159 if (!MFI.isVRegStackified(TeeReg)) { 1160 // Now we are not using TEE anymore, so unstackify DefReg too 1161 MFI.unstackifyVReg(DefReg); 1162 unsigned CopyOpc = 1163 WebAssembly::getCopyOpcodeForRegClass(MRI.getRegClass(DefReg)); 1164 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), TeeReg) 1165 .addReg(DefReg); 1166 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), Reg).addReg(DefReg); 1167 MI.eraseFromParent(); 1168 } 1169 } 1170 } 1171 1172 // Wrap the given range of instructions with a try-delegate that targets 1173 // 'UnwindDest'. RangeBegin and RangeEnd are inclusive. 1174 void WebAssemblyCFGStackify::addNestedTryDelegate( 1175 MachineInstr *RangeBegin, MachineInstr *RangeEnd, 1176 MachineBasicBlock *UnwindDest) { 1177 auto *BeginBB = RangeBegin->getParent(); 1178 auto *EndBB = RangeEnd->getParent(); 1179 MachineFunction &MF = *BeginBB->getParent(); 1180 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1181 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1182 1183 // Local expression tree before the first call of this range should go 1184 // after the nested TRY. 1185 SmallPtrSet<const MachineInstr *, 4> AfterSet; 1186 AfterSet.insert(RangeBegin); 1187 for (auto I = MachineBasicBlock::iterator(RangeBegin), E = BeginBB->begin(); 1188 I != E; --I) { 1189 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 1190 continue; 1191 if (WebAssembly::isChild(*std::prev(I), MFI)) 1192 AfterSet.insert(&*std::prev(I)); 1193 else 1194 break; 1195 } 1196 1197 // Create the nested try instruction. 1198 auto TryPos = getLatestInsertPos( 1199 BeginBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet); 1200 MachineInstr *Try = BuildMI(*BeginBB, TryPos, RangeBegin->getDebugLoc(), 1201 TII.get(WebAssembly::TRY)) 1202 .addImm(int64_t(WebAssembly::BlockType::Void)); 1203 1204 // Create a BB to insert the 'delegate' instruction. 1205 MachineBasicBlock *DelegateBB = MF.CreateMachineBasicBlock(); 1206 // If the destination of 'delegate' is not the caller, adds the destination to 1207 // the BB's successors. 1208 if (UnwindDest != FakeCallerBB) 1209 DelegateBB->addSuccessor(UnwindDest); 1210 1211 auto SplitPos = std::next(RangeEnd->getIterator()); 1212 if (SplitPos == EndBB->end()) { 1213 // If the range's end instruction is at the end of the BB, insert the new 1214 // delegate BB after the current BB. 1215 MF.insert(std::next(EndBB->getIterator()), DelegateBB); 1216 EndBB->addSuccessor(DelegateBB); 1217 1218 } else { 1219 // When the split pos is in the middle of a BB, we split the BB into two and 1220 // put the 'delegate' BB in between. We normally create a split BB and make 1221 // it a successor of the original BB (CatchAfterSplit == false), but in case 1222 // the BB is an EH pad and there is a 'catch' after the split pos 1223 // (CatchAfterSplit == true), we should preserve the BB's property, 1224 // including that it is an EH pad, in the later part of the BB, where the 1225 // 'catch' is. 1226 bool CatchAfterSplit = false; 1227 if (EndBB->isEHPad()) { 1228 for (auto I = MachineBasicBlock::iterator(SplitPos), E = EndBB->end(); 1229 I != E; ++I) { 1230 if (WebAssembly::isCatch(I->getOpcode())) { 1231 CatchAfterSplit = true; 1232 break; 1233 } 1234 } 1235 } 1236 1237 MachineBasicBlock *PreBB = nullptr, *PostBB = nullptr; 1238 if (!CatchAfterSplit) { 1239 // If the range's end instruction is in the middle of the BB, we split the 1240 // BB into two and insert the delegate BB in between. 1241 // - Before: 1242 // bb: 1243 // range_end 1244 // other_insts 1245 // 1246 // - After: 1247 // pre_bb: (previous 'bb') 1248 // range_end 1249 // delegate_bb: (new) 1250 // delegate 1251 // post_bb: (new) 1252 // other_insts 1253 PreBB = EndBB; 1254 PostBB = MF.CreateMachineBasicBlock(); 1255 MF.insert(std::next(PreBB->getIterator()), PostBB); 1256 MF.insert(std::next(PreBB->getIterator()), DelegateBB); 1257 PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->end()); 1258 PostBB->transferSuccessors(PreBB); 1259 } else { 1260 // - Before: 1261 // ehpad: 1262 // range_end 1263 // catch 1264 // ... 1265 // 1266 // - After: 1267 // pre_bb: (new) 1268 // range_end 1269 // delegate_bb: (new) 1270 // delegate 1271 // post_bb: (previous 'ehpad') 1272 // catch 1273 // ... 1274 assert(EndBB->isEHPad()); 1275 PreBB = MF.CreateMachineBasicBlock(); 1276 PostBB = EndBB; 1277 MF.insert(PostBB->getIterator(), PreBB); 1278 MF.insert(PostBB->getIterator(), DelegateBB); 1279 PreBB->splice(PreBB->end(), PostBB, PostBB->begin(), SplitPos); 1280 // We don't need to transfer predecessors of the EH pad to 'PreBB', 1281 // because an EH pad's predecessors are all through unwind edges and they 1282 // should still unwind to the EH pad, not PreBB. 1283 } 1284 unstackifyVRegsUsedInSplitBB(*PreBB, *PostBB); 1285 PreBB->addSuccessor(DelegateBB); 1286 PreBB->addSuccessor(PostBB); 1287 } 1288 1289 // Add a 'delegate' instruction in the delegate BB created above. 1290 MachineInstr *Delegate = BuildMI(DelegateBB, RangeEnd->getDebugLoc(), 1291 TII.get(WebAssembly::DELEGATE)) 1292 .addMBB(UnwindDest); 1293 registerTryScope(Try, Delegate, nullptr); 1294 } 1295 1296 // Given an unwind destination, return a trampoline BB. A trampoline BB is a 1297 // destination of a nested try_table inserted to fix an unwind mismatch. It 1298 // contains an end_block, which is the target of the try_table, and a throw_ref, 1299 // to rethrow the exception to the right try_table. 1300 // try_table (catch ... ) 1301 // block exnref 1302 // ... 1303 // try_table (catch_all_ref N) 1304 // some code 1305 // end_try_table 1306 // ... 1307 // unreachable 1308 // end_block ;; Trampoline BB 1309 // throw_ref 1310 // end_try_table 1311 MachineBasicBlock * 1312 WebAssemblyCFGStackify::getTrampolineBlock(MachineBasicBlock *UnwindDest) { 1313 // We need one trampoline BB per unwind destination, even though there are 1314 // multiple try_tables target the same unwind destination. If we have already 1315 // created one for the given UnwindDest, return it. 1316 auto It = UnwindDestToTrampoline.find(UnwindDest); 1317 if (It != UnwindDestToTrampoline.end()) 1318 return It->second; 1319 1320 auto &MF = *UnwindDest->getParent(); 1321 auto &MRI = MF.getRegInfo(); 1322 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1323 1324 MachineInstr *Block = nullptr; 1325 MachineBasicBlock *TrampolineBB = nullptr; 1326 DebugLoc EndDebugLoc; 1327 1328 if (UnwindDest == getFakeCallerBlock(MF)) { 1329 // If the unwind destination is the caller, create a caller-dedicated 1330 // trampoline BB at the end of the function and wrap the whole function with 1331 // a block. 1332 auto BeginPos = MF.begin()->begin(); 1333 while (WebAssembly::isArgument(BeginPos->getOpcode())) 1334 BeginPos++; 1335 Block = BuildMI(*MF.begin(), BeginPos, MF.begin()->begin()->getDebugLoc(), 1336 TII.get(WebAssembly::BLOCK)) 1337 .addImm(int64_t(WebAssembly::BlockType::Exnref)); 1338 TrampolineBB = getCallerTrampolineBlock(MF); 1339 MachineBasicBlock *PrevBB = &*std::prev(CallerTrampolineBB->getIterator()); 1340 EndDebugLoc = PrevBB->findPrevDebugLoc(PrevBB->end()); 1341 } else { 1342 // If the unwind destination is another EH pad, create a trampoline BB for 1343 // the unwind dest and insert a block instruction right after the target 1344 // try_table. 1345 auto *TargetBeginTry = EHPadToTry[UnwindDest]; 1346 auto *TargetEndTry = BeginToEnd[TargetBeginTry]; 1347 auto *TargetBeginBB = TargetBeginTry->getParent(); 1348 auto *TargetEndBB = TargetEndTry->getParent(); 1349 1350 Block = BuildMI(*TargetBeginBB, std::next(TargetBeginTry->getIterator()), 1351 TargetBeginTry->getDebugLoc(), TII.get(WebAssembly::BLOCK)) 1352 .addImm(int64_t(WebAssembly::BlockType::Exnref)); 1353 TrampolineBB = MF.CreateMachineBasicBlock(); 1354 EndDebugLoc = TargetEndTry->getDebugLoc(); 1355 MF.insert(TargetEndBB->getIterator(), TrampolineBB); 1356 TrampolineBB->addSuccessor(UnwindDest); 1357 } 1358 1359 // Insert an end_block, catch_all_ref (pseudo instruction), and throw_ref 1360 // instructions in the trampoline BB. 1361 MachineInstr *EndBlock = 1362 BuildMI(TrampolineBB, EndDebugLoc, TII.get(WebAssembly::END_BLOCK)); 1363 auto ExnReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass); 1364 BuildMI(TrampolineBB, EndDebugLoc, TII.get(WebAssembly::CATCH_ALL_REF)) 1365 .addDef(ExnReg); 1366 BuildMI(TrampolineBB, EndDebugLoc, TII.get(WebAssembly::THROW_REF)) 1367 .addReg(ExnReg); 1368 1369 // The trampoline BB's return type is exnref because it is a target of 1370 // catch_all_ref. But the body type of the block we just created is not. We 1371 // add an 'unreachable' right before the 'end_block' to make the code valid. 1372 MachineBasicBlock *TrampolineLayoutPred = TrampolineBB->getPrevNode(); 1373 BuildMI(TrampolineLayoutPred, TrampolineLayoutPred->findBranchDebugLoc(), 1374 TII.get(WebAssembly::UNREACHABLE)); 1375 1376 registerScope(Block, EndBlock); 1377 UnwindDestToTrampoline[UnwindDest] = TrampolineBB; 1378 return TrampolineBB; 1379 } 1380 1381 // Wrap the given range of instructions with a try_table-end_try_table that 1382 // targets 'UnwindDest'. RangeBegin and RangeEnd are inclusive. 1383 void WebAssemblyCFGStackify::addNestedTryTable(MachineInstr *RangeBegin, 1384 MachineInstr *RangeEnd, 1385 MachineBasicBlock *UnwindDest) { 1386 auto *BeginBB = RangeBegin->getParent(); 1387 auto *EndBB = RangeEnd->getParent(); 1388 1389 MachineFunction &MF = *BeginBB->getParent(); 1390 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1391 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1392 1393 // Get the trampoline BB that the new try_table will unwind to. 1394 auto *TrampolineBB = getTrampolineBlock(UnwindDest); 1395 1396 // Local expression tree before the first call of this range should go 1397 // after the nested TRY_TABLE. 1398 SmallPtrSet<const MachineInstr *, 4> AfterSet; 1399 AfterSet.insert(RangeBegin); 1400 for (auto I = MachineBasicBlock::iterator(RangeBegin), E = BeginBB->begin(); 1401 I != E; --I) { 1402 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 1403 continue; 1404 if (WebAssembly::isChild(*std::prev(I), MFI)) 1405 AfterSet.insert(&*std::prev(I)); 1406 else 1407 break; 1408 } 1409 1410 // Create the nested try_table instruction. 1411 auto TryTablePos = getLatestInsertPos( 1412 BeginBB, SmallPtrSet<const MachineInstr *, 4>(), AfterSet); 1413 MachineInstr *TryTable = 1414 BuildMI(*BeginBB, TryTablePos, RangeBegin->getDebugLoc(), 1415 TII.get(WebAssembly::TRY_TABLE)) 1416 .addImm(int64_t(WebAssembly::BlockType::Void)) 1417 .addImm(1) // # of catch clauses 1418 .addImm(wasm::WASM_OPCODE_CATCH_ALL_REF) 1419 .addMBB(TrampolineBB); 1420 1421 // Create a BB to insert the 'end_try_table' instruction. 1422 MachineBasicBlock *EndTryTableBB = MF.CreateMachineBasicBlock(); 1423 EndTryTableBB->addSuccessor(TrampolineBB); 1424 1425 auto SplitPos = std::next(RangeEnd->getIterator()); 1426 if (SplitPos == EndBB->end()) { 1427 // If the range's end instruction is at the end of the BB, insert the new 1428 // end_try_table BB after the current BB. 1429 MF.insert(std::next(EndBB->getIterator()), EndTryTableBB); 1430 EndBB->addSuccessor(EndTryTableBB); 1431 1432 } else { 1433 // When the split pos is in the middle of a BB, we split the BB into two and 1434 // put the 'end_try_table' BB in between. We normally create a split BB and 1435 // make it a successor of the original BB (CatchAfterSplit == false), but in 1436 // case the BB is an EH pad and there is a 'catch' after split pos 1437 // (CatchAfterSplit == true), we should preserve the BB's property, 1438 // including that it is an EH pad, in the later part of the BB, where the 1439 // 'catch' is. 1440 bool CatchAfterSplit = false; 1441 if (EndBB->isEHPad()) { 1442 for (auto I = MachineBasicBlock::iterator(SplitPos), E = EndBB->end(); 1443 I != E; ++I) { 1444 if (WebAssembly::isCatch(I->getOpcode())) { 1445 CatchAfterSplit = true; 1446 break; 1447 } 1448 } 1449 } 1450 1451 MachineBasicBlock *PreBB = nullptr, *PostBB = nullptr; 1452 if (!CatchAfterSplit) { 1453 // If the range's end instruction is in the middle of the BB, we split the 1454 // BB into two and insert the end_try_table BB in between. 1455 // - Before: 1456 // bb: 1457 // range_end 1458 // other_insts 1459 // 1460 // - After: 1461 // pre_bb: (previous 'bb') 1462 // range_end 1463 // end_try_table_bb: (new) 1464 // end_try_table 1465 // post_bb: (new) 1466 // other_insts 1467 PreBB = EndBB; 1468 PostBB = MF.CreateMachineBasicBlock(); 1469 MF.insert(std::next(PreBB->getIterator()), PostBB); 1470 MF.insert(std::next(PreBB->getIterator()), EndTryTableBB); 1471 PostBB->splice(PostBB->end(), PreBB, SplitPos, PreBB->end()); 1472 PostBB->transferSuccessors(PreBB); 1473 } else { 1474 // - Before: 1475 // ehpad: 1476 // range_end 1477 // catch 1478 // ... 1479 // 1480 // - After: 1481 // pre_bb: (new) 1482 // range_end 1483 // end_try_table_bb: (new) 1484 // end_try_table 1485 // post_bb: (previous 'ehpad') 1486 // catch 1487 // ... 1488 assert(EndBB->isEHPad()); 1489 PreBB = MF.CreateMachineBasicBlock(); 1490 PostBB = EndBB; 1491 MF.insert(PostBB->getIterator(), PreBB); 1492 MF.insert(PostBB->getIterator(), EndTryTableBB); 1493 PreBB->splice(PreBB->end(), PostBB, PostBB->begin(), SplitPos); 1494 // We don't need to transfer predecessors of the EH pad to 'PreBB', 1495 // because an EH pad's predecessors are all through unwind edges and they 1496 // should still unwind to the EH pad, not PreBB. 1497 } 1498 unstackifyVRegsUsedInSplitBB(*PreBB, *PostBB); 1499 PreBB->addSuccessor(EndTryTableBB); 1500 PreBB->addSuccessor(PostBB); 1501 } 1502 1503 // Add a 'end_try_table' instruction in the EndTryTable BB created above. 1504 MachineInstr *EndTryTable = BuildMI(EndTryTableBB, RangeEnd->getDebugLoc(), 1505 TII.get(WebAssembly::END_TRY_TABLE)); 1506 registerTryScope(TryTable, EndTryTable, nullptr); 1507 } 1508 1509 // In the standard (exnref) EH, we fix unwind mismatches by adding a new 1510 // block~end_block inside of the unwind destination try_table~end_try_table: 1511 // try_table ... 1512 // block exnref ;; (new) 1513 // ... 1514 // try_table (catch_all_ref N) ;; (new) to trampoline BB 1515 // code 1516 // end_try_table ;; (new) 1517 // ... 1518 // end_block ;; (new) trampoline BB 1519 // throw_ref ;; (new) 1520 // end_try_table 1521 // 1522 // To do this, we will create a new BB that will contain the new 'end_block' and 1523 // 'throw_ref' and insert it before the 'end_try_table' BB. 1524 // 1525 // But there are cases when there are 'end_loop'(s) before the 'end_try_table' 1526 // in the same BB. (There can't be 'end_block' before 'end_try_table' in the 1527 // same BB because EH pads can't be directly branched to.) Then after fixing 1528 // unwind mismatches this will create the mismatching markers like below: 1529 // bb0: 1530 // try_table 1531 // block exnref 1532 // ... 1533 // loop 1534 // ... 1535 // new_bb: 1536 // end_block 1537 // end_try_table_bb: 1538 // end_loop 1539 // end_try_table 1540 // 1541 // So if an end_try_table BB has an end_loop before the end_try_table, we split 1542 // the BB with the end_loop as a separate BB before the end_try_table BB, so 1543 // that after we fix the unwind mismatch, the code will be like: 1544 // bb0: 1545 // try_table 1546 // block exnref 1547 // ... 1548 // loop 1549 // ... 1550 // end_loop_bb: 1551 // end_loop 1552 // new_bb: 1553 // end_block 1554 // end_try_table_bb: 1555 // end_try_table 1556 static void splitEndLoopBB(MachineBasicBlock *EndTryTableBB) { 1557 auto &MF = *EndTryTableBB->getParent(); 1558 MachineInstr *EndTryTable = nullptr, *EndLoop = nullptr; 1559 for (auto &MI : reverse(*EndTryTableBB)) { 1560 if (MI.getOpcode() == WebAssembly::END_TRY_TABLE) { 1561 EndTryTable = &MI; 1562 continue; 1563 } 1564 if (EndTryTable && MI.getOpcode() == WebAssembly::END_LOOP) { 1565 EndLoop = &MI; 1566 break; 1567 } 1568 } 1569 if (!EndLoop) 1570 return; 1571 1572 auto *EndLoopBB = MF.CreateMachineBasicBlock(); 1573 MF.insert(EndTryTableBB->getIterator(), EndLoopBB); 1574 auto SplitPos = std::next(EndLoop->getIterator()); 1575 EndLoopBB->splice(EndLoopBB->end(), EndTryTableBB, EndTryTableBB->begin(), 1576 SplitPos); 1577 EndLoopBB->addSuccessor(EndTryTableBB); 1578 } 1579 1580 bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) { 1581 // This function is used for both the legacy EH and the standard (exnref) EH, 1582 // and the reason we have unwind mismatches is the same for the both of them, 1583 // but the code examples in the comments are going to be different. To make 1584 // the description less confusing, we write the basically same comments twice, 1585 // once for the legacy EH and the standard EH. 1586 // 1587 // -- Legacy EH -------------------------------------------------------------- 1588 // 1589 // Linearizing the control flow by placing TRY / END_TRY markers can create 1590 // mismatches in unwind destinations for throwing instructions, such as calls. 1591 // 1592 // We use the 'delegate' instruction to fix the unwind mismatches. 'delegate' 1593 // instruction delegates an exception to an outer 'catch'. It can target not 1594 // only 'catch' but all block-like structures including another 'delegate', 1595 // but with slightly different semantics than branches. When it targets a 1596 // 'catch', it will delegate the exception to that catch. It is being 1597 // discussed how to define the semantics when 'delegate''s target is a non-try 1598 // block: it will either be a validation failure or it will target the next 1599 // outer try-catch. But anyway our LLVM backend currently does not generate 1600 // such code. The example below illustrates where the 'delegate' instruction 1601 // in the middle will delegate the exception to, depending on the value of N. 1602 // try 1603 // try 1604 // block 1605 // try 1606 // try 1607 // call @foo 1608 // delegate N ;; Where will this delegate to? 1609 // catch ;; N == 0 1610 // end 1611 // end ;; N == 1 (invalid; will not be generated) 1612 // delegate ;; N == 2 1613 // catch ;; N == 3 1614 // end 1615 // ;; N == 4 (to caller) 1616 // 1617 // 1. When an instruction may throw, but the EH pad it will unwind to can be 1618 // different from the original CFG. 1619 // 1620 // Example: we have the following CFG: 1621 // bb0: 1622 // call @foo ; if it throws, unwind to bb2 1623 // bb1: 1624 // call @bar ; if it throws, unwind to bb3 1625 // bb2 (ehpad): 1626 // catch 1627 // ... 1628 // bb3 (ehpad) 1629 // catch 1630 // ... 1631 // 1632 // And the CFG is sorted in this order. Then after placing TRY markers, it 1633 // will look like: (BB markers are omitted) 1634 // try 1635 // try 1636 // call @foo 1637 // call @bar ;; if it throws, unwind to bb3 1638 // catch ;; ehpad (bb2) 1639 // ... 1640 // end_try 1641 // catch ;; ehpad (bb3) 1642 // ... 1643 // end_try 1644 // 1645 // Now if bar() throws, it is going to end up in bb2, not bb3, where it is 1646 // supposed to end up. We solve this problem by wrapping the mismatching call 1647 // with an inner try-delegate that rethrows the exception to the right 1648 // 'catch'. 1649 // 1650 // try 1651 // try 1652 // call @foo 1653 // try ;; (new) 1654 // call @bar 1655 // delegate 1 (bb3) ;; (new) 1656 // catch ;; ehpad (bb2) 1657 // ... 1658 // end_try 1659 // catch ;; ehpad (bb3) 1660 // ... 1661 // end_try 1662 // 1663 // --- 1664 // 2. The same as 1, but in this case an instruction unwinds to a caller 1665 // function and not another EH pad. 1666 // 1667 // Example: we have the following CFG: 1668 // bb0: 1669 // call @foo ; if it throws, unwind to bb2 1670 // bb1: 1671 // call @bar ; if it throws, unwind to caller 1672 // bb2 (ehpad): 1673 // catch 1674 // ... 1675 // 1676 // And the CFG is sorted in this order. Then after placing TRY markers, it 1677 // will look like: 1678 // try 1679 // call @foo 1680 // call @bar ;; if it throws, unwind to caller 1681 // catch ;; ehpad (bb2) 1682 // ... 1683 // end_try 1684 // 1685 // Now if bar() throws, it is going to end up in bb2, when it is supposed 1686 // throw up to the caller. We solve this problem in the same way, but in this 1687 // case 'delegate's immediate argument is the number of block depths + 1, 1688 // which means it rethrows to the caller. 1689 // try 1690 // call @foo 1691 // try ;; (new) 1692 // call @bar 1693 // delegate 1 (caller) ;; (new) 1694 // catch ;; ehpad (bb2) 1695 // ... 1696 // end_try 1697 // 1698 // Before rewriteDepthImmediates, delegate's argument is a BB. In case of the 1699 // caller, it will take a fake BB generated by getFakeCallerBlock(), which 1700 // will be converted to a correct immediate argument later. 1701 // 1702 // In case there are multiple calls in a BB that may throw to the caller, they 1703 // can be wrapped together in one nested try-delegate scope. (In 1, this 1704 // couldn't happen, because may-throwing instruction there had an unwind 1705 // destination, i.e., it was an invoke before, and there could be only one 1706 // invoke within a BB.) 1707 // 1708 // -- Standard EH ------------------------------------------------------------ 1709 // 1710 // Linearizing the control flow by placing TRY / END_TRY_TABLE markers can 1711 // create mismatches in unwind destinations for throwing instructions, such as 1712 // calls. 1713 // 1714 // We use the a nested 'try_table'~'end_try_table' instruction to fix the 1715 // unwind mismatches. try_table's catch clauses take an immediate argument 1716 // that specifics which block we should branch to. 1717 // 1718 // 1. When an instruction may throw, but the EH pad it will unwind to can be 1719 // different from the original CFG. 1720 // 1721 // Example: we have the following CFG: 1722 // bb0: 1723 // call @foo ; if it throws, unwind to bb2 1724 // bb1: 1725 // call @bar ; if it throws, unwind to bb3 1726 // bb2 (ehpad): 1727 // catch 1728 // ... 1729 // bb3 (ehpad) 1730 // catch 1731 // ... 1732 // 1733 // And the CFG is sorted in this order. Then after placing TRY_TABLE markers 1734 // (and BLOCK markers for the TRY_TABLE's destinations), it will look like: 1735 // (BB markers are omitted) 1736 // block 1737 // try_table (catch ... 0) 1738 // block 1739 // try_table (catch ... 0) 1740 // call @foo 1741 // call @bar ;; if it throws, unwind to bb3 1742 // end_try_table 1743 // end_block ;; ehpad (bb2) 1744 // ... 1745 // end_try_table 1746 // end_block ;; ehpad (bb3) 1747 // ... 1748 // 1749 // Now if bar() throws, it is going to end up in bb2, not bb3, where it is 1750 // supposed to end up. We solve this problem by wrapping the mismatching call 1751 // with an inner try_table~end_try_table that sends the exception to the the 1752 // 'trampoline' block, which rethrows, or 'bounces' it to the right 1753 // end_try_table: 1754 // block 1755 // try_table (catch ... 0) 1756 // block exnref ;; (new) 1757 // block 1758 // try_table (catch ... 0) 1759 // call @foo 1760 // try_table (catch_all_ref 2) ;; (new) to trampoline BB 1761 // call @bar 1762 // end_try_table ;; (new) 1763 // end_try_table 1764 // end_block ;; ehpad (bb2) 1765 // ... 1766 // end_block ;; (new) trampoline BB 1767 // throw_ref ;; (new) 1768 // end_try_table 1769 // end_block ;; ehpad (bb3) 1770 // 1771 // --- 1772 // 2. The same as 1, but in this case an instruction unwinds to a caller 1773 // function and not another EH pad. 1774 // 1775 // Example: we have the following CFG: 1776 // bb0: 1777 // call @foo ; if it throws, unwind to bb2 1778 // bb1: 1779 // call @bar ; if it throws, unwind to caller 1780 // bb2 (ehpad): 1781 // catch 1782 // ... 1783 // 1784 // And the CFG is sorted in this order. Then after placing TRY_TABLE markers 1785 // (and BLOCK markers for the TRY_TABLE's destinations), it will look like: 1786 // block 1787 // try_table (catch ... 0) 1788 // call @foo 1789 // call @bar ;; if it throws, unwind to caller 1790 // end_try_table 1791 // end_block ;; ehpad (bb2) 1792 // ... 1793 // 1794 // Now if bar() throws, it is going to end up in bb2, when it is supposed 1795 // throw up to the caller. We solve this problem in the same way, but in this 1796 // case 'delegate's immediate argument is the number of block depths + 1, 1797 // which means it rethrows to the caller. 1798 // block exnref ;; (new) 1799 // block 1800 // try_table (catch ... 0) 1801 // call @foo 1802 // try_table (catch_all_ref 2) ;; (new) to trampoline BB 1803 // call @bar 1804 // end_try_table ;; (new) 1805 // end_try_table 1806 // end_block ;; ehpad (bb2) 1807 // ... 1808 // end_block ;; (new) caller trampoline BB 1809 // throw_ref ;; (new) throw to the caller 1810 // 1811 // Before rewriteDepthImmediates, try_table's catch clauses' argument is a 1812 // trampoline BB from which we throw_ref the exception to the right 1813 // end_try_table. In case of the caller, it will take a new caller-dedicated 1814 // trampoline BB generated by getCallerTrampolineBlock(), which throws the 1815 // exception to the caller. 1816 // 1817 // In case there are multiple calls in a BB that may throw to the caller, they 1818 // can be wrapped together in one nested try_table-end_try_table scope. (In 1, 1819 // this couldn't happen, because may-throwing instruction there had an unwind 1820 // destination, i.e., it was an invoke before, and there could be only one 1821 // invoke within a BB.) 1822 1823 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 1824 // Range of intructions to be wrapped in a new nested try~delegate or 1825 // try_table~end_try_table. A range exists in a single BB and does not span 1826 // multiple BBs. 1827 using TryRange = std::pair<MachineInstr *, MachineInstr *>; 1828 // In original CFG, <unwind destination BB, a vector of try/try_table ranges> 1829 DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges; 1830 1831 // Gather possibly throwing calls (i.e., previously invokes) whose current 1832 // unwind destination is not the same as the original CFG. (Case 1) 1833 1834 for (auto &MBB : reverse(MF)) { 1835 bool SeenThrowableInstInBB = false; 1836 for (auto &MI : reverse(MBB)) { 1837 if (WebAssembly::isTry(MI.getOpcode())) 1838 EHPadStack.pop_back(); 1839 else if (WebAssembly::isCatch(MI.getOpcode())) 1840 EHPadStack.push_back(MI.getParent()); 1841 1842 // In this loop we only gather calls that have an EH pad to unwind. So 1843 // there will be at most 1 such call (= invoke) in a BB, so after we've 1844 // seen one, we can skip the rest of BB. Also if MBB has no EH pad 1845 // successor or MI does not throw, this is not an invoke. 1846 if (SeenThrowableInstInBB || !MBB.hasEHPadSuccessor() || 1847 !WebAssembly::mayThrow(MI)) 1848 continue; 1849 SeenThrowableInstInBB = true; 1850 1851 // If the EH pad on the stack top is where this instruction should unwind 1852 // next, we're good. 1853 MachineBasicBlock *UnwindDest = getFakeCallerBlock(MF); 1854 for (auto *Succ : MBB.successors()) { 1855 // Even though semantically a BB can have multiple successors in case an 1856 // exception is not caught by a catchpad, in our backend implementation 1857 // it is guaranteed that a BB can have at most one EH pad successor. For 1858 // details, refer to comments in findWasmUnwindDestinations function in 1859 // SelectionDAGBuilder.cpp. 1860 if (Succ->isEHPad()) { 1861 UnwindDest = Succ; 1862 break; 1863 } 1864 } 1865 if (EHPadStack.back() == UnwindDest) 1866 continue; 1867 1868 // Include EH_LABELs in the range before and after the invoke 1869 MachineInstr *RangeBegin = &MI, *RangeEnd = &MI; 1870 if (RangeBegin->getIterator() != MBB.begin() && 1871 std::prev(RangeBegin->getIterator())->isEHLabel()) 1872 RangeBegin = &*std::prev(RangeBegin->getIterator()); 1873 if (std::next(RangeEnd->getIterator()) != MBB.end() && 1874 std::next(RangeEnd->getIterator())->isEHLabel()) 1875 RangeEnd = &*std::next(RangeEnd->getIterator()); 1876 1877 // If not, record the range. 1878 UnwindDestToTryRanges[UnwindDest].push_back( 1879 TryRange(RangeBegin, RangeEnd)); 1880 LLVM_DEBUG(dbgs() << "- Call unwind mismatch: MBB = " << MBB.getName() 1881 << "\nCall = " << MI 1882 << "\nOriginal dest = " << UnwindDest->getName() 1883 << " Current dest = " << EHPadStack.back()->getName() 1884 << "\n\n"); 1885 } 1886 } 1887 1888 assert(EHPadStack.empty()); 1889 1890 // Gather possibly throwing calls that are supposed to unwind up to the caller 1891 // if they throw, but currently unwind to an incorrect destination. Unlike the 1892 // loop above, there can be multiple calls within a BB that unwind to the 1893 // caller, which we should group together in a range. (Case 2) 1894 1895 MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; // inclusive 1896 1897 // Record the range. 1898 auto RecordCallerMismatchRange = [&](const MachineBasicBlock *CurrentDest) { 1899 UnwindDestToTryRanges[getFakeCallerBlock(MF)].push_back( 1900 TryRange(RangeBegin, RangeEnd)); 1901 LLVM_DEBUG(dbgs() << "- Call unwind mismatch: MBB = " 1902 << RangeBegin->getParent()->getName() 1903 << "\nRange begin = " << *RangeBegin 1904 << "Range end = " << *RangeEnd 1905 << "\nOriginal dest = caller Current dest = " 1906 << CurrentDest->getName() << "\n\n"); 1907 RangeBegin = RangeEnd = nullptr; // Reset range pointers 1908 }; 1909 1910 for (auto &MBB : reverse(MF)) { 1911 bool SeenThrowableInstInBB = false; 1912 for (auto &MI : reverse(MBB)) { 1913 bool MayThrow = WebAssembly::mayThrow(MI); 1914 1915 // If MBB has an EH pad successor and this is the last instruction that 1916 // may throw, this instruction unwinds to the EH pad and not to the 1917 // caller. 1918 if (MBB.hasEHPadSuccessor() && MayThrow && !SeenThrowableInstInBB) 1919 SeenThrowableInstInBB = true; 1920 1921 // We wrap up the current range when we see a marker even if we haven't 1922 // finished a BB. 1923 else if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) 1924 RecordCallerMismatchRange(EHPadStack.back()); 1925 1926 // If EHPadStack is empty, that means it correctly unwinds to the caller 1927 // if it throws, so we're good. If MI does not throw, we're good too. 1928 else if (EHPadStack.empty() || !MayThrow) { 1929 } 1930 1931 // We found an instruction that unwinds to the caller but currently has an 1932 // incorrect unwind destination. Create a new range or increment the 1933 // currently existing range. 1934 else { 1935 if (!RangeEnd) 1936 RangeBegin = RangeEnd = &MI; 1937 else 1938 RangeBegin = &MI; 1939 } 1940 1941 // Update EHPadStack. 1942 if (WebAssembly::isTry(MI.getOpcode())) 1943 EHPadStack.pop_back(); 1944 else if (WebAssembly::isCatch(MI.getOpcode())) 1945 EHPadStack.push_back(MI.getParent()); 1946 } 1947 1948 if (RangeEnd) 1949 RecordCallerMismatchRange(EHPadStack.back()); 1950 } 1951 1952 assert(EHPadStack.empty()); 1953 1954 // We don't have any unwind destination mismatches to resolve. 1955 if (UnwindDestToTryRanges.empty()) 1956 return false; 1957 1958 // When end_loop is before end_try_table within the same BB in unwind 1959 // destinations, we should split the end_loop into another BB. 1960 if (!WebAssembly::WasmUseLegacyEH) 1961 for (auto &[UnwindDest, _] : UnwindDestToTryRanges) { 1962 auto It = EHPadToTry.find(UnwindDest); 1963 // If UnwindDest is the fake caller block, it will not be in EHPadToTry 1964 // map 1965 if (It != EHPadToTry.end()) { 1966 auto *TryTable = It->second; 1967 auto *EndTryTable = BeginToEnd[TryTable]; 1968 splitEndLoopBB(EndTryTable->getParent()); 1969 } 1970 } 1971 1972 // Now we fix the mismatches by wrapping calls with inner try-delegates. 1973 for (auto &P : UnwindDestToTryRanges) { 1974 NumCallUnwindMismatches += P.second.size(); 1975 MachineBasicBlock *UnwindDest = P.first; 1976 auto &TryRanges = P.second; 1977 1978 for (auto Range : TryRanges) { 1979 MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; 1980 std::tie(RangeBegin, RangeEnd) = Range; 1981 auto *MBB = RangeBegin->getParent(); 1982 1983 // If this BB has an EH pad successor, i.e., ends with an 'invoke', and if 1984 // the current range contains the invoke, now we are going to wrap the 1985 // invoke with try-delegate or try_table-end_try_table, making the 1986 // 'delegate' or 'end_try_table' BB the new successor instead, so remove 1987 // the EH pad succesor here. The BB may not have an EH pad successor if 1988 // calls in this BB throw to the caller. 1989 if (UnwindDest != getFakeCallerBlock(MF)) { 1990 MachineBasicBlock *EHPad = nullptr; 1991 for (auto *Succ : MBB->successors()) { 1992 if (Succ->isEHPad()) { 1993 EHPad = Succ; 1994 break; 1995 } 1996 } 1997 if (EHPad) 1998 MBB->removeSuccessor(EHPad); 1999 } 2000 2001 if (WebAssembly::WasmUseLegacyEH) 2002 addNestedTryDelegate(RangeBegin, RangeEnd, UnwindDest); 2003 else 2004 addNestedTryTable(RangeBegin, RangeEnd, UnwindDest); 2005 } 2006 } 2007 2008 return true; 2009 } 2010 2011 // Returns the single destination of try_table, if there is one. All try_table 2012 // we generate in this pass has a single destination, i.e., a single catch 2013 // clause. 2014 static MachineBasicBlock *getSingleUnwindDest(const MachineInstr *TryTable) { 2015 if (TryTable->getOperand(1).getImm() != 1) 2016 return nullptr; 2017 switch (TryTable->getOperand(2).getImm()) { 2018 case wasm::WASM_OPCODE_CATCH: 2019 case wasm::WASM_OPCODE_CATCH_REF: 2020 return TryTable->getOperand(4).getMBB(); 2021 case wasm::WASM_OPCODE_CATCH_ALL: 2022 case wasm::WASM_OPCODE_CATCH_ALL_REF: 2023 return TryTable->getOperand(3).getMBB(); 2024 default: 2025 llvm_unreachable("try_table: Invalid catch clause\n"); 2026 } 2027 } 2028 2029 bool WebAssemblyCFGStackify::fixCatchUnwindMismatches(MachineFunction &MF) { 2030 // This function is used for both the legacy EH and the standard (exnref) EH, 2031 // and the reason we have unwind mismatches is the same for the both of them, 2032 // but the code examples in the comments are going to be different. To make 2033 // the description less confusing, we write the basically same comments twice, 2034 // once for the legacy EH and the standard EH. 2035 // 2036 // -- Legacy EH -------------------------------------------------------------- 2037 // 2038 // There is another kind of unwind destination mismatches besides call unwind 2039 // mismatches, which we will call "catch unwind mismatches". See this example 2040 // after the marker placement: 2041 // try 2042 // try 2043 // call @foo 2044 // catch __cpp_exception ;; ehpad A (next unwind dest: caller) 2045 // ... 2046 // end_try 2047 // catch_all ;; ehpad B 2048 // ... 2049 // end_try 2050 // 2051 // 'call @foo's unwind destination is the ehpad A. But suppose 'call @foo' 2052 // throws a foreign exception that is not caught by ehpad A, and its next 2053 // destination should be the caller. But after control flow linearization, 2054 // another EH pad can be placed in between (e.g. ehpad B here), making the 2055 // next unwind destination incorrect. In this case, the foreign exception will 2056 // instead go to ehpad B and will be caught there instead. In this example the 2057 // correct next unwind destination is the caller, but it can be another outer 2058 // catch in other cases. 2059 // 2060 // There is no specific 'call' or 'throw' instruction to wrap with a 2061 // try-delegate, so we wrap the whole try-catch-end with a try-delegate and 2062 // make it rethrow to the right destination, which is the caller in the 2063 // example below: 2064 // try 2065 // try ;; (new) 2066 // try 2067 // call @foo 2068 // catch __cpp_exception ;; ehpad A (next unwind dest: caller) 2069 // ... 2070 // end_try 2071 // delegate 1 (caller) ;; (new) 2072 // catch_all ;; ehpad B 2073 // ... 2074 // end_try 2075 // 2076 // The right destination may be another EH pad or the caller. (The example 2077 // here shows the case it is the caller.) 2078 // 2079 // -- Standard EH ------------------------------------------------------------ 2080 // 2081 // There is another kind of unwind destination mismatches besides call unwind 2082 // mismatches, which we will call "catch unwind mismatches". See this example 2083 // after the marker placement: 2084 // block 2085 // try_table (catch_all_ref 0) 2086 // block 2087 // try_table (catch ... 0) 2088 // call @foo 2089 // end_try_table 2090 // end_block ;; ehpad A (next unwind dest: caller) 2091 // ... 2092 // end_try_table 2093 // end_block ;; ehpad B 2094 // ... 2095 // 2096 // 'call @foo's unwind destination is the ehpad A. But suppose 'call @foo' 2097 // throws a foreign exception that is not caught by ehpad A, and its next 2098 // destination should be the caller. But after control flow linearization, 2099 // another EH pad can be placed in between (e.g. ehpad B here), making the 2100 // next unwind destination incorrect. In this case, the foreign exception will 2101 // instead go to ehpad B and will be caught there instead. In this example the 2102 // correct next unwind destination is the caller, but it can be another outer 2103 // catch in other cases. 2104 // 2105 // There is no specific 'call' or 'throw' instruction to wrap with an inner 2106 // try_table-end_try_table, so we wrap the whole try_table-end_try_table with 2107 // an inner try_table-end_try_table that sends the exception to a trampoline 2108 // BB. We rethrow the sent exception using a throw_ref to the right 2109 // destination, which is the caller in the example below: 2110 // block exnref 2111 // block 2112 // try_table (catch_all_ref 0) 2113 // try_table (catch_all_ref 2) ;; (new) to trampoline 2114 // block 2115 // try_table (catch ... 0) 2116 // call @foo 2117 // end_try_table 2118 // end_block ;; ehpad A (next unwind dest: caller) 2119 // end_try_table ;; (new) 2120 // ... 2121 // end_try_table 2122 // end_block ;; ehpad B 2123 // ... 2124 // end_block ;; (new) caller trampoline BB 2125 // throw_ref ;; (new) throw to the caller 2126 // 2127 // The right destination may be another EH pad or the caller. (The example 2128 // here shows the case it is the caller.) 2129 2130 const auto *EHInfo = MF.getWasmEHFuncInfo(); 2131 assert(EHInfo); 2132 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 2133 // For EH pads that have catch unwind mismatches, a map of <EH pad, its 2134 // correct unwind destination>. 2135 DenseMap<MachineBasicBlock *, MachineBasicBlock *> EHPadToUnwindDest; 2136 2137 for (auto &MBB : reverse(MF)) { 2138 for (auto &MI : reverse(MBB)) { 2139 if (MI.getOpcode() == WebAssembly::TRY) 2140 EHPadStack.pop_back(); 2141 else if (MI.getOpcode() == WebAssembly::TRY_TABLE) { 2142 // We want to exclude try_tables created in fixCallUnwindMismatches. 2143 // Check if the try_table's unwind destination matches the EH pad stack 2144 // top. If it is created in fixCallUnwindMismatches, it wouldn't. 2145 if (getSingleUnwindDest(&MI) == EHPadStack.back()) 2146 EHPadStack.pop_back(); 2147 } else if (MI.getOpcode() == WebAssembly::DELEGATE) 2148 EHPadStack.push_back(&MBB); 2149 else if (WebAssembly::isCatch(MI.getOpcode())) { 2150 auto *EHPad = &MBB; 2151 2152 // If the BB has a catch pseudo instruction but is not marked as an EH 2153 // pad, it's a trampoline BB we created in fixCallUnwindMismatches. Skip 2154 // it. 2155 if (!EHPad->isEHPad()) 2156 continue; 2157 2158 // catch_all always catches an exception, so we don't need to do 2159 // anything 2160 if (WebAssembly::isCatchAll(MI.getOpcode())) { 2161 } 2162 2163 // This can happen when the unwind dest was removed during the 2164 // optimization, e.g. because it was unreachable. 2165 else if (EHPadStack.empty() && EHInfo->hasUnwindDest(EHPad)) { 2166 LLVM_DEBUG(dbgs() << "EHPad (" << EHPad->getName() 2167 << "'s unwind destination does not exist anymore" 2168 << "\n\n"); 2169 } 2170 2171 // The EHPad's next unwind destination is the caller, but we incorrectly 2172 // unwind to another EH pad. 2173 else if (!EHPadStack.empty() && !EHInfo->hasUnwindDest(EHPad)) { 2174 EHPadToUnwindDest[EHPad] = getFakeCallerBlock(MF); 2175 LLVM_DEBUG(dbgs() 2176 << "- Catch unwind mismatch:\nEHPad = " << EHPad->getName() 2177 << " Original dest = caller Current dest = " 2178 << EHPadStack.back()->getName() << "\n\n"); 2179 } 2180 2181 // The EHPad's next unwind destination is an EH pad, whereas we 2182 // incorrectly unwind to another EH pad. 2183 else if (!EHPadStack.empty() && EHInfo->hasUnwindDest(EHPad)) { 2184 auto *UnwindDest = EHInfo->getUnwindDest(EHPad); 2185 if (EHPadStack.back() != UnwindDest) { 2186 EHPadToUnwindDest[EHPad] = UnwindDest; 2187 LLVM_DEBUG(dbgs() << "- Catch unwind mismatch:\nEHPad = " 2188 << EHPad->getName() << " Original dest = " 2189 << UnwindDest->getName() << " Current dest = " 2190 << EHPadStack.back()->getName() << "\n\n"); 2191 } 2192 } 2193 2194 EHPadStack.push_back(EHPad); 2195 } 2196 } 2197 } 2198 2199 assert(EHPadStack.empty()); 2200 if (EHPadToUnwindDest.empty()) 2201 return false; 2202 2203 // When end_loop is before end_try_table within the same BB in unwind 2204 // destinations, we should split the end_loop into another BB. 2205 for (auto &[_, UnwindDest] : EHPadToUnwindDest) { 2206 auto It = EHPadToTry.find(UnwindDest); 2207 // If UnwindDest is the fake caller block, it will not be in EHPadToTry map 2208 if (It != EHPadToTry.end()) { 2209 auto *TryTable = It->second; 2210 auto *EndTryTable = BeginToEnd[TryTable]; 2211 splitEndLoopBB(EndTryTable->getParent()); 2212 } 2213 } 2214 2215 NumCatchUnwindMismatches += EHPadToUnwindDest.size(); 2216 SmallPtrSet<MachineBasicBlock *, 4> NewEndTryBBs; 2217 2218 for (auto &[EHPad, UnwindDest] : EHPadToUnwindDest) { 2219 MachineInstr *Try = EHPadToTry[EHPad]; 2220 MachineInstr *EndTry = BeginToEnd[Try]; 2221 if (WebAssembly::WasmUseLegacyEH) { 2222 addNestedTryDelegate(Try, EndTry, UnwindDest); 2223 NewEndTryBBs.insert(EndTry->getParent()); 2224 } else { 2225 addNestedTryTable(Try, EndTry, UnwindDest); 2226 } 2227 } 2228 2229 if (!WebAssembly::WasmUseLegacyEH) 2230 return true; 2231 2232 // Adding a try-delegate wrapping an existing try-catch-end can make existing 2233 // branch destination BBs invalid. For example, 2234 // 2235 // - Before: 2236 // bb0: 2237 // block 2238 // br bb3 2239 // bb1: 2240 // try 2241 // ... 2242 // bb2: (ehpad) 2243 // catch 2244 // bb3: 2245 // end_try 2246 // end_block ;; 'br bb3' targets here 2247 // 2248 // Suppose this try-catch-end has a catch unwind mismatch, so we need to wrap 2249 // this with a try-delegate. Then this becomes: 2250 // 2251 // - After: 2252 // bb0: 2253 // block 2254 // br bb3 ;; invalid destination! 2255 // bb1: 2256 // try ;; (new instruction) 2257 // try 2258 // ... 2259 // bb2: (ehpad) 2260 // catch 2261 // bb3: 2262 // end_try ;; 'br bb3' still incorrectly targets here! 2263 // delegate_bb: ;; (new BB) 2264 // delegate ;; (new instruction) 2265 // split_bb: ;; (new BB) 2266 // end_block 2267 // 2268 // Now 'br bb3' incorrectly branches to an inner scope. 2269 // 2270 // As we can see in this case, when branches target a BB that has both 2271 // 'end_try' and 'end_block' and the BB is split to insert a 'delegate', we 2272 // have to remap existing branch destinations so that they target not the 2273 // 'end_try' BB but the new 'end_block' BB. There can be multiple 'delegate's 2274 // in between, so we try to find the next BB with 'end_block' instruction. In 2275 // this example, the 'br bb3' instruction should be remapped to 'br split_bb'. 2276 for (auto &MBB : MF) { 2277 for (auto &MI : MBB) { 2278 if (MI.isTerminator()) { 2279 for (auto &MO : MI.operands()) { 2280 if (MO.isMBB() && NewEndTryBBs.count(MO.getMBB())) { 2281 auto *BrDest = MO.getMBB(); 2282 bool FoundEndBlock = false; 2283 for (; std::next(BrDest->getIterator()) != MF.end(); 2284 BrDest = BrDest->getNextNode()) { 2285 for (const auto &MI : *BrDest) { 2286 if (MI.getOpcode() == WebAssembly::END_BLOCK) { 2287 FoundEndBlock = true; 2288 break; 2289 } 2290 } 2291 if (FoundEndBlock) 2292 break; 2293 } 2294 assert(FoundEndBlock); 2295 MO.setMBB(BrDest); 2296 } 2297 } 2298 } 2299 } 2300 } 2301 2302 return true; 2303 } 2304 2305 void WebAssemblyCFGStackify::recalculateScopeTops(MachineFunction &MF) { 2306 // Renumber BBs and recalculate ScopeTop info because new BBs might have been 2307 // created and inserted during fixing unwind mismatches. 2308 MF.RenumberBlocks(); 2309 MDT->updateBlockNumbers(); 2310 ScopeTops.clear(); 2311 ScopeTops.resize(MF.getNumBlockIDs()); 2312 for (auto &MBB : reverse(MF)) { 2313 for (auto &MI : reverse(MBB)) { 2314 if (ScopeTops[MBB.getNumber()]) 2315 break; 2316 switch (MI.getOpcode()) { 2317 case WebAssembly::END_BLOCK: 2318 case WebAssembly::END_LOOP: 2319 case WebAssembly::END_TRY: 2320 case WebAssembly::END_TRY_TABLE: 2321 case WebAssembly::DELEGATE: 2322 updateScopeTops(EndToBegin[&MI]->getParent(), &MBB); 2323 break; 2324 case WebAssembly::CATCH_LEGACY: 2325 case WebAssembly::CATCH_ALL_LEGACY: 2326 updateScopeTops(EHPadToTry[&MBB]->getParent(), &MBB); 2327 break; 2328 } 2329 } 2330 } 2331 } 2332 2333 /// In normal assembly languages, when the end of a function is unreachable, 2334 /// because the function ends in an infinite loop or a noreturn call or similar, 2335 /// it isn't necessary to worry about the function return type at the end of 2336 /// the function, because it's never reached. However, in WebAssembly, blocks 2337 /// that end at the function end need to have a return type signature that 2338 /// matches the function signature, even though it's unreachable. This function 2339 /// checks for such cases and fixes up the signatures. 2340 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 2341 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 2342 2343 if (MFI.getResults().empty()) 2344 return; 2345 2346 // MCInstLower will add the proper types to multivalue signatures based on the 2347 // function return type 2348 WebAssembly::BlockType RetType = 2349 MFI.getResults().size() > 1 2350 ? WebAssembly::BlockType::Multivalue 2351 : WebAssembly::BlockType( 2352 WebAssembly::toValType(MFI.getResults().front())); 2353 2354 SmallVector<MachineBasicBlock::reverse_iterator, 4> Worklist; 2355 Worklist.push_back(MF.rbegin()->rbegin()); 2356 2357 auto Process = [&](MachineBasicBlock::reverse_iterator It) { 2358 auto *MBB = It->getParent(); 2359 while (It != MBB->rend()) { 2360 MachineInstr &MI = *It++; 2361 if (MI.isPosition() || MI.isDebugInstr()) 2362 continue; 2363 switch (MI.getOpcode()) { 2364 case WebAssembly::END_TRY: { 2365 // If a 'try''s return type is fixed, both its try body and catch body 2366 // should satisfy the return type, so we need to search 'end' 2367 // instructions before its corresponding 'catch' too. 2368 auto *EHPad = TryToEHPad.lookup(EndToBegin[&MI]); 2369 assert(EHPad); 2370 auto NextIt = 2371 std::next(WebAssembly::findCatch(EHPad)->getReverseIterator()); 2372 if (NextIt != EHPad->rend()) 2373 Worklist.push_back(NextIt); 2374 [[fallthrough]]; 2375 } 2376 case WebAssembly::END_BLOCK: 2377 case WebAssembly::END_LOOP: 2378 case WebAssembly::END_TRY_TABLE: 2379 case WebAssembly::DELEGATE: 2380 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 2381 continue; 2382 default: 2383 // Something other than an `end`. We're done for this BB. 2384 return; 2385 } 2386 } 2387 // We've reached the beginning of a BB. Continue the search in the previous 2388 // BB. 2389 Worklist.push_back(MBB->getPrevNode()->rbegin()); 2390 }; 2391 2392 while (!Worklist.empty()) 2393 Process(Worklist.pop_back_val()); 2394 } 2395 2396 // WebAssembly functions end with an end instruction, as if the function body 2397 // were a block. 2398 static void appendEndToFunction(MachineFunction &MF, 2399 const WebAssemblyInstrInfo &TII) { 2400 BuildMI(MF.back(), MF.back().end(), 2401 MF.back().findPrevDebugLoc(MF.back().end()), 2402 TII.get(WebAssembly::END_FUNCTION)); 2403 } 2404 2405 // We added block~end_block and try_table~end_try_table markers in 2406 // placeTryTableMarker. But When catch clause's destination has a return type, 2407 // as in the case of catch with a concrete tag, catch_ref, and catch_all_ref. 2408 // For example: 2409 // block exnref 2410 // try_table (catch_all_ref 0) 2411 // ... 2412 // end_try_table 2413 // end_block 2414 // ... use exnref ... 2415 // 2416 // This code is not valid because the block's body type is not exnref. So we add 2417 // an unreachable after the 'end_try_table' to make the code valid here: 2418 // block exnref 2419 // try_table (catch_all_ref 0) 2420 // ... 2421 // end_try_table 2422 // unreachable (new) 2423 // end_block 2424 // 2425 // Because 'unreachable' is a terminator we also need to split the BB. 2426 static void addUnreachableAfterTryTables(MachineFunction &MF, 2427 const WebAssemblyInstrInfo &TII) { 2428 std::vector<MachineInstr *> EndTryTables; 2429 for (auto &MBB : MF) 2430 for (auto &MI : MBB) 2431 if (MI.getOpcode() == WebAssembly::END_TRY_TABLE) 2432 EndTryTables.push_back(&MI); 2433 2434 for (auto *EndTryTable : EndTryTables) { 2435 auto *MBB = EndTryTable->getParent(); 2436 auto *NewEndTryTableBB = MF.CreateMachineBasicBlock(); 2437 MF.insert(MBB->getIterator(), NewEndTryTableBB); 2438 auto SplitPos = std::next(EndTryTable->getIterator()); 2439 NewEndTryTableBB->splice(NewEndTryTableBB->end(), MBB, MBB->begin(), 2440 SplitPos); 2441 NewEndTryTableBB->addSuccessor(MBB); 2442 BuildMI(NewEndTryTableBB, EndTryTable->getDebugLoc(), 2443 TII.get(WebAssembly::UNREACHABLE)); 2444 } 2445 } 2446 2447 /// Insert BLOCK/LOOP/TRY/TRY_TABLE markers at appropriate places. 2448 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 2449 // We allocate one more than the number of blocks in the function to 2450 // accommodate for the possible fake block we may insert at the end. 2451 ScopeTops.resize(MF.getNumBlockIDs() + 1); 2452 // Place the LOOP for MBB if MBB is the header of a loop. 2453 for (auto &MBB : MF) 2454 placeLoopMarker(MBB); 2455 2456 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 2457 for (auto &MBB : MF) { 2458 if (MBB.isEHPad()) { 2459 // Place the TRY/TRY_TABLE for MBB if MBB is the EH pad of an exception. 2460 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 2461 MF.getFunction().hasPersonalityFn()) { 2462 if (WebAssembly::WasmUseLegacyEH) 2463 placeTryMarker(MBB); 2464 else 2465 placeTryTableMarker(MBB); 2466 } 2467 } else { 2468 // Place the BLOCK for MBB if MBB is branched to from above. 2469 placeBlockMarker(MBB); 2470 } 2471 } 2472 2473 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 2474 MF.getFunction().hasPersonalityFn()) { 2475 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2476 // Add an 'unreachable' after 'end_try_table's. 2477 addUnreachableAfterTryTables(MF, TII); 2478 // Fix mismatches in unwind destinations induced by linearizing the code. 2479 fixCallUnwindMismatches(MF); 2480 fixCatchUnwindMismatches(MF); 2481 // addUnreachableAfterTryTables and fixUnwindMismatches create new BBs, so 2482 // we need to recalculate ScopeTops. 2483 recalculateScopeTops(MF); 2484 } 2485 } 2486 2487 unsigned WebAssemblyCFGStackify::getBranchDepth( 2488 const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) { 2489 unsigned Depth = 0; 2490 for (auto X : reverse(Stack)) { 2491 if (X.first == MBB) 2492 break; 2493 ++Depth; 2494 } 2495 assert(Depth < Stack.size() && "Branch destination should be in scope"); 2496 return Depth; 2497 } 2498 2499 unsigned WebAssemblyCFGStackify::getDelegateDepth( 2500 const SmallVectorImpl<EndMarkerInfo> &Stack, const MachineBasicBlock *MBB) { 2501 if (MBB == FakeCallerBB) 2502 return Stack.size(); 2503 // Delegate's destination is either a catch or a another delegate BB. When the 2504 // destination is another delegate, we can compute the argument in the same 2505 // way as branches, because the target delegate BB only contains the single 2506 // delegate instruction. 2507 if (!MBB->isEHPad()) // Target is a delegate BB 2508 return getBranchDepth(Stack, MBB); 2509 2510 // When the delegate's destination is a catch BB, we need to use its 2511 // corresponding try's end_try BB because Stack contains each marker's end BB. 2512 // Also we need to check if the end marker instruction matches, because a 2513 // single BB can contain multiple end markers, like this: 2514 // bb: 2515 // END_BLOCK 2516 // END_TRY 2517 // END_BLOCK 2518 // END_TRY 2519 // ... 2520 // 2521 // In case of branches getting the immediate that targets any of these is 2522 // fine, but delegate has to exactly target the correct try. 2523 unsigned Depth = 0; 2524 const MachineInstr *EndTry = BeginToEnd[EHPadToTry[MBB]]; 2525 for (auto X : reverse(Stack)) { 2526 if (X.first == EndTry->getParent() && X.second == EndTry) 2527 break; 2528 ++Depth; 2529 } 2530 assert(Depth < Stack.size() && "Delegate destination should be in scope"); 2531 return Depth; 2532 } 2533 2534 unsigned WebAssemblyCFGStackify::getRethrowDepth( 2535 const SmallVectorImpl<EndMarkerInfo> &Stack, 2536 const MachineBasicBlock *EHPadToRethrow) { 2537 unsigned Depth = 0; 2538 for (auto X : reverse(Stack)) { 2539 const MachineInstr *End = X.second; 2540 if (End->getOpcode() == WebAssembly::END_TRY) { 2541 auto *EHPad = TryToEHPad[EndToBegin[End]]; 2542 if (EHPadToRethrow == EHPad) 2543 break; 2544 } 2545 ++Depth; 2546 } 2547 assert(Depth < Stack.size() && "Rethrow destination should be in scope"); 2548 return Depth; 2549 } 2550 2551 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 2552 // Now rewrite references to basic blocks to be depth immediates. 2553 SmallVector<EndMarkerInfo, 8> Stack; 2554 2555 auto RewriteOperands = [&](MachineInstr &MI) { 2556 // Rewrite MBB operands to be depth immediates. 2557 SmallVector<MachineOperand, 4> Ops(MI.operands()); 2558 while (MI.getNumOperands() > 0) 2559 MI.removeOperand(MI.getNumOperands() - 1); 2560 for (auto MO : Ops) { 2561 if (MO.isMBB()) { 2562 if (MI.getOpcode() == WebAssembly::DELEGATE) 2563 MO = MachineOperand::CreateImm(getDelegateDepth(Stack, MO.getMBB())); 2564 else if (MI.getOpcode() == WebAssembly::RETHROW) 2565 MO = MachineOperand::CreateImm(getRethrowDepth(Stack, MO.getMBB())); 2566 else 2567 MO = MachineOperand::CreateImm(getBranchDepth(Stack, MO.getMBB())); 2568 } 2569 MI.addOperand(MF, MO); 2570 } 2571 }; 2572 2573 for (auto &MBB : reverse(MF)) { 2574 for (MachineInstr &MI : llvm::reverse(MBB)) { 2575 switch (MI.getOpcode()) { 2576 case WebAssembly::BLOCK: 2577 case WebAssembly::TRY: 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 break; 2583 2584 case WebAssembly::TRY_TABLE: 2585 assert(ScopeTops[Stack.back().first->getNumber()]->getNumber() <= 2586 MBB.getNumber() && 2587 "Block/try/try_table marker should be balanced"); 2588 Stack.pop_back(); 2589 RewriteOperands(MI); 2590 break; 2591 2592 case WebAssembly::LOOP: 2593 assert(Stack.back().first == &MBB && "Loop top should be balanced"); 2594 Stack.pop_back(); 2595 break; 2596 2597 case WebAssembly::END_BLOCK: 2598 case WebAssembly::END_TRY: 2599 case WebAssembly::END_TRY_TABLE: 2600 Stack.push_back(std::make_pair(&MBB, &MI)); 2601 break; 2602 2603 case WebAssembly::END_LOOP: 2604 Stack.push_back(std::make_pair(EndToBegin[&MI]->getParent(), &MI)); 2605 break; 2606 2607 case WebAssembly::DELEGATE: 2608 RewriteOperands(MI); 2609 Stack.push_back(std::make_pair(&MBB, &MI)); 2610 break; 2611 2612 default: 2613 if (MI.isTerminator()) 2614 RewriteOperands(MI); 2615 break; 2616 } 2617 } 2618 } 2619 assert(Stack.empty() && "Control flow should be balanced"); 2620 } 2621 2622 void WebAssemblyCFGStackify::cleanupFunctionData(MachineFunction &MF) { 2623 if (FakeCallerBB) 2624 MF.deleteMachineBasicBlock(FakeCallerBB); 2625 AppendixBB = FakeCallerBB = CallerTrampolineBB = nullptr; 2626 } 2627 2628 void WebAssemblyCFGStackify::releaseMemory() { 2629 ScopeTops.clear(); 2630 BeginToEnd.clear(); 2631 EndToBegin.clear(); 2632 TryToEHPad.clear(); 2633 EHPadToTry.clear(); 2634 UnwindDestToTrampoline.clear(); 2635 } 2636 2637 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 2638 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 2639 "********** Function: " 2640 << MF.getName() << '\n'); 2641 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 2642 MDT = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree(); 2643 2644 releaseMemory(); 2645 2646 // Liveness is not tracked for VALUE_STACK physreg. 2647 MF.getRegInfo().invalidateLiveness(); 2648 2649 // Place the BLOCK/LOOP/TRY/TRY_TABLE markers to indicate the beginnings of 2650 // scopes. 2651 placeMarkers(MF); 2652 2653 // Remove unnecessary instructions possibly introduced by try/end_trys. 2654 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 2655 MF.getFunction().hasPersonalityFn() && WebAssembly::WasmUseLegacyEH) 2656 removeUnnecessaryInstrs(MF); 2657 2658 // Convert MBB operands in terminators to relative depth immediates. 2659 rewriteDepthImmediates(MF); 2660 2661 // Fix up block/loop/try/try_table signatures at the end of the function to 2662 // conform to WebAssembly's rules. 2663 fixEndsAtEndOfFunction(MF); 2664 2665 // Add an end instruction at the end of the function body. 2666 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 2667 appendEndToFunction(MF, TII); 2668 2669 cleanupFunctionData(MF); 2670 2671 MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified(); 2672 return true; 2673 } 2674