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