1 //===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// 10 /// \file 11 /// This file implements a CFG stacking pass. 12 /// 13 /// This pass inserts BLOCK, LOOP, and TRY markers to mark the start of scopes, 14 /// since scope boundaries serve as the labels for WebAssembly's control 15 /// transfers. 16 /// 17 /// This is sufficient to convert arbitrary CFGs into a form that works on 18 /// WebAssembly, provided that all loops are single-entry. 19 /// 20 /// In case we use exceptions, this pass also fixes mismatches in unwind 21 /// destinations created during transforming CFG into wasm structured format. 22 /// 23 //===----------------------------------------------------------------------===// 24 25 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 26 #include "WebAssembly.h" 27 #include "WebAssemblyExceptionInfo.h" 28 #include "WebAssemblyMachineFunctionInfo.h" 29 #include "WebAssemblySubtarget.h" 30 #include "WebAssemblyUtilities.h" 31 #include "llvm/CodeGen/MachineDominators.h" 32 #include "llvm/CodeGen/MachineFunction.h" 33 #include "llvm/CodeGen/MachineInstrBuilder.h" 34 #include "llvm/CodeGen/MachineLoopInfo.h" 35 #include "llvm/CodeGen/MachineRegisterInfo.h" 36 #include "llvm/CodeGen/Passes.h" 37 #include "llvm/CodeGen/WasmEHFuncInfo.h" 38 #include "llvm/MC/MCAsmInfo.h" 39 #include "llvm/Support/Debug.h" 40 #include "llvm/Support/raw_ostream.h" 41 using namespace llvm; 42 43 #define DEBUG_TYPE "wasm-cfg-stackify" 44 45 namespace { 46 class WebAssemblyCFGStackify final : public MachineFunctionPass { 47 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; } 48 49 void getAnalysisUsage(AnalysisUsage &AU) const override { 50 AU.addRequired<MachineDominatorTree>(); 51 AU.addRequired<MachineLoopInfo>(); 52 AU.addRequired<WebAssemblyExceptionInfo>(); 53 MachineFunctionPass::getAnalysisUsage(AU); 54 } 55 56 bool runOnMachineFunction(MachineFunction &MF) override; 57 58 // For each block whose label represents the end of a scope, record the block 59 // which holds the beginning of the scope. This will allow us to quickly skip 60 // over scoped regions when walking blocks. 61 SmallVector<MachineBasicBlock *, 8> ScopeTops; 62 63 void placeMarkers(MachineFunction &MF); 64 void placeBlockMarker(MachineBasicBlock &MBB); 65 void placeLoopMarker(MachineBasicBlock &MBB); 66 void placeTryMarker(MachineBasicBlock &MBB); 67 void rewriteDepthImmediates(MachineFunction &MF); 68 void fixEndsAtEndOfFunction(MachineFunction &MF); 69 70 // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY). 71 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd; 72 // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY. 73 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin; 74 // <TRY marker, EH pad> map 75 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad; 76 // <EH pad, TRY marker> map 77 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry; 78 // <LOOP|TRY marker, Loop/exception bottom BB> map 79 DenseMap<const MachineInstr *, MachineBasicBlock *> BeginToBottom; 80 81 // Helper functions to register scope information created by marker 82 // instructions. 83 void registerScope(MachineInstr *Begin, MachineInstr *End); 84 void registerTryScope(MachineInstr *Begin, MachineInstr *End, 85 MachineBasicBlock *EHPad); 86 87 MachineBasicBlock *getBottom(const MachineInstr *Begin); 88 89 public: 90 static char ID; // Pass identification, replacement for typeid 91 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 92 ~WebAssemblyCFGStackify() override { releaseMemory(); } 93 void releaseMemory() override; 94 }; 95 } // end anonymous namespace 96 97 char WebAssemblyCFGStackify::ID = 0; 98 INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE, 99 "Insert BLOCK and LOOP markers for WebAssembly scopes", false, 100 false) 101 102 FunctionPass *llvm::createWebAssemblyCFGStackify() { 103 return new WebAssemblyCFGStackify(); 104 } 105 106 /// Test whether Pred has any terminators explicitly branching to MBB, as 107 /// opposed to falling through. Note that it's possible (eg. in unoptimized 108 /// code) for a branch instruction to both branch to a block and fallthrough 109 /// to it, so we check the actual branch operands to see if there are any 110 /// explicit mentions. 111 static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred, 112 MachineBasicBlock *MBB) { 113 for (MachineInstr &MI : Pred->terminators()) 114 // Even if a rethrow takes a BB argument, it is not a branch 115 if (!WebAssembly::isRethrow(MI)) 116 for (MachineOperand &MO : MI.explicit_operands()) 117 if (MO.isMBB() && MO.getMBB() == MBB) 118 return true; 119 return false; 120 } 121 122 // Returns an iterator to the earliest position possible within the MBB, 123 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 124 // contains instructions that should go before the marker, and AfterSet contains 125 // ones that should go after the marker. In this function, AfterSet is only 126 // used for sanity checking. 127 static MachineBasicBlock::iterator 128 GetEarliestInsertPos(MachineBasicBlock *MBB, 129 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 130 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 131 auto InsertPos = MBB->end(); 132 while (InsertPos != MBB->begin()) { 133 if (BeforeSet.count(&*std::prev(InsertPos))) { 134 #ifndef NDEBUG 135 // Sanity check 136 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 137 assert(!AfterSet.count(&*std::prev(Pos))); 138 #endif 139 break; 140 } 141 --InsertPos; 142 } 143 return InsertPos; 144 } 145 146 // Returns an iterator to the latest position possible within the MBB, 147 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 148 // contains instructions that should go before the marker, and AfterSet contains 149 // ones that should go after the marker. In this function, BeforeSet is only 150 // used for sanity checking. 151 static MachineBasicBlock::iterator 152 GetLatestInsertPos(MachineBasicBlock *MBB, 153 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 154 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 155 auto InsertPos = MBB->begin(); 156 while (InsertPos != MBB->end()) { 157 if (AfterSet.count(&*InsertPos)) { 158 #ifndef NDEBUG 159 // Sanity check 160 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 161 assert(!BeforeSet.count(&*Pos)); 162 #endif 163 break; 164 } 165 ++InsertPos; 166 } 167 return InsertPos; 168 } 169 170 void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 171 MachineInstr *End) { 172 BeginToEnd[Begin] = End; 173 EndToBegin[End] = Begin; 174 } 175 176 void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 177 MachineInstr *End, 178 MachineBasicBlock *EHPad) { 179 registerScope(Begin, End); 180 TryToEHPad[Begin] = EHPad; 181 EHPadToTry[EHPad] = Begin; 182 } 183 184 // Given a LOOP/TRY marker, returns its bottom BB. Use cached information if any 185 // to prevent recomputation. 186 MachineBasicBlock * 187 WebAssemblyCFGStackify::getBottom(const MachineInstr *Begin) { 188 const auto &MLI = getAnalysis<MachineLoopInfo>(); 189 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 190 if (BeginToBottom.count(Begin)) 191 return BeginToBottom[Begin]; 192 if (Begin->getOpcode() == WebAssembly::LOOP) { 193 MachineLoop *L = MLI.getLoopFor(Begin->getParent()); 194 assert(L); 195 BeginToBottom[Begin] = WebAssembly::getBottom(L); 196 } else if (Begin->getOpcode() == WebAssembly::TRY) { 197 WebAssemblyException *WE = WEI.getExceptionFor(TryToEHPad[Begin]); 198 assert(WE); 199 BeginToBottom[Begin] = WebAssembly::getBottom(WE); 200 } else 201 assert(false); 202 return BeginToBottom[Begin]; 203 } 204 205 /// Insert a BLOCK marker for branches to MBB (if needed). 206 void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 207 // This should have been handled in placeTryMarker. 208 if (MBB.isEHPad()) 209 return; 210 211 MachineFunction &MF = *MBB.getParent(); 212 auto &MDT = getAnalysis<MachineDominatorTree>(); 213 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 214 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 215 216 // First compute the nearest common dominator of all forward non-fallthrough 217 // predecessors so that we minimize the time that the BLOCK is on the stack, 218 // which reduces overall stack height. 219 MachineBasicBlock *Header = nullptr; 220 bool IsBranchedTo = false; 221 int MBBNumber = MBB.getNumber(); 222 for (MachineBasicBlock *Pred : MBB.predecessors()) { 223 if (Pred->getNumber() < MBBNumber) { 224 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 225 if (ExplicitlyBranchesTo(Pred, &MBB)) 226 IsBranchedTo = true; 227 } 228 } 229 if (!Header) 230 return; 231 if (!IsBranchedTo) 232 return; 233 234 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 235 MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB)); 236 237 // If the nearest common dominator is inside a more deeply nested context, 238 // walk out to the nearest scope which isn't more deeply nested. 239 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 240 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 241 if (ScopeTop->getNumber() > Header->getNumber()) { 242 // Skip over an intervening scope. 243 I = std::next(MachineFunction::iterator(ScopeTop)); 244 } else { 245 // We found a scope level at an appropriate depth. 246 Header = ScopeTop; 247 break; 248 } 249 } 250 } 251 252 // Decide where in Header to put the BLOCK. 253 254 // Instructions that should go before the BLOCK. 255 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 256 // Instructions that should go after the BLOCK. 257 SmallPtrSet<const MachineInstr *, 4> AfterSet; 258 for (const auto &MI : *Header) { 259 // If there is a previously placed LOOP/TRY marker and the bottom block of 260 // the loop/exception is above MBB, it should be after the BLOCK, because 261 // the loop/exception is nested in this block. Otherwise it should be before 262 // the BLOCK. 263 if (MI.getOpcode() == WebAssembly::LOOP || 264 MI.getOpcode() == WebAssembly::TRY) { 265 if (MBB.getNumber() > getBottom(&MI)->getNumber()) 266 AfterSet.insert(&MI); 267 #ifndef NDEBUG 268 else 269 BeforeSet.insert(&MI); 270 #endif 271 } 272 273 // All previously inserted BLOCK markers should be after the BLOCK because 274 // they are all nested blocks. 275 if (MI.getOpcode() == WebAssembly::BLOCK) 276 AfterSet.insert(&MI); 277 278 #ifndef NDEBUG 279 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK. 280 if (MI.getOpcode() == WebAssembly::END_BLOCK || 281 MI.getOpcode() == WebAssembly::END_LOOP || 282 MI.getOpcode() == WebAssembly::END_TRY) 283 BeforeSet.insert(&MI); 284 #endif 285 286 // Terminators should go after the BLOCK. 287 if (MI.isTerminator()) 288 AfterSet.insert(&MI); 289 } 290 291 // Local expression tree should go after the BLOCK. 292 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 293 --I) { 294 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 295 continue; 296 if (WebAssembly::isChild(*std::prev(I), MFI)) 297 AfterSet.insert(&*std::prev(I)); 298 else 299 break; 300 } 301 302 // Add the BLOCK. 303 auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet); 304 MachineInstr *Begin = 305 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 306 TII.get(WebAssembly::BLOCK)) 307 .addImm(int64_t(WebAssembly::ExprType::Void)); 308 309 // Decide where in Header to put the END_BLOCK. 310 BeforeSet.clear(); 311 AfterSet.clear(); 312 for (auto &MI : MBB) { 313 #ifndef NDEBUG 314 // END_BLOCK should precede existing LOOP and TRY markers. 315 if (MI.getOpcode() == WebAssembly::LOOP || 316 MI.getOpcode() == WebAssembly::TRY) 317 AfterSet.insert(&MI); 318 #endif 319 320 // If there is a previously placed END_LOOP marker and the header of the 321 // loop is above this block's header, the END_LOOP should be placed after 322 // the BLOCK, because the loop contains this block. Otherwise the END_LOOP 323 // should be placed before the BLOCK. The same for END_TRY. 324 if (MI.getOpcode() == WebAssembly::END_LOOP || 325 MI.getOpcode() == WebAssembly::END_TRY) { 326 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 327 BeforeSet.insert(&MI); 328 #ifndef NDEBUG 329 else 330 AfterSet.insert(&MI); 331 #endif 332 } 333 } 334 335 // Mark the end of the block. 336 InsertPos = GetEarliestInsertPos(&MBB, BeforeSet, AfterSet); 337 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 338 TII.get(WebAssembly::END_BLOCK)); 339 registerScope(Begin, End); 340 341 // Track the farthest-spanning scope that ends at this point. 342 int Number = MBB.getNumber(); 343 if (!ScopeTops[Number] || 344 ScopeTops[Number]->getNumber() > Header->getNumber()) 345 ScopeTops[Number] = Header; 346 } 347 348 /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). 349 void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) { 350 MachineFunction &MF = *MBB.getParent(); 351 const auto &MLI = getAnalysis<MachineLoopInfo>(); 352 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 353 354 MachineLoop *Loop = MLI.getLoopFor(&MBB); 355 if (!Loop || Loop->getHeader() != &MBB) 356 return; 357 358 // The operand of a LOOP is the first block after the loop. If the loop is the 359 // bottom of the function, insert a dummy block at the end. 360 MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop); 361 auto Iter = std::next(MachineFunction::iterator(Bottom)); 362 if (Iter == MF.end()) { 363 MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); 364 // Give it a fake predecessor so that AsmPrinter prints its label. 365 Label->addSuccessor(Label); 366 MF.push_back(Label); 367 Iter = std::next(MachineFunction::iterator(Bottom)); 368 } 369 MachineBasicBlock *AfterLoop = &*Iter; 370 371 // Decide where in Header to put the LOOP. 372 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 373 SmallPtrSet<const MachineInstr *, 4> AfterSet; 374 for (const auto &MI : MBB) { 375 // LOOP marker should be after any existing loop that ends here. Otherwise 376 // we assume the instruction belongs to the loop. 377 if (MI.getOpcode() == WebAssembly::END_LOOP) 378 BeforeSet.insert(&MI); 379 #ifndef NDEBUG 380 else 381 AfterSet.insert(&MI); 382 #endif 383 } 384 385 // Mark the beginning of the loop. 386 auto InsertPos = GetEarliestInsertPos(&MBB, BeforeSet, AfterSet); 387 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos), 388 TII.get(WebAssembly::LOOP)) 389 .addImm(int64_t(WebAssembly::ExprType::Void)); 390 391 // Decide where in Header to put the END_LOOP. 392 BeforeSet.clear(); 393 AfterSet.clear(); 394 #ifndef NDEBUG 395 for (const auto &MI : MBB) 396 // Existing END_LOOP markers belong to parent loops of this loop 397 if (MI.getOpcode() == WebAssembly::END_LOOP) 398 AfterSet.insert(&MI); 399 #endif 400 401 // Mark the end of the loop (using arbitrary debug location that branched to 402 // the loop end as its location). 403 InsertPos = GetEarliestInsertPos(AfterLoop, BeforeSet, AfterSet); 404 DebugLoc EndDL = (*AfterLoop->pred_rbegin())->findBranchDebugLoc(); 405 MachineInstr *End = 406 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP)); 407 registerScope(Begin, End); 408 409 assert((!ScopeTops[AfterLoop->getNumber()] || 410 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && 411 "With block sorting the outermost loop for a block should be first."); 412 if (!ScopeTops[AfterLoop->getNumber()]) 413 ScopeTops[AfterLoop->getNumber()] = &MBB; 414 } 415 416 void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) { 417 if (!MBB.isEHPad()) 418 return; 419 420 // catch_all terminate pad is grouped together with catch terminate pad and 421 // does not need a separate TRY and END_TRY marker. 422 if (WebAssembly::isCatchAllTerminatePad(MBB)) 423 return; 424 425 MachineFunction &MF = *MBB.getParent(); 426 auto &MDT = getAnalysis<MachineDominatorTree>(); 427 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 428 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 429 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 430 431 // Compute the nearest common dominator of all unwind predecessors 432 MachineBasicBlock *Header = nullptr; 433 int MBBNumber = MBB.getNumber(); 434 for (auto *Pred : MBB.predecessors()) { 435 if (Pred->getNumber() < MBBNumber) { 436 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 437 assert(!ExplicitlyBranchesTo(Pred, &MBB) && 438 "Explicit branch to an EH pad!"); 439 } 440 } 441 if (!Header) 442 return; 443 444 // If this try is at the bottom of the function, insert a dummy block at the 445 // end. 446 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 447 assert(WE); 448 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE); 449 450 auto Iter = std::next(MachineFunction::iterator(Bottom)); 451 if (Iter == MF.end()) { 452 MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); 453 // Give it a fake predecessor so that AsmPrinter prints its label. 454 Label->addSuccessor(Label); 455 MF.push_back(Label); 456 Iter = std::next(MachineFunction::iterator(Bottom)); 457 } 458 MachineBasicBlock *AfterTry = &*Iter; 459 460 assert(AfterTry != &MF.front()); 461 MachineBasicBlock *LayoutPred = 462 &*std::prev(MachineFunction::iterator(AfterTry)); 463 464 // If the nearest common dominator is inside a more deeply nested context, 465 // walk out to the nearest scope which isn't more deeply nested. 466 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 467 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 468 if (ScopeTop->getNumber() > Header->getNumber()) { 469 // Skip over an intervening scope. 470 I = std::next(MachineFunction::iterator(ScopeTop)); 471 } else { 472 // We found a scope level at an appropriate depth. 473 Header = ScopeTop; 474 break; 475 } 476 } 477 } 478 479 // Decide where in Header to put the TRY. 480 481 // Instructions that should go before the BLOCK. 482 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 483 // Instructions that should go after the BLOCK. 484 SmallPtrSet<const MachineInstr *, 4> AfterSet; 485 for (const auto &MI : *Header) { 486 // If there is a previously placed LOOP marker and the bottom block of 487 // the loop is above MBB, the LOOP should be after the TRY, because the 488 // loop is nested in this try. Otherwise it should be before the TRY. 489 if (MI.getOpcode() == WebAssembly::LOOP) { 490 if (MBB.getNumber() > Bottom->getNumber()) 491 AfterSet.insert(&MI); 492 #ifndef NDEBUG 493 else 494 BeforeSet.insert(&MI); 495 #endif 496 } 497 498 // All previously inserted TRY markers should be after the TRY because they 499 // are all nested trys. 500 if (MI.getOpcode() == WebAssembly::TRY) 501 AfterSet.insert(&MI); 502 503 #ifndef NDEBUG 504 // All END_(LOOP/TRY) markers should be before the TRY. 505 if (MI.getOpcode() == WebAssembly::END_LOOP || 506 MI.getOpcode() == WebAssembly::END_TRY) 507 BeforeSet.insert(&MI); 508 #endif 509 510 // Terminators should go after the TRY. 511 if (MI.isTerminator()) 512 AfterSet.insert(&MI); 513 } 514 515 // Local expression tree should go after the TRY. 516 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 517 --I) { 518 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 519 continue; 520 if (WebAssembly::isChild(*std::prev(I), MFI)) 521 AfterSet.insert(&*std::prev(I)); 522 else 523 break; 524 } 525 526 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 527 // contain the call within it. So the call should go after the TRY. The 528 // exception is when the header's terminator is a rethrow instruction, in 529 // which case that instruction, not a call instruction before it, is gonna 530 // throw. 531 if (MBB.isPredecessor(Header)) { 532 auto TermPos = Header->getFirstTerminator(); 533 if (TermPos == Header->end() || !WebAssembly::isRethrow(*TermPos)) { 534 for (const auto &MI : reverse(*Header)) { 535 if (MI.isCall()) { 536 AfterSet.insert(&MI); 537 break; 538 } 539 } 540 } 541 } 542 543 // Add the TRY. 544 auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet); 545 MachineInstr *Begin = 546 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 547 TII.get(WebAssembly::TRY)) 548 .addImm(int64_t(WebAssembly::ExprType::Void)); 549 550 // Decide where in Header to put the END_TRY. 551 BeforeSet.clear(); 552 AfterSet.clear(); 553 for (const auto &MI : *AfterTry) { 554 #ifndef NDEBUG 555 // END_TRY should precede existing LOOP markers. 556 if (MI.getOpcode() == WebAssembly::LOOP) 557 AfterSet.insert(&MI); 558 559 // All END_TRY markers placed earlier belong to exceptions that contains 560 // this one. 561 if (MI.getOpcode() == WebAssembly::END_TRY) 562 AfterSet.insert(&MI); 563 #endif 564 565 // If there is a previously placed END_LOOP marker and its header is after 566 // where TRY marker is, this loop is contained within the 'catch' part, so 567 // the END_TRY marker should go after that. Otherwise, the whole try-catch 568 // is contained within this loop, so the END_TRY should go before that. 569 if (MI.getOpcode() == WebAssembly::END_LOOP) { 570 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 571 BeforeSet.insert(&MI); 572 #ifndef NDEBUG 573 else 574 AfterSet.insert(&MI); 575 #endif 576 } 577 } 578 579 // Mark the end of the TRY. 580 InsertPos = GetEarliestInsertPos(AfterTry, BeforeSet, AfterSet); 581 MachineInstr *End = 582 BuildMI(*AfterTry, InsertPos, Bottom->findBranchDebugLoc(), 583 TII.get(WebAssembly::END_TRY)); 584 registerTryScope(Begin, End, &MBB); 585 586 // Track the farthest-spanning scope that ends at this point. 587 int Number = AfterTry->getNumber(); 588 if (!ScopeTops[Number] || 589 ScopeTops[Number]->getNumber() > Header->getNumber()) 590 ScopeTops[Number] = Header; 591 } 592 593 static unsigned 594 GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, 595 const MachineBasicBlock *MBB) { 596 unsigned Depth = 0; 597 for (auto X : reverse(Stack)) { 598 if (X == MBB) 599 break; 600 ++Depth; 601 } 602 assert(Depth < Stack.size() && "Branch destination should be in scope"); 603 return Depth; 604 } 605 606 /// In normal assembly languages, when the end of a function is unreachable, 607 /// because the function ends in an infinite loop or a noreturn call or similar, 608 /// it isn't necessary to worry about the function return type at the end of 609 /// the function, because it's never reached. However, in WebAssembly, blocks 610 /// that end at the function end need to have a return type signature that 611 /// matches the function signature, even though it's unreachable. This function 612 /// checks for such cases and fixes up the signatures. 613 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 614 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 615 assert(MFI.getResults().size() <= 1); 616 617 if (MFI.getResults().empty()) 618 return; 619 620 WebAssembly::ExprType retType; 621 switch (MFI.getResults().front().SimpleTy) { 622 case MVT::i32: 623 retType = WebAssembly::ExprType::I32; 624 break; 625 case MVT::i64: 626 retType = WebAssembly::ExprType::I64; 627 break; 628 case MVT::f32: 629 retType = WebAssembly::ExprType::F32; 630 break; 631 case MVT::f64: 632 retType = WebAssembly::ExprType::F64; 633 break; 634 case MVT::v16i8: 635 case MVT::v8i16: 636 case MVT::v4i32: 637 case MVT::v2i64: 638 case MVT::v4f32: 639 case MVT::v2f64: 640 retType = WebAssembly::ExprType::V128; 641 break; 642 case MVT::ExceptRef: 643 retType = WebAssembly::ExprType::ExceptRef; 644 break; 645 default: 646 llvm_unreachable("unexpected return type"); 647 } 648 649 for (MachineBasicBlock &MBB : reverse(MF)) { 650 for (MachineInstr &MI : reverse(MBB)) { 651 if (MI.isPosition() || MI.isDebugInstr()) 652 continue; 653 if (MI.getOpcode() == WebAssembly::END_BLOCK) { 654 EndToBegin[&MI]->getOperand(0).setImm(int32_t(retType)); 655 continue; 656 } 657 if (MI.getOpcode() == WebAssembly::END_LOOP) { 658 EndToBegin[&MI]->getOperand(0).setImm(int32_t(retType)); 659 continue; 660 } 661 // Something other than an `end`. We're done. 662 return; 663 } 664 } 665 } 666 667 // WebAssembly functions end with an end instruction, as if the function body 668 // were a block. 669 static void AppendEndToFunction(MachineFunction &MF, 670 const WebAssemblyInstrInfo &TII) { 671 BuildMI(MF.back(), MF.back().end(), 672 MF.back().findPrevDebugLoc(MF.back().end()), 673 TII.get(WebAssembly::END_FUNCTION)); 674 } 675 676 /// Insert LOOP/TRY/BLOCK markers at appropriate places. 677 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 678 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 679 // We allocate one more than the number of blocks in the function to 680 // accommodate for the possible fake block we may insert at the end. 681 ScopeTops.resize(MF.getNumBlockIDs() + 1); 682 // Place the LOOP for MBB if MBB is the header of a loop. 683 for (auto &MBB : MF) 684 placeLoopMarker(MBB); 685 // Place the TRY for MBB if MBB is the EH pad of an exception. 686 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 687 MF.getFunction().hasPersonalityFn()) 688 for (auto &MBB : MF) 689 placeTryMarker(MBB); 690 // Place the BLOCK for MBB if MBB is branched to from above. 691 for (auto &MBB : MF) 692 placeBlockMarker(MBB); 693 } 694 695 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 696 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 697 // Now rewrite references to basic blocks to be depth immediates. 698 // We need two stacks: one for normal scopes and the other for EH pad scopes. 699 // EH pad stack is used to rewrite depths in rethrow instructions. 700 SmallVector<const MachineBasicBlock *, 8> Stack; 701 SmallVector<const MachineBasicBlock *, 8> EHPadStack; 702 for (auto &MBB : reverse(MF)) { 703 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { 704 MachineInstr &MI = *I; 705 switch (MI.getOpcode()) { 706 case WebAssembly::BLOCK: 707 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 708 MBB.getNumber() && 709 "Block/try should be balanced"); 710 Stack.pop_back(); 711 break; 712 713 case WebAssembly::TRY: 714 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 715 MBB.getNumber() && 716 "Block/try marker should be balanced"); 717 Stack.pop_back(); 718 EHPadStack.pop_back(); 719 break; 720 721 case WebAssembly::CATCH_I32: 722 case WebAssembly::CATCH_I64: 723 case WebAssembly::CATCH_ALL: 724 // Currently the only case there are more than one catch for a try is 725 // for catch terminate pad, in the form of 726 // try 727 // catch 728 // call @__clang_call_terminate 729 // unreachable 730 // catch_all 731 // call @std::terminate 732 // unreachable 733 // end 734 // So we shouldn't push the current BB for the second catch_all block 735 // here. 736 if (!WebAssembly::isCatchAllTerminatePad(MBB)) 737 EHPadStack.push_back(&MBB); 738 break; 739 740 case WebAssembly::LOOP: 741 assert(Stack.back() == &MBB && "Loop top should be balanced"); 742 Stack.pop_back(); 743 break; 744 745 case WebAssembly::END_BLOCK: 746 case WebAssembly::END_TRY: 747 Stack.push_back(&MBB); 748 break; 749 750 case WebAssembly::END_LOOP: 751 Stack.push_back(EndToBegin[&MI]->getParent()); 752 break; 753 754 case WebAssembly::RETHROW: { 755 // Rewrite MBB operands to be depth immediates. 756 unsigned EHPadDepth = GetDepth(EHPadStack, MI.getOperand(0).getMBB()); 757 MI.RemoveOperand(0); 758 MI.addOperand(MF, MachineOperand::CreateImm(EHPadDepth)); 759 break; 760 } 761 762 case WebAssembly::RETHROW_TO_CALLER: { 763 MachineInstr *Rethrow = 764 BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(WebAssembly::RETHROW)) 765 .addImm(EHPadStack.size()); 766 MI.eraseFromParent(); 767 I = MachineBasicBlock::reverse_iterator(Rethrow); 768 break; 769 } 770 771 default: 772 if (MI.isTerminator()) { 773 // Rewrite MBB operands to be depth immediates. 774 SmallVector<MachineOperand, 4> Ops(MI.operands()); 775 while (MI.getNumOperands() > 0) 776 MI.RemoveOperand(MI.getNumOperands() - 1); 777 for (auto MO : Ops) { 778 if (MO.isMBB()) 779 MO = MachineOperand::CreateImm(GetDepth(Stack, MO.getMBB())); 780 MI.addOperand(MF, MO); 781 } 782 } 783 break; 784 } 785 } 786 } 787 assert(Stack.empty() && "Control flow should be balanced"); 788 } 789 790 void WebAssemblyCFGStackify::releaseMemory() { 791 ScopeTops.clear(); 792 BeginToEnd.clear(); 793 EndToBegin.clear(); 794 TryToEHPad.clear(); 795 EHPadToTry.clear(); 796 BeginToBottom.clear(); 797 } 798 799 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 800 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 801 "********** Function: " 802 << MF.getName() << '\n'); 803 804 releaseMemory(); 805 806 // Liveness is not tracked for VALUE_STACK physreg. 807 MF.getRegInfo().invalidateLiveness(); 808 809 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes. 810 placeMarkers(MF); 811 812 // Convert MBB operands in terminators to relative depth immediates. 813 rewriteDepthImmediates(MF); 814 815 // Fix up block/loop/try signatures at the end of the function to conform to 816 // WebAssembly's rules. 817 fixEndsAtEndOfFunction(MF); 818 819 // Add an end instruction at the end of the function body. 820 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 821 if (!MF.getSubtarget<WebAssemblySubtarget>() 822 .getTargetTriple() 823 .isOSBinFormatELF()) 824 AppendEndToFunction(MF, TII); 825 826 return true; 827 } 828