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 #include <cstring> 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 79 // Helper functions to register scope information created by marker 80 // instructions. 81 void registerScope(MachineInstr *Begin, MachineInstr *End); 82 void registerTryScope(MachineInstr *Begin, MachineInstr *End, 83 MachineBasicBlock *EHPad); 84 85 public: 86 static char ID; // Pass identification, replacement for typeid 87 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 88 ~WebAssemblyCFGStackify() override { releaseMemory(); } 89 void releaseMemory() override; 90 }; 91 } // end anonymous namespace 92 93 char WebAssemblyCFGStackify::ID = 0; 94 INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE, 95 "Insert BLOCK and LOOP markers for WebAssembly scopes", false, 96 false) 97 98 FunctionPass *llvm::createWebAssemblyCFGStackify() { 99 return new WebAssemblyCFGStackify(); 100 } 101 102 /// Test whether Pred has any terminators explicitly branching to MBB, as 103 /// opposed to falling through. Note that it's possible (eg. in unoptimized 104 /// code) for a branch instruction to both branch to a block and fallthrough 105 /// to it, so we check the actual branch operands to see if there are any 106 /// explicit mentions. 107 static bool explicitlyBranchesTo(MachineBasicBlock *Pred, 108 MachineBasicBlock *MBB) { 109 for (MachineInstr &MI : Pred->terminators()) 110 for (MachineOperand &MO : MI.explicit_operands()) 111 if (MO.isMBB() && MO.getMBB() == MBB) 112 return true; 113 return false; 114 } 115 116 // Returns an iterator to the earliest position possible within the MBB, 117 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 118 // contains instructions that should go before the marker, and AfterSet contains 119 // ones that should go after the marker. In this function, AfterSet is only 120 // used for sanity checking. 121 static MachineBasicBlock::iterator 122 getEarliestInsertPos(MachineBasicBlock *MBB, 123 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 124 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 125 auto InsertPos = MBB->end(); 126 while (InsertPos != MBB->begin()) { 127 if (BeforeSet.count(&*std::prev(InsertPos))) { 128 #ifndef NDEBUG 129 // Sanity check 130 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 131 assert(!AfterSet.count(&*std::prev(Pos))); 132 #endif 133 break; 134 } 135 --InsertPos; 136 } 137 return InsertPos; 138 } 139 140 // Returns an iterator to the latest position possible within the MBB, 141 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 142 // contains instructions that should go before the marker, and AfterSet contains 143 // ones that should go after the marker. In this function, BeforeSet is only 144 // used for sanity checking. 145 static MachineBasicBlock::iterator 146 getLatestInsertPos(MachineBasicBlock *MBB, 147 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 148 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 149 auto InsertPos = MBB->begin(); 150 while (InsertPos != MBB->end()) { 151 if (AfterSet.count(&*InsertPos)) { 152 #ifndef NDEBUG 153 // Sanity check 154 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 155 assert(!BeforeSet.count(&*Pos)); 156 #endif 157 break; 158 } 159 ++InsertPos; 160 } 161 return InsertPos; 162 } 163 164 void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 165 MachineInstr *End) { 166 BeginToEnd[Begin] = End; 167 EndToBegin[End] = Begin; 168 } 169 170 void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 171 MachineInstr *End, 172 MachineBasicBlock *EHPad) { 173 registerScope(Begin, End); 174 TryToEHPad[Begin] = EHPad; 175 EHPadToTry[EHPad] = Begin; 176 } 177 178 /// Insert a BLOCK marker for branches to MBB (if needed). 179 void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 180 // This should have been handled in placeTryMarker. 181 if (MBB.isEHPad()) 182 return; 183 184 MachineFunction &MF = *MBB.getParent(); 185 auto &MDT = getAnalysis<MachineDominatorTree>(); 186 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 187 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 188 189 // First compute the nearest common dominator of all forward non-fallthrough 190 // predecessors so that we minimize the time that the BLOCK is on the stack, 191 // which reduces overall stack height. 192 MachineBasicBlock *Header = nullptr; 193 bool IsBranchedTo = false; 194 bool IsBrOnExn = false; 195 MachineInstr *BrOnExn = nullptr; 196 int MBBNumber = MBB.getNumber(); 197 for (MachineBasicBlock *Pred : MBB.predecessors()) { 198 if (Pred->getNumber() < MBBNumber) { 199 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 200 if (explicitlyBranchesTo(Pred, &MBB)) { 201 IsBranchedTo = true; 202 if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) { 203 IsBrOnExn = true; 204 assert(!BrOnExn && "There should be only one br_on_exn per block"); 205 BrOnExn = &*Pred->getFirstTerminator(); 206 } 207 } 208 } 209 } 210 if (!Header) 211 return; 212 if (!IsBranchedTo) 213 return; 214 215 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 216 MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB)); 217 218 // If the nearest common dominator is inside a more deeply nested context, 219 // walk out to the nearest scope which isn't more deeply nested. 220 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 221 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 222 if (ScopeTop->getNumber() > Header->getNumber()) { 223 // Skip over an intervening scope. 224 I = std::next(MachineFunction::iterator(ScopeTop)); 225 } else { 226 // We found a scope level at an appropriate depth. 227 Header = ScopeTop; 228 break; 229 } 230 } 231 } 232 233 // Decide where in Header to put the BLOCK. 234 235 // Instructions that should go before the BLOCK. 236 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 237 // Instructions that should go after the BLOCK. 238 SmallPtrSet<const MachineInstr *, 4> AfterSet; 239 for (const auto &MI : *Header) { 240 // If there is a previously placed LOOP/TRY marker and the bottom block of 241 // the loop/exception is above MBB, it should be after the BLOCK, because 242 // the loop/exception is nested in this block. Otherwise it should be before 243 // the BLOCK. 244 if (MI.getOpcode() == WebAssembly::LOOP || 245 MI.getOpcode() == WebAssembly::TRY) { 246 auto *BottomBB = 247 &*std::prev(MachineFunction::iterator(BeginToEnd[&MI]->getParent())); 248 if (MBB.getNumber() > BottomBB->getNumber()) 249 AfterSet.insert(&MI); 250 #ifndef NDEBUG 251 else 252 BeforeSet.insert(&MI); 253 #endif 254 } 255 256 // All previously inserted BLOCK markers should be after the BLOCK because 257 // they are all nested blocks. 258 if (MI.getOpcode() == WebAssembly::BLOCK) 259 AfterSet.insert(&MI); 260 261 #ifndef NDEBUG 262 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK. 263 if (MI.getOpcode() == WebAssembly::END_BLOCK || 264 MI.getOpcode() == WebAssembly::END_LOOP || 265 MI.getOpcode() == WebAssembly::END_TRY) 266 BeforeSet.insert(&MI); 267 #endif 268 269 // Terminators should go after the BLOCK. 270 if (MI.isTerminator()) 271 AfterSet.insert(&MI); 272 } 273 274 // Local expression tree should go after the BLOCK. 275 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 276 --I) { 277 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 278 continue; 279 if (WebAssembly::isChild(*std::prev(I), MFI)) 280 AfterSet.insert(&*std::prev(I)); 281 else 282 break; 283 } 284 285 // Add the BLOCK. 286 287 // 'br_on_exn' extracts except_ref object and pushes variable number of values 288 // depending on its tag. For C++ exception, its a single i32 value, and the 289 // generated code will be in the form of: 290 // block i32 291 // br_on_exn 0, $__cpp_exception 292 // rethrow 293 // end_block 294 WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void; 295 if (IsBrOnExn) { 296 const char *TagName = BrOnExn->getOperand(1).getSymbolName(); 297 if (std::strcmp(TagName, "__cpp_exception") != 0) 298 llvm_unreachable("Only C++ exception is supported"); 299 ReturnType = WebAssembly::ExprType::I32; 300 } 301 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(ReturnType)); 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 MachineFunction &MF = *MBB.getParent(); 420 auto &MDT = getAnalysis<MachineDominatorTree>(); 421 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 422 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 423 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 424 425 // Compute the nearest common dominator of all unwind predecessors 426 MachineBasicBlock *Header = nullptr; 427 int MBBNumber = MBB.getNumber(); 428 for (auto *Pred : MBB.predecessors()) { 429 if (Pred->getNumber() < MBBNumber) { 430 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 431 assert(!explicitlyBranchesTo(Pred, &MBB) && 432 "Explicit branch to an EH pad!"); 433 } 434 } 435 if (!Header) 436 return; 437 438 // If this try is at the bottom of the function, insert a dummy block at the 439 // end. 440 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 441 assert(WE); 442 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE); 443 444 auto Iter = std::next(MachineFunction::iterator(Bottom)); 445 if (Iter == MF.end()) { 446 MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); 447 // Give it a fake predecessor so that AsmPrinter prints its label. 448 Label->addSuccessor(Label); 449 MF.push_back(Label); 450 Iter = std::next(MachineFunction::iterator(Bottom)); 451 } 452 MachineBasicBlock *AfterTry = &*Iter; 453 454 assert(AfterTry != &MF.front()); 455 MachineBasicBlock *LayoutPred = 456 &*std::prev(MachineFunction::iterator(AfterTry)); 457 458 // If the nearest common dominator is inside a more deeply nested context, 459 // walk out to the nearest scope which isn't more deeply nested. 460 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 461 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 462 if (ScopeTop->getNumber() > Header->getNumber()) { 463 // Skip over an intervening scope. 464 I = std::next(MachineFunction::iterator(ScopeTop)); 465 } else { 466 // We found a scope level at an appropriate depth. 467 Header = ScopeTop; 468 break; 469 } 470 } 471 } 472 473 // Decide where in Header to put the TRY. 474 475 // Instructions that should go before the BLOCK. 476 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 477 // Instructions that should go after the BLOCK. 478 SmallPtrSet<const MachineInstr *, 4> AfterSet; 479 for (const auto &MI : *Header) { 480 // If there is a previously placed LOOP marker and the bottom block of 481 // the loop is above MBB, the LOOP should be after the TRY, because the 482 // loop is nested in this try. Otherwise it should be before the TRY. 483 if (MI.getOpcode() == WebAssembly::LOOP) { 484 if (MBB.getNumber() > Bottom->getNumber()) 485 AfterSet.insert(&MI); 486 #ifndef NDEBUG 487 else 488 BeforeSet.insert(&MI); 489 #endif 490 } 491 492 // All previously inserted TRY markers should be after the TRY because they 493 // are all nested trys. 494 if (MI.getOpcode() == WebAssembly::TRY) 495 AfterSet.insert(&MI); 496 497 #ifndef NDEBUG 498 // All END_(LOOP/TRY) markers should be before the TRY. 499 if (MI.getOpcode() == WebAssembly::END_LOOP || 500 MI.getOpcode() == WebAssembly::END_TRY) 501 BeforeSet.insert(&MI); 502 #endif 503 504 // Terminators should go after the TRY. 505 if (MI.isTerminator()) 506 AfterSet.insert(&MI); 507 } 508 509 // Local expression tree should go after the TRY. 510 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 511 --I) { 512 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 513 continue; 514 if (WebAssembly::isChild(*std::prev(I), MFI)) 515 AfterSet.insert(&*std::prev(I)); 516 else 517 break; 518 } 519 520 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 521 // contain the call within it. So the call should go after the TRY. The 522 // exception is when the header's terminator is a rethrow instruction, in 523 // which case that instruction, not a call instruction before it, is gonna 524 // throw. 525 if (MBB.isPredecessor(Header)) { 526 auto TermPos = Header->getFirstTerminator(); 527 if (TermPos == Header->end() || 528 TermPos->getOpcode() != WebAssembly::RETHROW) { 529 for (const auto &MI : reverse(*Header)) { 530 if (MI.isCall()) { 531 AfterSet.insert(&MI); 532 break; 533 } 534 } 535 } 536 } 537 538 // Add the TRY. 539 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 540 MachineInstr *Begin = 541 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 542 TII.get(WebAssembly::TRY)) 543 .addImm(int64_t(WebAssembly::ExprType::Void)); 544 545 // Decide where in Header to put the END_TRY. 546 BeforeSet.clear(); 547 AfterSet.clear(); 548 for (const auto &MI : *AfterTry) { 549 #ifndef NDEBUG 550 // END_TRY should precede existing LOOP markers. 551 if (MI.getOpcode() == WebAssembly::LOOP) 552 AfterSet.insert(&MI); 553 554 // All END_TRY markers placed earlier belong to exceptions that contains 555 // this one. 556 if (MI.getOpcode() == WebAssembly::END_TRY) 557 AfterSet.insert(&MI); 558 #endif 559 560 // If there is a previously placed END_LOOP marker and its header is after 561 // where TRY marker is, this loop is contained within the 'catch' part, so 562 // the END_TRY marker should go after that. Otherwise, the whole try-catch 563 // is contained within this loop, so the END_TRY should go before that. 564 if (MI.getOpcode() == WebAssembly::END_LOOP) { 565 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 566 BeforeSet.insert(&MI); 567 #ifndef NDEBUG 568 else 569 AfterSet.insert(&MI); 570 #endif 571 } 572 } 573 574 // Mark the end of the TRY. 575 InsertPos = getEarliestInsertPos(AfterTry, BeforeSet, AfterSet); 576 MachineInstr *End = 577 BuildMI(*AfterTry, InsertPos, Bottom->findBranchDebugLoc(), 578 TII.get(WebAssembly::END_TRY)); 579 registerTryScope(Begin, End, &MBB); 580 581 // Track the farthest-spanning scope that ends at this point. 582 int Number = AfterTry->getNumber(); 583 if (!ScopeTops[Number] || 584 ScopeTops[Number]->getNumber() > Header->getNumber()) 585 ScopeTops[Number] = Header; 586 } 587 588 static unsigned 589 getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, 590 const MachineBasicBlock *MBB) { 591 unsigned Depth = 0; 592 for (auto X : reverse(Stack)) { 593 if (X == MBB) 594 break; 595 ++Depth; 596 } 597 assert(Depth < Stack.size() && "Branch destination should be in scope"); 598 return Depth; 599 } 600 601 /// In normal assembly languages, when the end of a function is unreachable, 602 /// because the function ends in an infinite loop or a noreturn call or similar, 603 /// it isn't necessary to worry about the function return type at the end of 604 /// the function, because it's never reached. However, in WebAssembly, blocks 605 /// that end at the function end need to have a return type signature that 606 /// matches the function signature, even though it's unreachable. This function 607 /// checks for such cases and fixes up the signatures. 608 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 609 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 610 assert(MFI.getResults().size() <= 1); 611 612 if (MFI.getResults().empty()) 613 return; 614 615 WebAssembly::ExprType RetType; 616 switch (MFI.getResults().front().SimpleTy) { 617 case MVT::i32: 618 RetType = WebAssembly::ExprType::I32; 619 break; 620 case MVT::i64: 621 RetType = WebAssembly::ExprType::I64; 622 break; 623 case MVT::f32: 624 RetType = WebAssembly::ExprType::F32; 625 break; 626 case MVT::f64: 627 RetType = WebAssembly::ExprType::F64; 628 break; 629 case MVT::v16i8: 630 case MVT::v8i16: 631 case MVT::v4i32: 632 case MVT::v2i64: 633 case MVT::v4f32: 634 case MVT::v2f64: 635 RetType = WebAssembly::ExprType::V128; 636 break; 637 case MVT::ExceptRef: 638 RetType = WebAssembly::ExprType::ExceptRef; 639 break; 640 default: 641 llvm_unreachable("unexpected return type"); 642 } 643 644 for (MachineBasicBlock &MBB : reverse(MF)) { 645 for (MachineInstr &MI : reverse(MBB)) { 646 if (MI.isPosition() || MI.isDebugInstr()) 647 continue; 648 if (MI.getOpcode() == WebAssembly::END_BLOCK) { 649 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 650 continue; 651 } 652 if (MI.getOpcode() == WebAssembly::END_LOOP) { 653 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 654 continue; 655 } 656 // Something other than an `end`. We're done. 657 return; 658 } 659 } 660 } 661 662 // WebAssembly functions end with an end instruction, as if the function body 663 // were a block. 664 static void appendEndToFunction(MachineFunction &MF, 665 const WebAssemblyInstrInfo &TII) { 666 BuildMI(MF.back(), MF.back().end(), 667 MF.back().findPrevDebugLoc(MF.back().end()), 668 TII.get(WebAssembly::END_FUNCTION)); 669 } 670 671 /// Insert LOOP/TRY/BLOCK markers at appropriate places. 672 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 673 // We allocate one more than the number of blocks in the function to 674 // accommodate for the possible fake block we may insert at the end. 675 ScopeTops.resize(MF.getNumBlockIDs() + 1); 676 // Place the LOOP for MBB if MBB is the header of a loop. 677 for (auto &MBB : MF) 678 placeLoopMarker(MBB); 679 // Place the TRY for MBB if MBB is the EH pad of an exception. 680 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 681 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 682 MF.getFunction().hasPersonalityFn()) 683 for (auto &MBB : MF) 684 placeTryMarker(MBB); 685 // Place the BLOCK for MBB if MBB is branched to from above. 686 for (auto &MBB : MF) 687 placeBlockMarker(MBB); 688 } 689 690 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 691 // Now rewrite references to basic blocks to be depth immediates. 692 SmallVector<const MachineBasicBlock *, 8> Stack; 693 for (auto &MBB : reverse(MF)) { 694 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { 695 MachineInstr &MI = *I; 696 switch (MI.getOpcode()) { 697 case WebAssembly::BLOCK: 698 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 699 MBB.getNumber() && 700 "Block/try should be balanced"); 701 Stack.pop_back(); 702 break; 703 704 case WebAssembly::TRY: 705 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 706 MBB.getNumber() && 707 "Block/try marker should be balanced"); 708 Stack.pop_back(); 709 break; 710 711 case WebAssembly::LOOP: 712 assert(Stack.back() == &MBB && "Loop top should be balanced"); 713 Stack.pop_back(); 714 break; 715 716 case WebAssembly::END_BLOCK: 717 case WebAssembly::END_TRY: 718 Stack.push_back(&MBB); 719 break; 720 721 case WebAssembly::END_LOOP: 722 Stack.push_back(EndToBegin[&MI]->getParent()); 723 break; 724 725 default: 726 if (MI.isTerminator()) { 727 // Rewrite MBB operands to be depth immediates. 728 SmallVector<MachineOperand, 4> Ops(MI.operands()); 729 while (MI.getNumOperands() > 0) 730 MI.RemoveOperand(MI.getNumOperands() - 1); 731 for (auto MO : Ops) { 732 if (MO.isMBB()) 733 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB())); 734 MI.addOperand(MF, MO); 735 } 736 } 737 break; 738 } 739 } 740 } 741 assert(Stack.empty() && "Control flow should be balanced"); 742 } 743 744 void WebAssemblyCFGStackify::releaseMemory() { 745 ScopeTops.clear(); 746 BeginToEnd.clear(); 747 EndToBegin.clear(); 748 TryToEHPad.clear(); 749 EHPadToTry.clear(); 750 } 751 752 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 753 errs() << "Function: " << MF.getName() << "\n"; 754 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 755 "********** Function: " 756 << MF.getName() << '\n'); 757 758 releaseMemory(); 759 760 // Liveness is not tracked for VALUE_STACK physreg. 761 MF.getRegInfo().invalidateLiveness(); 762 763 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes. 764 placeMarkers(MF); 765 766 // Convert MBB operands in terminators to relative depth immediates. 767 rewriteDepthImmediates(MF); 768 769 // Fix up block/loop/try signatures at the end of the function to conform to 770 // WebAssembly's rules. 771 fixEndsAtEndOfFunction(MF); 772 773 // Add an end instruction at the end of the function body. 774 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 775 if (!MF.getSubtarget<WebAssemblySubtarget>() 776 .getTargetTriple() 777 .isOSBinFormatELF()) 778 appendEndToFunction(MF, TII); 779 780 return true; 781 } 782