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, and TRY markers to mark the start of scopes, 13 /// since scope boundaries serve as the labels for WebAssembly's control 14 /// 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 "WebAssembly.h" 25 #include "WebAssemblyExceptionInfo.h" 26 #include "WebAssemblyMachineFunctionInfo.h" 27 #include "WebAssemblySubtarget.h" 28 #include "WebAssemblyUtilities.h" 29 #include "llvm/ADT/Statistic.h" 30 #include "llvm/CodeGen/MachineDominators.h" 31 #include "llvm/CodeGen/MachineInstrBuilder.h" 32 #include "llvm/MC/MCAsmInfo.h" 33 using namespace llvm; 34 35 #define DEBUG_TYPE "wasm-cfg-stackify" 36 37 STATISTIC(NumUnwindMismatches, "Number of EH pad unwind mismatches found"); 38 39 namespace { 40 class WebAssemblyCFGStackify final : public MachineFunctionPass { 41 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; } 42 43 void getAnalysisUsage(AnalysisUsage &AU) const override { 44 AU.addRequired<MachineDominatorTree>(); 45 AU.addRequired<MachineLoopInfo>(); 46 AU.addRequired<WebAssemblyExceptionInfo>(); 47 MachineFunctionPass::getAnalysisUsage(AU); 48 } 49 50 bool runOnMachineFunction(MachineFunction &MF) override; 51 52 // For each block whose label represents the end of a scope, record the block 53 // which holds the beginning of the scope. This will allow us to quickly skip 54 // over scoped regions when walking blocks. 55 SmallVector<MachineBasicBlock *, 8> ScopeTops; 56 57 // Placing markers. 58 void placeMarkers(MachineFunction &MF); 59 void placeBlockMarker(MachineBasicBlock &MBB); 60 void placeLoopMarker(MachineBasicBlock &MBB); 61 void placeTryMarker(MachineBasicBlock &MBB); 62 void removeUnnecessaryInstrs(MachineFunction &MF); 63 bool fixUnwindMismatches(MachineFunction &MF); 64 void rewriteDepthImmediates(MachineFunction &MF); 65 void fixEndsAtEndOfFunction(MachineFunction &MF); 66 67 // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY). 68 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd; 69 // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY. 70 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin; 71 // <TRY marker, EH pad> map 72 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad; 73 // <EH pad, TRY marker> map 74 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry; 75 76 // There can be an appendix block at the end of each function, shared for: 77 // - creating a correct signature for fallthrough returns 78 // - target for rethrows that need to unwind to the caller, but are trapped 79 // inside another try/catch 80 MachineBasicBlock *AppendixBB = nullptr; 81 MachineBasicBlock *getAppendixBlock(MachineFunction &MF) { 82 if (!AppendixBB) { 83 AppendixBB = MF.CreateMachineBasicBlock(); 84 // Give it a fake predecessor so that AsmPrinter prints its label. 85 AppendixBB->addSuccessor(AppendixBB); 86 MF.push_back(AppendixBB); 87 } 88 return AppendixBB; 89 } 90 91 // Helper functions to register / unregister scope information created by 92 // marker instructions. 93 void registerScope(MachineInstr *Begin, MachineInstr *End); 94 void registerTryScope(MachineInstr *Begin, MachineInstr *End, 95 MachineBasicBlock *EHPad); 96 void unregisterScope(MachineInstr *Begin); 97 98 public: 99 static char ID; // Pass identification, replacement for typeid 100 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 101 ~WebAssemblyCFGStackify() override { releaseMemory(); } 102 void releaseMemory() override; 103 }; 104 } // end anonymous namespace 105 106 char WebAssemblyCFGStackify::ID = 0; 107 INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE, 108 "Insert BLOCK/LOOP/TRY markers for WebAssembly scopes", false, 109 false) 110 111 FunctionPass *llvm::createWebAssemblyCFGStackify() { 112 return new WebAssemblyCFGStackify(); 113 } 114 115 /// Test whether Pred has any terminators explicitly branching to MBB, as 116 /// opposed to falling through. Note that it's possible (eg. in unoptimized 117 /// code) for a branch instruction to both branch to a block and fallthrough 118 /// to it, so we check the actual branch operands to see if there are any 119 /// explicit mentions. 120 static bool explicitlyBranchesTo(MachineBasicBlock *Pred, 121 MachineBasicBlock *MBB) { 122 for (MachineInstr &MI : Pred->terminators()) 123 for (MachineOperand &MO : MI.explicit_operands()) 124 if (MO.isMBB() && MO.getMBB() == MBB) 125 return true; 126 return false; 127 } 128 129 // Returns an iterator to the earliest position possible within the MBB, 130 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 131 // contains instructions that should go before the marker, and AfterSet contains 132 // ones that should go after the marker. In this function, AfterSet is only 133 // used for sanity checking. 134 static MachineBasicBlock::iterator 135 getEarliestInsertPos(MachineBasicBlock *MBB, 136 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 137 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 138 auto InsertPos = MBB->end(); 139 while (InsertPos != MBB->begin()) { 140 if (BeforeSet.count(&*std::prev(InsertPos))) { 141 #ifndef NDEBUG 142 // Sanity check 143 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 144 assert(!AfterSet.count(&*std::prev(Pos))); 145 #endif 146 break; 147 } 148 --InsertPos; 149 } 150 return InsertPos; 151 } 152 153 // Returns an iterator to the latest position possible within the MBB, 154 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 155 // contains instructions that should go before the marker, and AfterSet contains 156 // ones that should go after the marker. In this function, BeforeSet is only 157 // used for sanity checking. 158 static MachineBasicBlock::iterator 159 getLatestInsertPos(MachineBasicBlock *MBB, 160 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 161 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 162 auto InsertPos = MBB->begin(); 163 while (InsertPos != MBB->end()) { 164 if (AfterSet.count(&*InsertPos)) { 165 #ifndef NDEBUG 166 // Sanity check 167 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 168 assert(!BeforeSet.count(&*Pos)); 169 #endif 170 break; 171 } 172 ++InsertPos; 173 } 174 return InsertPos; 175 } 176 177 void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 178 MachineInstr *End) { 179 BeginToEnd[Begin] = End; 180 EndToBegin[End] = Begin; 181 } 182 183 void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 184 MachineInstr *End, 185 MachineBasicBlock *EHPad) { 186 registerScope(Begin, End); 187 TryToEHPad[Begin] = EHPad; 188 EHPadToTry[EHPad] = Begin; 189 } 190 191 void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) { 192 assert(BeginToEnd.count(Begin)); 193 MachineInstr *End = BeginToEnd[Begin]; 194 assert(EndToBegin.count(End)); 195 BeginToEnd.erase(Begin); 196 EndToBegin.erase(End); 197 MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin); 198 if (EHPad) { 199 assert(EHPadToTry.count(EHPad)); 200 TryToEHPad.erase(Begin); 201 EHPadToTry.erase(EHPad); 202 } 203 } 204 205 /// Insert a BLOCK marker for branches to MBB (if needed). 206 // TODO Consider a more generalized way of handling block (and also loop and 207 // try) signatures when we implement the multi-value proposal later. 208 void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 209 assert(!MBB.isEHPad()); 210 MachineFunction &MF = *MBB.getParent(); 211 auto &MDT = getAnalysis<MachineDominatorTree>(); 212 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 213 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 214 215 // First compute the nearest common dominator of all forward non-fallthrough 216 // predecessors so that we minimize the time that the BLOCK is on the stack, 217 // which reduces overall stack height. 218 MachineBasicBlock *Header = nullptr; 219 bool IsBranchedTo = false; 220 bool IsBrOnExn = false; 221 MachineInstr *BrOnExn = nullptr; 222 int MBBNumber = MBB.getNumber(); 223 for (MachineBasicBlock *Pred : MBB.predecessors()) { 224 if (Pred->getNumber() < MBBNumber) { 225 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 226 if (explicitlyBranchesTo(Pred, &MBB)) { 227 IsBranchedTo = true; 228 if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) { 229 IsBrOnExn = true; 230 assert(!BrOnExn && "There should be only one br_on_exn per block"); 231 BrOnExn = &*Pred->getFirstTerminator(); 232 } 233 } 234 } 235 } 236 if (!Header) 237 return; 238 if (!IsBranchedTo) 239 return; 240 241 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 242 MachineBasicBlock *LayoutPred = MBB.getPrevNode(); 243 244 // If the nearest common dominator is inside a more deeply nested context, 245 // walk out to the nearest scope which isn't more deeply nested. 246 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 247 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 248 if (ScopeTop->getNumber() > Header->getNumber()) { 249 // Skip over an intervening scope. 250 I = std::next(ScopeTop->getIterator()); 251 } else { 252 // We found a scope level at an appropriate depth. 253 Header = ScopeTop; 254 break; 255 } 256 } 257 } 258 259 // Decide where in Header to put the BLOCK. 260 261 // Instructions that should go before the BLOCK. 262 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 263 // Instructions that should go after the BLOCK. 264 SmallPtrSet<const MachineInstr *, 4> AfterSet; 265 for (const auto &MI : *Header) { 266 // If there is a previously placed LOOP marker and the bottom block of the 267 // loop is above MBB, it should be after the BLOCK, because the loop is 268 // nested in this BLOCK. Otherwise it should be before the BLOCK. 269 if (MI.getOpcode() == WebAssembly::LOOP) { 270 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 271 if (MBB.getNumber() > LoopBottom->getNumber()) 272 AfterSet.insert(&MI); 273 #ifndef NDEBUG 274 else 275 BeforeSet.insert(&MI); 276 #endif 277 } 278 279 // All previously inserted BLOCK/TRY markers should be after the BLOCK 280 // because they are all nested blocks. 281 if (MI.getOpcode() == WebAssembly::BLOCK || 282 MI.getOpcode() == WebAssembly::TRY) 283 AfterSet.insert(&MI); 284 285 #ifndef NDEBUG 286 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK. 287 if (MI.getOpcode() == WebAssembly::END_BLOCK || 288 MI.getOpcode() == WebAssembly::END_LOOP || 289 MI.getOpcode() == WebAssembly::END_TRY) 290 BeforeSet.insert(&MI); 291 #endif 292 293 // Terminators should go after the BLOCK. 294 if (MI.isTerminator()) 295 AfterSet.insert(&MI); 296 } 297 298 // Local expression tree should go after the BLOCK. 299 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 300 --I) { 301 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 302 continue; 303 if (WebAssembly::isChild(*std::prev(I), MFI)) 304 AfterSet.insert(&*std::prev(I)); 305 else 306 break; 307 } 308 309 // Add the BLOCK. 310 311 // 'br_on_exn' extracts exnref object and pushes variable number of values 312 // depending on its tag. For C++ exception, its a single i32 value, and the 313 // generated code will be in the form of: 314 // block i32 315 // br_on_exn 0, $__cpp_exception 316 // rethrow 317 // end_block 318 WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void; 319 if (IsBrOnExn) { 320 const char *TagName = BrOnExn->getOperand(1).getSymbolName(); 321 if (std::strcmp(TagName, "__cpp_exception") != 0) 322 llvm_unreachable("Only C++ exception is supported"); 323 ReturnType = WebAssembly::ExprType::I32; 324 } 325 326 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 327 MachineInstr *Begin = 328 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 329 TII.get(WebAssembly::BLOCK)) 330 .addImm(int64_t(ReturnType)); 331 332 // Decide where in Header to put the END_BLOCK. 333 BeforeSet.clear(); 334 AfterSet.clear(); 335 for (auto &MI : MBB) { 336 #ifndef NDEBUG 337 // END_BLOCK should precede existing LOOP and TRY markers. 338 if (MI.getOpcode() == WebAssembly::LOOP || 339 MI.getOpcode() == WebAssembly::TRY) 340 AfterSet.insert(&MI); 341 #endif 342 343 // If there is a previously placed END_LOOP marker and the header of the 344 // loop is above this block's header, the END_LOOP should be placed after 345 // the BLOCK, because the loop contains this block. Otherwise the END_LOOP 346 // should be placed before the BLOCK. The same for END_TRY. 347 if (MI.getOpcode() == WebAssembly::END_LOOP || 348 MI.getOpcode() == WebAssembly::END_TRY) { 349 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 350 BeforeSet.insert(&MI); 351 #ifndef NDEBUG 352 else 353 AfterSet.insert(&MI); 354 #endif 355 } 356 } 357 358 // Mark the end of the block. 359 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 360 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 361 TII.get(WebAssembly::END_BLOCK)); 362 registerScope(Begin, End); 363 364 // Track the farthest-spanning scope that ends at this point. 365 int Number = MBB.getNumber(); 366 if (!ScopeTops[Number] || 367 ScopeTops[Number]->getNumber() > Header->getNumber()) 368 ScopeTops[Number] = Header; 369 } 370 371 /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). 372 void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) { 373 MachineFunction &MF = *MBB.getParent(); 374 const auto &MLI = getAnalysis<MachineLoopInfo>(); 375 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 376 377 MachineLoop *Loop = MLI.getLoopFor(&MBB); 378 if (!Loop || Loop->getHeader() != &MBB) 379 return; 380 381 // The operand of a LOOP is the first block after the loop. If the loop is the 382 // bottom of the function, insert a dummy block at the end. 383 MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop); 384 auto Iter = std::next(Bottom->getIterator()); 385 if (Iter == MF.end()) { 386 getAppendixBlock(MF); 387 Iter = std::next(Bottom->getIterator()); 388 } 389 MachineBasicBlock *AfterLoop = &*Iter; 390 391 // Decide where in Header to put the LOOP. 392 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 393 SmallPtrSet<const MachineInstr *, 4> AfterSet; 394 for (const auto &MI : MBB) { 395 // LOOP marker should be after any existing loop that ends here. Otherwise 396 // we assume the instruction belongs to the loop. 397 if (MI.getOpcode() == WebAssembly::END_LOOP) 398 BeforeSet.insert(&MI); 399 #ifndef NDEBUG 400 else 401 AfterSet.insert(&MI); 402 #endif 403 } 404 405 // Mark the beginning of the loop. 406 auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 407 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos), 408 TII.get(WebAssembly::LOOP)) 409 .addImm(int64_t(WebAssembly::ExprType::Void)); 410 411 // Decide where in Header to put the END_LOOP. 412 BeforeSet.clear(); 413 AfterSet.clear(); 414 #ifndef NDEBUG 415 for (const auto &MI : MBB) 416 // Existing END_LOOP markers belong to parent loops of this loop 417 if (MI.getOpcode() == WebAssembly::END_LOOP) 418 AfterSet.insert(&MI); 419 #endif 420 421 // Mark the end of the loop (using arbitrary debug location that branched to 422 // the loop end as its location). 423 InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet); 424 DebugLoc EndDL = AfterLoop->pred_empty() 425 ? DebugLoc() 426 : (*AfterLoop->pred_rbegin())->findBranchDebugLoc(); 427 MachineInstr *End = 428 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP)); 429 registerScope(Begin, End); 430 431 assert((!ScopeTops[AfterLoop->getNumber()] || 432 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && 433 "With block sorting the outermost loop for a block should be first."); 434 if (!ScopeTops[AfterLoop->getNumber()]) 435 ScopeTops[AfterLoop->getNumber()] = &MBB; 436 } 437 438 void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) { 439 assert(MBB.isEHPad()); 440 MachineFunction &MF = *MBB.getParent(); 441 auto &MDT = getAnalysis<MachineDominatorTree>(); 442 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 443 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 444 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 445 446 // Compute the nearest common dominator of all unwind predecessors 447 MachineBasicBlock *Header = nullptr; 448 int MBBNumber = MBB.getNumber(); 449 for (auto *Pred : MBB.predecessors()) { 450 if (Pred->getNumber() < MBBNumber) { 451 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 452 assert(!explicitlyBranchesTo(Pred, &MBB) && 453 "Explicit branch to an EH pad!"); 454 } 455 } 456 if (!Header) 457 return; 458 459 // If this try is at the bottom of the function, insert a dummy block at the 460 // end. 461 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 462 assert(WE); 463 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE); 464 465 auto Iter = std::next(Bottom->getIterator()); 466 if (Iter == MF.end()) { 467 getAppendixBlock(MF); 468 Iter = std::next(Bottom->getIterator()); 469 } 470 MachineBasicBlock *Cont = &*Iter; 471 472 assert(Cont != &MF.front()); 473 MachineBasicBlock *LayoutPred = Cont->getPrevNode(); 474 475 // If the nearest common dominator is inside a more deeply nested context, 476 // walk out to the nearest scope which isn't more deeply nested. 477 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 478 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 479 if (ScopeTop->getNumber() > Header->getNumber()) { 480 // Skip over an intervening scope. 481 I = std::next(ScopeTop->getIterator()); 482 } else { 483 // We found a scope level at an appropriate depth. 484 Header = ScopeTop; 485 break; 486 } 487 } 488 } 489 490 // Decide where in Header to put the TRY. 491 492 // Instructions that should go before the TRY. 493 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 494 // Instructions that should go after the TRY. 495 SmallPtrSet<const MachineInstr *, 4> AfterSet; 496 for (const auto &MI : *Header) { 497 // If there is a previously placed LOOP marker and the bottom block of the 498 // loop is above MBB, it should be after the TRY, because the loop is nested 499 // in this TRY. Otherwise it should be before the TRY. 500 if (MI.getOpcode() == WebAssembly::LOOP) { 501 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 502 if (MBB.getNumber() > LoopBottom->getNumber()) 503 AfterSet.insert(&MI); 504 #ifndef NDEBUG 505 else 506 BeforeSet.insert(&MI); 507 #endif 508 } 509 510 // All previously inserted BLOCK/TRY markers should be after the TRY because 511 // they are all nested trys. 512 if (MI.getOpcode() == WebAssembly::BLOCK || 513 MI.getOpcode() == WebAssembly::TRY) 514 AfterSet.insert(&MI); 515 516 #ifndef NDEBUG 517 // All END_(BLOCK/LOOP/TRY) markers should be before the TRY. 518 if (MI.getOpcode() == WebAssembly::END_BLOCK || 519 MI.getOpcode() == WebAssembly::END_LOOP || 520 MI.getOpcode() == WebAssembly::END_TRY) 521 BeforeSet.insert(&MI); 522 #endif 523 524 // Terminators should go after the TRY. 525 if (MI.isTerminator()) 526 AfterSet.insert(&MI); 527 } 528 529 // Local expression tree should go after the TRY. 530 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 531 --I) { 532 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 533 continue; 534 if (WebAssembly::isChild(*std::prev(I), MFI)) 535 AfterSet.insert(&*std::prev(I)); 536 else 537 break; 538 } 539 540 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 541 // contain the call within it. So the call should go after the TRY. The 542 // exception is when the header's terminator is a rethrow instruction, in 543 // which case that instruction, not a call instruction before it, is gonna 544 // throw. 545 if (MBB.isPredecessor(Header)) { 546 auto TermPos = Header->getFirstTerminator(); 547 if (TermPos == Header->end() || 548 TermPos->getOpcode() != WebAssembly::RETHROW) { 549 for (const auto &MI : reverse(*Header)) { 550 if (MI.isCall()) { 551 AfterSet.insert(&MI); 552 // Possibly throwing calls are usually wrapped by EH_LABEL 553 // instructions. We don't want to split them and the call. 554 if (MI.getIterator() != Header->begin() && 555 std::prev(MI.getIterator())->isEHLabel()) 556 AfterSet.insert(&*std::prev(MI.getIterator())); 557 break; 558 } 559 } 560 } 561 } 562 563 // Add the TRY. 564 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 565 MachineInstr *Begin = 566 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 567 TII.get(WebAssembly::TRY)) 568 .addImm(int64_t(WebAssembly::ExprType::Void)); 569 570 // Decide where in Header to put the END_TRY. 571 BeforeSet.clear(); 572 AfterSet.clear(); 573 for (const auto &MI : *Cont) { 574 #ifndef NDEBUG 575 // END_TRY should precede existing LOOP and BLOCK markers. 576 if (MI.getOpcode() == WebAssembly::LOOP || 577 MI.getOpcode() == WebAssembly::BLOCK) 578 AfterSet.insert(&MI); 579 580 // All END_TRY markers placed earlier belong to exceptions that contains 581 // this one. 582 if (MI.getOpcode() == WebAssembly::END_TRY) 583 AfterSet.insert(&MI); 584 #endif 585 586 // If there is a previously placed END_LOOP marker and its header is after 587 // where TRY marker is, this loop is contained within the 'catch' part, so 588 // the END_TRY marker should go after that. Otherwise, the whole try-catch 589 // is contained within this loop, so the END_TRY should go before that. 590 if (MI.getOpcode() == WebAssembly::END_LOOP) { 591 // For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they 592 // are in the same BB, LOOP is always before TRY. 593 if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber()) 594 BeforeSet.insert(&MI); 595 #ifndef NDEBUG 596 else 597 AfterSet.insert(&MI); 598 #endif 599 } 600 601 // It is not possible for an END_BLOCK to be already in this block. 602 } 603 604 // Mark the end of the TRY. 605 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet); 606 MachineInstr *End = 607 BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(), 608 TII.get(WebAssembly::END_TRY)); 609 registerTryScope(Begin, End, &MBB); 610 611 // Track the farthest-spanning scope that ends at this point. We create two 612 // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB 613 // with 'try'). We need to create 'catch' -> 'try' mapping here too because 614 // markers should not span across 'catch'. For example, this should not 615 // happen: 616 // 617 // try 618 // block --| (X) 619 // catch | 620 // end_block --| 621 // end_try 622 for (int Number : {Cont->getNumber(), MBB.getNumber()}) { 623 if (!ScopeTops[Number] || 624 ScopeTops[Number]->getNumber() > Header->getNumber()) 625 ScopeTops[Number] = Header; 626 } 627 } 628 629 void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) { 630 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 631 632 // When there is an unconditional branch right before a catch instruction and 633 // it branches to the end of end_try marker, we don't need the branch, because 634 // it there is no exception, the control flow transfers to that point anyway. 635 // bb0: 636 // try 637 // ... 638 // br bb2 <- Not necessary 639 // bb1: 640 // catch 641 // ... 642 // bb2: 643 // end 644 for (auto &MBB : MF) { 645 if (!MBB.isEHPad()) 646 continue; 647 648 MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 649 SmallVector<MachineOperand, 4> Cond; 650 MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode(); 651 MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent(); 652 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 653 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) || 654 (!Cond.empty() && FBB && FBB == Cont))) 655 TII.removeBranch(*EHPadLayoutPred); 656 } 657 658 // When there are block / end_block markers that overlap with try / end_try 659 // markers, and the block and try markers' return types are the same, the 660 // block /end_block markers are not necessary, because try / end_try markers 661 // also can serve as boundaries for branches. 662 // block <- Not necessary 663 // try 664 // ... 665 // catch 666 // ... 667 // end 668 // end <- Not necessary 669 SmallVector<MachineInstr *, 32> ToDelete; 670 for (auto &MBB : MF) { 671 for (auto &MI : MBB) { 672 if (MI.getOpcode() != WebAssembly::TRY) 673 continue; 674 675 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try]; 676 MachineBasicBlock *TryBB = Try->getParent(); 677 MachineBasicBlock *Cont = EndTry->getParent(); 678 int64_t RetType = Try->getOperand(0).getImm(); 679 for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator()); 680 B != TryBB->begin() && E != Cont->end() && 681 std::prev(B)->getOpcode() == WebAssembly::BLOCK && 682 E->getOpcode() == WebAssembly::END_BLOCK && 683 std::prev(B)->getOperand(0).getImm() == RetType; 684 --B, ++E) { 685 ToDelete.push_back(&*std::prev(B)); 686 ToDelete.push_back(&*E); 687 } 688 } 689 } 690 for (auto *MI : ToDelete) { 691 if (MI->getOpcode() == WebAssembly::BLOCK) 692 unregisterScope(MI); 693 MI->eraseFromParent(); 694 } 695 } 696 697 // When MBB is split into MBB and Split, we should unstackify defs in MBB that 698 // have their uses in Split. 699 static void unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, 700 MachineBasicBlock &Split, 701 WebAssemblyFunctionInfo &MFI, 702 MachineRegisterInfo &MRI) { 703 for (auto &MI : Split) { 704 for (auto &MO : MI.explicit_uses()) { 705 if (!MO.isReg() || Register::isPhysicalRegister(MO.getReg())) 706 continue; 707 if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg())) 708 if (Def->getParent() == &MBB) 709 MFI.unstackifyVReg(MO.getReg()); 710 } 711 } 712 } 713 714 bool WebAssemblyCFGStackify::fixUnwindMismatches(MachineFunction &MF) { 715 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 716 auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 717 MachineRegisterInfo &MRI = MF.getRegInfo(); 718 719 // Linearizing the control flow by placing TRY / END_TRY markers can create 720 // mismatches in unwind destinations. There are two kinds of mismatches we 721 // try to solve here. 722 723 // 1. When an instruction may throw, but the EH pad it will unwind to can be 724 // different from the original CFG. 725 // 726 // Example: we have the following CFG: 727 // bb0: 728 // call @foo (if it throws, unwind to bb2) 729 // bb1: 730 // call @bar (if it throws, unwind to bb3) 731 // bb2 (ehpad): 732 // catch 733 // ... 734 // bb3 (ehpad) 735 // catch 736 // handler body 737 // 738 // And the CFG is sorted in this order. Then after placing TRY markers, it 739 // will look like: (BB markers are omitted) 740 // try $label1 741 // try 742 // call @foo 743 // call @bar (if it throws, unwind to bb3) 744 // catch <- ehpad (bb2) 745 // ... 746 // end_try 747 // catch <- ehpad (bb3) 748 // handler body 749 // end_try 750 // 751 // Now if bar() throws, it is going to end up ip in bb2, not bb3, where it 752 // is supposed to end up. We solve this problem by 753 // a. Split the target unwind EH pad (here bb3) so that the handler body is 754 // right after 'end_try', which means we extract the handler body out of 755 // the catch block. We do this because this handler body should be 756 // somewhere branch-eable from the inner scope. 757 // b. Wrap the call that has an incorrect unwind destination ('call @bar' 758 // here) with a nested try/catch/end_try scope, and within the new catch 759 // block, branches to the handler body. 760 // c. Place a branch after the newly inserted nested end_try so it can bypass 761 // the handler body, which is now outside of a catch block. 762 // 763 // The result will like as follows. (new: a) means this instruction is newly 764 // created in the process of doing 'a' above. 765 // 766 // block $label0 (new: placeBlockMarker) 767 // try $label1 768 // try 769 // call @foo 770 // try (new: b) 771 // call @bar 772 // catch (new: b) 773 // local.set n / drop (new: b) 774 // br $label1 (new: b) 775 // end_try (new: b) 776 // catch <- ehpad (bb2) 777 // end_try 778 // br $label0 (new: c) 779 // catch <- ehpad (bb3) 780 // end_try (hoisted: a) 781 // handler body 782 // end_block (new: placeBlockMarker) 783 // 784 // Note that the new wrapping block/end_block will be generated later in 785 // placeBlockMarker. 786 // 787 // TODO Currently local.set and local.gets are generated to move exnref value 788 // created by catches. That's because we don't support yielding values from a 789 // block in LLVM machine IR yet, even though it is supported by wasm. Delete 790 // unnecessary local.get/local.sets once yielding values from a block is 791 // supported. The full EH spec requires multi-value support to do this, but 792 // for C++ we don't yet need it because we only throw a single i32. 793 // 794 // --- 795 // 2. The same as 1, but in this case an instruction unwinds to a caller 796 // function and not another EH pad. 797 // 798 // Example: we have the following CFG: 799 // bb0: 800 // call @foo (if it throws, unwind to bb2) 801 // bb1: 802 // call @bar (if it throws, unwind to caller) 803 // bb2 (ehpad): 804 // catch 805 // ... 806 // 807 // And the CFG is sorted in this order. Then after placing TRY markers, it 808 // will look like: 809 // try 810 // call @foo 811 // call @bar (if it throws, unwind to caller) 812 // catch <- ehpad (bb2) 813 // ... 814 // end_try 815 // 816 // Now if bar() throws, it is going to end up ip in bb2, when it is supposed 817 // throw up to the caller. 818 // We solve this problem by 819 // a. Create a new 'appendix' BB at the end of the function and put a single 820 // 'rethrow' instruction (+ local.get) in there. 821 // b. Wrap the call that has an incorrect unwind destination ('call @bar' 822 // here) with a nested try/catch/end_try scope, and within the new catch 823 // block, branches to the new appendix block. 824 // 825 // block $label0 (new: placeBlockMarker) 826 // try 827 // call @foo 828 // try (new: b) 829 // call @bar 830 // catch (new: b) 831 // local.set n (new: b) 832 // br $label0 (new: b) 833 // end_try (new: b) 834 // catch <- ehpad (bb2) 835 // ... 836 // end_try 837 // ... 838 // end_block (new: placeBlockMarker) 839 // local.get n (new: a) <- appendix block 840 // rethrow (new: a) 841 // 842 // In case there are multiple calls in a BB that may throw to the caller, they 843 // can be wrapped together in one nested try scope. (In 1, this couldn't 844 // happen, because may-throwing instruction there had an unwind destination, 845 // i.e., it was an invoke before, and there could be only one invoke within a 846 // BB.) 847 848 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 849 // Range of intructions to be wrapped in a new nested try/catch 850 using TryRange = std::pair<MachineInstr *, MachineInstr *>; 851 // In original CFG, <unwind destination BB, a vector of try ranges> 852 DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges; 853 // In new CFG, <destination to branch to, a vector of try ranges> 854 DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> BrDestToTryRanges; 855 // In new CFG, <destination to branch to, register containing exnref> 856 DenseMap<MachineBasicBlock *, unsigned> BrDestToExnReg; 857 858 // Gather possibly throwing calls (i.e., previously invokes) whose current 859 // unwind destination is not the same as the original CFG. 860 for (auto &MBB : reverse(MF)) { 861 bool SeenThrowableInstInBB = false; 862 for (auto &MI : reverse(MBB)) { 863 if (MI.getOpcode() == WebAssembly::TRY) 864 EHPadStack.pop_back(); 865 else if (MI.getOpcode() == WebAssembly::CATCH) 866 EHPadStack.push_back(MI.getParent()); 867 868 // In this loop we only gather calls that have an EH pad to unwind. So 869 // there will be at most 1 such call (= invoke) in a BB, so after we've 870 // seen one, we can skip the rest of BB. Also if MBB has no EH pad 871 // successor or MI does not throw, this is not an invoke. 872 if (SeenThrowableInstInBB || !MBB.hasEHPadSuccessor() || 873 !WebAssembly::mayThrow(MI)) 874 continue; 875 SeenThrowableInstInBB = true; 876 877 // If the EH pad on the stack top is where this instruction should unwind 878 // next, we're good. 879 MachineBasicBlock *UnwindDest = nullptr; 880 for (auto *Succ : MBB.successors()) { 881 if (Succ->isEHPad()) { 882 UnwindDest = Succ; 883 break; 884 } 885 } 886 if (EHPadStack.back() == UnwindDest) 887 continue; 888 889 // If not, record the range. 890 UnwindDestToTryRanges[UnwindDest].push_back(TryRange(&MI, &MI)); 891 } 892 } 893 894 assert(EHPadStack.empty()); 895 896 // Gather possibly throwing calls that are supposed to unwind up to the caller 897 // if they throw, but currently unwind to an incorrect destination. Unlike the 898 // loop above, there can be multiple calls within a BB that unwind to the 899 // caller, which we should group together in a range. 900 bool NeedAppendixBlock = false; 901 for (auto &MBB : reverse(MF)) { 902 MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; // inclusive 903 for (auto &MI : reverse(MBB)) { 904 if (MI.getOpcode() == WebAssembly::TRY) 905 EHPadStack.pop_back(); 906 else if (MI.getOpcode() == WebAssembly::CATCH) 907 EHPadStack.push_back(MI.getParent()); 908 909 // If MBB has an EH pad successor, this inst does not unwind to caller. 910 if (MBB.hasEHPadSuccessor()) 911 continue; 912 913 // We wrap up the current range when we see a marker even if we haven't 914 // finished a BB. 915 if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) { 916 NeedAppendixBlock = true; 917 // Record the range. nullptr here means the unwind destination is the 918 // caller. 919 UnwindDestToTryRanges[nullptr].push_back( 920 TryRange(RangeBegin, RangeEnd)); 921 RangeBegin = RangeEnd = nullptr; // Reset range pointers 922 } 923 924 // If EHPadStack is empty, that means it is correctly unwind to caller if 925 // it throws, so we're good. If MI does not throw, we're good too. 926 if (EHPadStack.empty() || !WebAssembly::mayThrow(MI)) 927 continue; 928 929 // We found an instruction that unwinds to the caller but currently has an 930 // incorrect unwind destination. Create a new range or increment the 931 // currently existing range. 932 if (!RangeEnd) 933 RangeBegin = RangeEnd = &MI; 934 else 935 RangeBegin = &MI; 936 } 937 938 if (RangeEnd) { 939 NeedAppendixBlock = true; 940 // Record the range. nullptr here means the unwind destination is the 941 // caller. 942 UnwindDestToTryRanges[nullptr].push_back(TryRange(RangeBegin, RangeEnd)); 943 RangeBegin = RangeEnd = nullptr; // Reset range pointers 944 } 945 } 946 947 assert(EHPadStack.empty()); 948 // We don't have any unwind destination mismatches to resolve. 949 if (UnwindDestToTryRanges.empty()) 950 return false; 951 952 // If we found instructions that should unwind to the caller but currently 953 // have incorrect unwind destination, we create an appendix block at the end 954 // of the function with a local.get and a rethrow instruction. 955 if (NeedAppendixBlock) { 956 auto *AppendixBB = getAppendixBlock(MF); 957 Register ExnReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass); 958 BuildMI(AppendixBB, DebugLoc(), TII.get(WebAssembly::RETHROW)) 959 .addReg(ExnReg); 960 // These instruction ranges should branch to this appendix BB. 961 for (auto Range : UnwindDestToTryRanges[nullptr]) 962 BrDestToTryRanges[AppendixBB].push_back(Range); 963 BrDestToExnReg[AppendixBB] = ExnReg; 964 } 965 966 // We loop through unwind destination EH pads that are targeted from some 967 // inner scopes. Because these EH pads are destination of more than one scope 968 // now, we split them so that the handler body is after 'end_try'. 969 // - Before 970 // ehpad: 971 // catch 972 // local.set n / drop 973 // handler body 974 // ... 975 // cont: 976 // end_try 977 // 978 // - After 979 // ehpad: 980 // catch 981 // local.set n / drop 982 // brdest: (new) 983 // end_try (hoisted from 'cont' BB) 984 // handler body (taken from 'ehpad') 985 // ... 986 // cont: 987 for (auto &P : UnwindDestToTryRanges) { 988 NumUnwindMismatches += P.second.size(); 989 990 // This means the destination is the appendix BB, which was separately 991 // handled above. 992 if (!P.first) 993 continue; 994 995 MachineBasicBlock *EHPad = P.first; 996 997 // Find 'catch' and 'local.set' or 'drop' instruction that follows the 998 // 'catch'. If -wasm-disable-explicit-locals is not set, 'catch' should be 999 // always followed by either 'local.set' or a 'drop', because 'br_on_exn' is 1000 // generated after 'catch' in LateEHPrepare and we don't support blocks 1001 // taking values yet. 1002 MachineInstr *Catch = nullptr; 1003 unsigned ExnReg = 0; 1004 for (auto &MI : *EHPad) { 1005 switch (MI.getOpcode()) { 1006 case WebAssembly::CATCH: 1007 Catch = &MI; 1008 ExnReg = Catch->getOperand(0).getReg(); 1009 break; 1010 } 1011 } 1012 assert(Catch && "EH pad does not have a catch"); 1013 assert(ExnReg != 0 && "Invalid register"); 1014 1015 auto SplitPos = std::next(Catch->getIterator()); 1016 1017 // Create a new BB that's gonna be the destination for branches from the 1018 // inner mismatched scope. 1019 MachineInstr *BeginTry = EHPadToTry[EHPad]; 1020 MachineInstr *EndTry = BeginToEnd[BeginTry]; 1021 MachineBasicBlock *Cont = EndTry->getParent(); 1022 auto *BrDest = MF.CreateMachineBasicBlock(); 1023 MF.insert(std::next(EHPad->getIterator()), BrDest); 1024 // Hoist up the existing 'end_try'. 1025 BrDest->insert(BrDest->end(), EndTry->removeFromParent()); 1026 // Take out the handler body from EH pad to the new branch destination BB. 1027 BrDest->splice(BrDest->end(), EHPad, SplitPos, EHPad->end()); 1028 unstackifyVRegsUsedInSplitBB(*EHPad, *BrDest, MFI, MRI); 1029 // Fix predecessor-successor relationship. 1030 BrDest->transferSuccessors(EHPad); 1031 EHPad->addSuccessor(BrDest); 1032 1033 // All try ranges that were supposed to unwind to this EH pad now have to 1034 // branch to this new branch dest BB. 1035 for (auto Range : UnwindDestToTryRanges[EHPad]) 1036 BrDestToTryRanges[BrDest].push_back(Range); 1037 BrDestToExnReg[BrDest] = ExnReg; 1038 1039 // In case we fall through to the continuation BB after the catch block, we 1040 // now have to add a branch to it. 1041 // - Before 1042 // try 1043 // ... 1044 // (falls through to 'cont') 1045 // catch 1046 // handler body 1047 // end 1048 // <-- cont 1049 // 1050 // - After 1051 // try 1052 // ... 1053 // br %cont (new) 1054 // catch 1055 // end 1056 // handler body 1057 // <-- cont 1058 MachineBasicBlock *EHPadLayoutPred = &*std::prev(EHPad->getIterator()); 1059 MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 1060 SmallVector<MachineOperand, 4> Cond; 1061 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 1062 if (Analyzable && !TBB && !FBB) { 1063 DebugLoc DL = EHPadLayoutPred->empty() 1064 ? DebugLoc() 1065 : EHPadLayoutPred->rbegin()->getDebugLoc(); 1066 BuildMI(EHPadLayoutPred, DL, TII.get(WebAssembly::BR)).addMBB(Cont); 1067 } 1068 } 1069 1070 // For possibly throwing calls whose unwind destinations are currently 1071 // incorrect because of CFG linearization, we wrap them with a nested 1072 // try/catch/end_try, and within the new catch block, we branch to the correct 1073 // handler. 1074 // - Before 1075 // mbb: 1076 // call @foo <- Unwind destination mismatch! 1077 // ehpad: 1078 // ... 1079 // 1080 // - After 1081 // mbb: 1082 // try (new) 1083 // call @foo 1084 // nested-ehpad: (new) 1085 // catch (new) 1086 // local.set n / drop (new) 1087 // br %brdest (new) 1088 // nested-end: (new) 1089 // end_try (new) 1090 // ehpad: 1091 // ... 1092 for (auto &P : BrDestToTryRanges) { 1093 MachineBasicBlock *BrDest = P.first; 1094 auto &TryRanges = P.second; 1095 unsigned ExnReg = BrDestToExnReg[BrDest]; 1096 1097 for (auto Range : TryRanges) { 1098 MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; 1099 std::tie(RangeBegin, RangeEnd) = Range; 1100 auto *MBB = RangeBegin->getParent(); 1101 1102 // Include possible EH_LABELs in the range 1103 if (RangeBegin->getIterator() != MBB->begin() && 1104 std::prev(RangeBegin->getIterator())->isEHLabel()) 1105 RangeBegin = &*std::prev(RangeBegin->getIterator()); 1106 if (std::next(RangeEnd->getIterator()) != MBB->end() && 1107 std::next(RangeEnd->getIterator())->isEHLabel()) 1108 RangeEnd = &*std::next(RangeEnd->getIterator()); 1109 1110 MachineBasicBlock *EHPad = nullptr; 1111 for (auto *Succ : MBB->successors()) { 1112 if (Succ->isEHPad()) { 1113 EHPad = Succ; 1114 break; 1115 } 1116 } 1117 1118 // Create the nested try instruction. 1119 MachineInstr *NestedTry = 1120 BuildMI(*MBB, *RangeBegin, RangeBegin->getDebugLoc(), 1121 TII.get(WebAssembly::TRY)) 1122 .addImm(int64_t(WebAssembly::ExprType::Void)); 1123 1124 // Create the nested EH pad and fill instructions in. 1125 MachineBasicBlock *NestedEHPad = MF.CreateMachineBasicBlock(); 1126 MF.insert(std::next(MBB->getIterator()), NestedEHPad); 1127 NestedEHPad->setIsEHPad(); 1128 NestedEHPad->setIsEHScopeEntry(); 1129 BuildMI(NestedEHPad, RangeEnd->getDebugLoc(), TII.get(WebAssembly::CATCH), 1130 ExnReg); 1131 BuildMI(NestedEHPad, RangeEnd->getDebugLoc(), TII.get(WebAssembly::BR)) 1132 .addMBB(BrDest); 1133 1134 // Create the nested continuation BB and end_try instruction. 1135 MachineBasicBlock *NestedCont = MF.CreateMachineBasicBlock(); 1136 MF.insert(std::next(NestedEHPad->getIterator()), NestedCont); 1137 MachineInstr *NestedEndTry = 1138 BuildMI(*NestedCont, NestedCont->begin(), RangeEnd->getDebugLoc(), 1139 TII.get(WebAssembly::END_TRY)); 1140 // In case MBB has more instructions after the try range, move them to the 1141 // new nested continuation BB. 1142 NestedCont->splice(NestedCont->end(), MBB, 1143 std::next(RangeEnd->getIterator()), MBB->end()); 1144 unstackifyVRegsUsedInSplitBB(*MBB, *NestedCont, MFI, MRI); 1145 registerTryScope(NestedTry, NestedEndTry, NestedEHPad); 1146 1147 // Fix predecessor-successor relationship. 1148 NestedCont->transferSuccessors(MBB); 1149 if (EHPad) 1150 NestedCont->removeSuccessor(EHPad); 1151 MBB->addSuccessor(NestedEHPad); 1152 MBB->addSuccessor(NestedCont); 1153 NestedEHPad->addSuccessor(BrDest); 1154 } 1155 } 1156 1157 // Renumber BBs and recalculate ScopeTop info because new BBs might have been 1158 // created and inserted above. 1159 MF.RenumberBlocks(); 1160 ScopeTops.clear(); 1161 ScopeTops.resize(MF.getNumBlockIDs()); 1162 for (auto &MBB : reverse(MF)) { 1163 for (auto &MI : reverse(MBB)) { 1164 if (ScopeTops[MBB.getNumber()]) 1165 break; 1166 switch (MI.getOpcode()) { 1167 case WebAssembly::END_BLOCK: 1168 case WebAssembly::END_LOOP: 1169 case WebAssembly::END_TRY: 1170 ScopeTops[MBB.getNumber()] = EndToBegin[&MI]->getParent(); 1171 break; 1172 case WebAssembly::CATCH: 1173 ScopeTops[MBB.getNumber()] = EHPadToTry[&MBB]->getParent(); 1174 break; 1175 } 1176 } 1177 } 1178 1179 // Recompute the dominator tree. 1180 getAnalysis<MachineDominatorTree>().runOnMachineFunction(MF); 1181 1182 // Place block markers for newly added branches. 1183 SmallVector <MachineBasicBlock *, 8> BrDests; 1184 for (auto &P : BrDestToTryRanges) 1185 BrDests.push_back(P.first); 1186 llvm::sort(BrDests, 1187 [&](const MachineBasicBlock *A, const MachineBasicBlock *B) { 1188 auto ANum = A->getNumber(); 1189 auto BNum = B->getNumber(); 1190 return ANum < BNum; 1191 }); 1192 for (auto *Dest : BrDests) 1193 placeBlockMarker(*Dest); 1194 1195 return true; 1196 } 1197 1198 static unsigned 1199 getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, 1200 const MachineBasicBlock *MBB) { 1201 unsigned Depth = 0; 1202 for (auto X : reverse(Stack)) { 1203 if (X == MBB) 1204 break; 1205 ++Depth; 1206 } 1207 assert(Depth < Stack.size() && "Branch destination should be in scope"); 1208 return Depth; 1209 } 1210 1211 /// In normal assembly languages, when the end of a function is unreachable, 1212 /// because the function ends in an infinite loop or a noreturn call or similar, 1213 /// it isn't necessary to worry about the function return type at the end of 1214 /// the function, because it's never reached. However, in WebAssembly, blocks 1215 /// that end at the function end need to have a return type signature that 1216 /// matches the function signature, even though it's unreachable. This function 1217 /// checks for such cases and fixes up the signatures. 1218 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 1219 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 1220 assert(MFI.getResults().size() <= 1); 1221 1222 if (MFI.getResults().empty()) 1223 return; 1224 1225 WebAssembly::ExprType RetType; 1226 switch (MFI.getResults().front().SimpleTy) { 1227 case MVT::i32: 1228 RetType = WebAssembly::ExprType::I32; 1229 break; 1230 case MVT::i64: 1231 RetType = WebAssembly::ExprType::I64; 1232 break; 1233 case MVT::f32: 1234 RetType = WebAssembly::ExprType::F32; 1235 break; 1236 case MVT::f64: 1237 RetType = WebAssembly::ExprType::F64; 1238 break; 1239 case MVT::v16i8: 1240 case MVT::v8i16: 1241 case MVT::v4i32: 1242 case MVT::v2i64: 1243 case MVT::v4f32: 1244 case MVT::v2f64: 1245 RetType = WebAssembly::ExprType::V128; 1246 break; 1247 case MVT::exnref: 1248 RetType = WebAssembly::ExprType::Exnref; 1249 break; 1250 default: 1251 llvm_unreachable("unexpected return type"); 1252 } 1253 1254 for (MachineBasicBlock &MBB : reverse(MF)) { 1255 for (MachineInstr &MI : reverse(MBB)) { 1256 if (MI.isPosition() || MI.isDebugInstr()) 1257 continue; 1258 if (MI.getOpcode() == WebAssembly::END_BLOCK) { 1259 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 1260 continue; 1261 } 1262 if (MI.getOpcode() == WebAssembly::END_LOOP) { 1263 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 1264 continue; 1265 } 1266 // Something other than an `end`. We're done. 1267 return; 1268 } 1269 } 1270 } 1271 1272 // WebAssembly functions end with an end instruction, as if the function body 1273 // were a block. 1274 static void appendEndToFunction(MachineFunction &MF, 1275 const WebAssemblyInstrInfo &TII) { 1276 BuildMI(MF.back(), MF.back().end(), 1277 MF.back().findPrevDebugLoc(MF.back().end()), 1278 TII.get(WebAssembly::END_FUNCTION)); 1279 } 1280 1281 /// Insert LOOP/TRY/BLOCK markers at appropriate places. 1282 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 1283 // We allocate one more than the number of blocks in the function to 1284 // accommodate for the possible fake block we may insert at the end. 1285 ScopeTops.resize(MF.getNumBlockIDs() + 1); 1286 // Place the LOOP for MBB if MBB is the header of a loop. 1287 for (auto &MBB : MF) 1288 placeLoopMarker(MBB); 1289 1290 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 1291 for (auto &MBB : MF) { 1292 if (MBB.isEHPad()) { 1293 // Place the TRY for MBB if MBB is the EH pad of an exception. 1294 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1295 MF.getFunction().hasPersonalityFn()) 1296 placeTryMarker(MBB); 1297 } else { 1298 // Place the BLOCK for MBB if MBB is branched to from above. 1299 placeBlockMarker(MBB); 1300 } 1301 } 1302 // Fix mismatches in unwind destinations induced by linearizing the code. 1303 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1304 MF.getFunction().hasPersonalityFn()) 1305 fixUnwindMismatches(MF); 1306 } 1307 1308 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 1309 // Now rewrite references to basic blocks to be depth immediates. 1310 SmallVector<const MachineBasicBlock *, 8> Stack; 1311 for (auto &MBB : reverse(MF)) { 1312 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { 1313 MachineInstr &MI = *I; 1314 switch (MI.getOpcode()) { 1315 case WebAssembly::BLOCK: 1316 case WebAssembly::TRY: 1317 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 1318 MBB.getNumber() && 1319 "Block/try marker should be balanced"); 1320 Stack.pop_back(); 1321 break; 1322 1323 case WebAssembly::LOOP: 1324 assert(Stack.back() == &MBB && "Loop top should be balanced"); 1325 Stack.pop_back(); 1326 break; 1327 1328 case WebAssembly::END_BLOCK: 1329 case WebAssembly::END_TRY: 1330 Stack.push_back(&MBB); 1331 break; 1332 1333 case WebAssembly::END_LOOP: 1334 Stack.push_back(EndToBegin[&MI]->getParent()); 1335 break; 1336 1337 default: 1338 if (MI.isTerminator()) { 1339 // Rewrite MBB operands to be depth immediates. 1340 SmallVector<MachineOperand, 4> Ops(MI.operands()); 1341 while (MI.getNumOperands() > 0) 1342 MI.RemoveOperand(MI.getNumOperands() - 1); 1343 for (auto MO : Ops) { 1344 if (MO.isMBB()) 1345 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB())); 1346 MI.addOperand(MF, MO); 1347 } 1348 } 1349 break; 1350 } 1351 } 1352 } 1353 assert(Stack.empty() && "Control flow should be balanced"); 1354 } 1355 1356 void WebAssemblyCFGStackify::releaseMemory() { 1357 ScopeTops.clear(); 1358 BeginToEnd.clear(); 1359 EndToBegin.clear(); 1360 TryToEHPad.clear(); 1361 EHPadToTry.clear(); 1362 AppendixBB = nullptr; 1363 } 1364 1365 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 1366 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 1367 "********** Function: " 1368 << MF.getName() << '\n'); 1369 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 1370 1371 releaseMemory(); 1372 1373 // Liveness is not tracked for VALUE_STACK physreg. 1374 MF.getRegInfo().invalidateLiveness(); 1375 1376 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes. 1377 placeMarkers(MF); 1378 1379 // Remove unnecessary instructions possibly introduced by try/end_trys. 1380 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1381 MF.getFunction().hasPersonalityFn()) 1382 removeUnnecessaryInstrs(MF); 1383 1384 // Convert MBB operands in terminators to relative depth immediates. 1385 rewriteDepthImmediates(MF); 1386 1387 // Fix up block/loop/try signatures at the end of the function to conform to 1388 // WebAssembly's rules. 1389 fixEndsAtEndOfFunction(MF); 1390 1391 // Add an end instruction at the end of the function body. 1392 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1393 if (!MF.getSubtarget<WebAssemblySubtarget>() 1394 .getTargetTriple() 1395 .isOSBinFormatELF()) 1396 appendEndToFunction(MF, TII); 1397 1398 MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified(); 1399 return true; 1400 } 1401