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 removeUnnecessaryInstrs(MachineFunction &MF); 68 void rewriteDepthImmediates(MachineFunction &MF); 69 void fixEndsAtEndOfFunction(MachineFunction &MF); 70 71 // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY). 72 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd; 73 // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY. 74 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin; 75 // <TRY marker, EH pad> map 76 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad; 77 // <EH pad, TRY marker> map 78 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry; 79 80 // Helper functions to register / unregister scope information created by 81 // marker instructions. 82 void registerScope(MachineInstr *Begin, MachineInstr *End); 83 void registerTryScope(MachineInstr *Begin, MachineInstr *End, 84 MachineBasicBlock *EHPad); 85 void unregisterScope(MachineInstr *Begin); 86 87 public: 88 static char ID; // Pass identification, replacement for typeid 89 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 90 ~WebAssemblyCFGStackify() override { releaseMemory(); } 91 void releaseMemory() override; 92 }; 93 } // end anonymous namespace 94 95 char WebAssemblyCFGStackify::ID = 0; 96 INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE, 97 "Insert BLOCK and LOOP markers for WebAssembly scopes", false, 98 false) 99 100 FunctionPass *llvm::createWebAssemblyCFGStackify() { 101 return new WebAssemblyCFGStackify(); 102 } 103 104 /// Test whether Pred has any terminators explicitly branching to MBB, as 105 /// opposed to falling through. Note that it's possible (eg. in unoptimized 106 /// code) for a branch instruction to both branch to a block and fallthrough 107 /// to it, so we check the actual branch operands to see if there are any 108 /// explicit mentions. 109 static bool explicitlyBranchesTo(MachineBasicBlock *Pred, 110 MachineBasicBlock *MBB) { 111 for (MachineInstr &MI : Pred->terminators()) 112 for (MachineOperand &MO : MI.explicit_operands()) 113 if (MO.isMBB() && MO.getMBB() == MBB) 114 return true; 115 return false; 116 } 117 118 // Returns an iterator to the earliest position possible within the MBB, 119 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 120 // contains instructions that should go before the marker, and AfterSet contains 121 // ones that should go after the marker. In this function, AfterSet is only 122 // used for sanity checking. 123 static MachineBasicBlock::iterator 124 getEarliestInsertPos(MachineBasicBlock *MBB, 125 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 126 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 127 auto InsertPos = MBB->end(); 128 while (InsertPos != MBB->begin()) { 129 if (BeforeSet.count(&*std::prev(InsertPos))) { 130 #ifndef NDEBUG 131 // Sanity check 132 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 133 assert(!AfterSet.count(&*std::prev(Pos))); 134 #endif 135 break; 136 } 137 --InsertPos; 138 } 139 return InsertPos; 140 } 141 142 // Returns an iterator to the latest position possible within the MBB, 143 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 144 // contains instructions that should go before the marker, and AfterSet contains 145 // ones that should go after the marker. In this function, BeforeSet is only 146 // used for sanity checking. 147 static MachineBasicBlock::iterator 148 getLatestInsertPos(MachineBasicBlock *MBB, 149 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 150 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 151 auto InsertPos = MBB->begin(); 152 while (InsertPos != MBB->end()) { 153 if (AfterSet.count(&*InsertPos)) { 154 #ifndef NDEBUG 155 // Sanity check 156 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 157 assert(!BeforeSet.count(&*Pos)); 158 #endif 159 break; 160 } 161 ++InsertPos; 162 } 163 return InsertPos; 164 } 165 166 void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 167 MachineInstr *End) { 168 BeginToEnd[Begin] = End; 169 EndToBegin[End] = Begin; 170 } 171 172 void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 173 MachineInstr *End, 174 MachineBasicBlock *EHPad) { 175 registerScope(Begin, End); 176 TryToEHPad[Begin] = EHPad; 177 EHPadToTry[EHPad] = Begin; 178 } 179 180 void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) { 181 assert(BeginToEnd.count(Begin)); 182 MachineInstr *End = BeginToEnd[Begin]; 183 assert(EndToBegin.count(End)); 184 BeginToEnd.erase(Begin); 185 EndToBegin.erase(End); 186 MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin); 187 if (EHPad) { 188 assert(EHPadToTry.count(EHPad)); 189 TryToEHPad.erase(Begin); 190 EHPadToTry.erase(EHPad); 191 } 192 } 193 194 /// Insert a BLOCK marker for branches to MBB (if needed). 195 void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 196 // This should have been handled in placeTryMarker. 197 if (MBB.isEHPad()) 198 return; 199 200 MachineFunction &MF = *MBB.getParent(); 201 auto &MDT = getAnalysis<MachineDominatorTree>(); 202 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 203 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 204 205 // First compute the nearest common dominator of all forward non-fallthrough 206 // predecessors so that we minimize the time that the BLOCK is on the stack, 207 // which reduces overall stack height. 208 MachineBasicBlock *Header = nullptr; 209 bool IsBranchedTo = false; 210 bool IsBrOnExn = false; 211 MachineInstr *BrOnExn = nullptr; 212 int MBBNumber = MBB.getNumber(); 213 for (MachineBasicBlock *Pred : MBB.predecessors()) { 214 if (Pred->getNumber() < MBBNumber) { 215 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 216 if (explicitlyBranchesTo(Pred, &MBB)) { 217 IsBranchedTo = true; 218 if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) { 219 IsBrOnExn = true; 220 assert(!BrOnExn && "There should be only one br_on_exn per block"); 221 BrOnExn = &*Pred->getFirstTerminator(); 222 } 223 } 224 } 225 } 226 if (!Header) 227 return; 228 if (!IsBranchedTo) 229 return; 230 231 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 232 MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB)); 233 234 // If the nearest common dominator is inside a more deeply nested context, 235 // walk out to the nearest scope which isn't more deeply nested. 236 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 237 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 238 if (ScopeTop->getNumber() > Header->getNumber()) { 239 // Skip over an intervening scope. 240 I = std::next(MachineFunction::iterator(ScopeTop)); 241 } else { 242 // We found a scope level at an appropriate depth. 243 Header = ScopeTop; 244 break; 245 } 246 } 247 } 248 249 // Decide where in Header to put the BLOCK. 250 251 // Instructions that should go before the BLOCK. 252 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 253 // Instructions that should go after the BLOCK. 254 SmallPtrSet<const MachineInstr *, 4> AfterSet; 255 for (const auto &MI : *Header) { 256 // If there is a previously placed LOOP/TRY marker and the bottom block of 257 // the loop/exception is above MBB, it should be after the BLOCK, because 258 // the loop/exception is nested in this block. Otherwise it should be before 259 // the BLOCK. 260 if (MI.getOpcode() == WebAssembly::LOOP || 261 MI.getOpcode() == WebAssembly::TRY) { 262 auto *BottomBB = 263 &*std::prev(MachineFunction::iterator(BeginToEnd[&MI]->getParent())); 264 if (MBB.getNumber() > BottomBB->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 303 // 'br_on_exn' extracts except_ref object and pushes variable number of values 304 // depending on its tag. For C++ exception, its a single i32 value, and the 305 // generated code will be in the form of: 306 // block i32 307 // br_on_exn 0, $__cpp_exception 308 // rethrow 309 // end_block 310 WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void; 311 if (IsBrOnExn) { 312 const char *TagName = BrOnExn->getOperand(1).getSymbolName(); 313 if (std::strcmp(TagName, "__cpp_exception") != 0) 314 llvm_unreachable("Only C++ exception is supported"); 315 ReturnType = WebAssembly::ExprType::I32; 316 } 317 318 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 319 MachineInstr *Begin = 320 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 321 TII.get(WebAssembly::BLOCK)) 322 .addImm(int64_t(ReturnType)); 323 324 // Decide where in Header to put the END_BLOCK. 325 BeforeSet.clear(); 326 AfterSet.clear(); 327 for (auto &MI : MBB) { 328 #ifndef NDEBUG 329 // END_BLOCK should precede existing LOOP and TRY markers. 330 if (MI.getOpcode() == WebAssembly::LOOP || 331 MI.getOpcode() == WebAssembly::TRY) 332 AfterSet.insert(&MI); 333 #endif 334 335 // If there is a previously placed END_LOOP marker and the header of the 336 // loop is above this block's header, the END_LOOP should be placed after 337 // the BLOCK, because the loop contains this block. Otherwise the END_LOOP 338 // should be placed before the BLOCK. The same for END_TRY. 339 if (MI.getOpcode() == WebAssembly::END_LOOP || 340 MI.getOpcode() == WebAssembly::END_TRY) { 341 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 342 BeforeSet.insert(&MI); 343 #ifndef NDEBUG 344 else 345 AfterSet.insert(&MI); 346 #endif 347 } 348 } 349 350 // Mark the end of the block. 351 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 352 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 353 TII.get(WebAssembly::END_BLOCK)); 354 registerScope(Begin, End); 355 356 // Track the farthest-spanning scope that ends at this point. 357 int Number = MBB.getNumber(); 358 if (!ScopeTops[Number] || 359 ScopeTops[Number]->getNumber() > Header->getNumber()) 360 ScopeTops[Number] = Header; 361 } 362 363 /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). 364 void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) { 365 MachineFunction &MF = *MBB.getParent(); 366 const auto &MLI = getAnalysis<MachineLoopInfo>(); 367 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 368 369 MachineLoop *Loop = MLI.getLoopFor(&MBB); 370 if (!Loop || Loop->getHeader() != &MBB) 371 return; 372 373 // The operand of a LOOP is the first block after the loop. If the loop is the 374 // bottom of the function, insert a dummy block at the end. 375 MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop); 376 auto Iter = std::next(MachineFunction::iterator(Bottom)); 377 if (Iter == MF.end()) { 378 MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); 379 // Give it a fake predecessor so that AsmPrinter prints its label. 380 Label->addSuccessor(Label); 381 MF.push_back(Label); 382 Iter = std::next(MachineFunction::iterator(Bottom)); 383 } 384 MachineBasicBlock *AfterLoop = &*Iter; 385 386 // Decide where in Header to put the LOOP. 387 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 388 SmallPtrSet<const MachineInstr *, 4> AfterSet; 389 for (const auto &MI : MBB) { 390 // LOOP marker should be after any existing loop that ends here. Otherwise 391 // we assume the instruction belongs to the loop. 392 if (MI.getOpcode() == WebAssembly::END_LOOP) 393 BeforeSet.insert(&MI); 394 #ifndef NDEBUG 395 else 396 AfterSet.insert(&MI); 397 #endif 398 } 399 400 // Mark the beginning of the loop. 401 auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 402 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos), 403 TII.get(WebAssembly::LOOP)) 404 .addImm(int64_t(WebAssembly::ExprType::Void)); 405 406 // Decide where in Header to put the END_LOOP. 407 BeforeSet.clear(); 408 AfterSet.clear(); 409 #ifndef NDEBUG 410 for (const auto &MI : MBB) 411 // Existing END_LOOP markers belong to parent loops of this loop 412 if (MI.getOpcode() == WebAssembly::END_LOOP) 413 AfterSet.insert(&MI); 414 #endif 415 416 // Mark the end of the loop (using arbitrary debug location that branched to 417 // the loop end as its location). 418 InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet); 419 DebugLoc EndDL = (*AfterLoop->pred_rbegin())->findBranchDebugLoc(); 420 MachineInstr *End = 421 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP)); 422 registerScope(Begin, End); 423 424 assert((!ScopeTops[AfterLoop->getNumber()] || 425 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && 426 "With block sorting the outermost loop for a block should be first."); 427 if (!ScopeTops[AfterLoop->getNumber()]) 428 ScopeTops[AfterLoop->getNumber()] = &MBB; 429 } 430 431 void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) { 432 if (!MBB.isEHPad()) 433 return; 434 435 MachineFunction &MF = *MBB.getParent(); 436 auto &MDT = getAnalysis<MachineDominatorTree>(); 437 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 438 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 439 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 440 441 // Compute the nearest common dominator of all unwind predecessors 442 MachineBasicBlock *Header = nullptr; 443 int MBBNumber = MBB.getNumber(); 444 for (auto *Pred : MBB.predecessors()) { 445 if (Pred->getNumber() < MBBNumber) { 446 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 447 assert(!explicitlyBranchesTo(Pred, &MBB) && 448 "Explicit branch to an EH pad!"); 449 } 450 } 451 if (!Header) 452 return; 453 454 // If this try is at the bottom of the function, insert a dummy block at the 455 // end. 456 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 457 assert(WE); 458 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE); 459 460 auto Iter = std::next(MachineFunction::iterator(Bottom)); 461 if (Iter == MF.end()) { 462 MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); 463 // Give it a fake predecessor so that AsmPrinter prints its label. 464 Label->addSuccessor(Label); 465 MF.push_back(Label); 466 Iter = std::next(MachineFunction::iterator(Bottom)); 467 } 468 MachineBasicBlock *Cont = &*Iter; 469 470 assert(Cont != &MF.front()); 471 MachineBasicBlock *LayoutPred = 472 &*std::prev(MachineFunction::iterator(Cont)); 473 474 // If the nearest common dominator is inside a more deeply nested context, 475 // walk out to the nearest scope which isn't more deeply nested. 476 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 477 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 478 if (ScopeTop->getNumber() > Header->getNumber()) { 479 // Skip over an intervening scope. 480 I = std::next(MachineFunction::iterator(ScopeTop)); 481 } else { 482 // We found a scope level at an appropriate depth. 483 Header = ScopeTop; 484 break; 485 } 486 } 487 } 488 489 // Decide where in Header to put the TRY. 490 491 // Instructions that should go before the BLOCK. 492 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 493 // Instructions that should go after the BLOCK. 494 SmallPtrSet<const MachineInstr *, 4> AfterSet; 495 for (const auto &MI : *Header) { 496 // If there is a previously placed LOOP marker and the bottom block of 497 // the loop is above MBB, the LOOP should be after the TRY, because the 498 // loop is nested in this try. Otherwise it should be before the TRY. 499 if (MI.getOpcode() == WebAssembly::LOOP) { 500 if (MBB.getNumber() > Bottom->getNumber()) 501 AfterSet.insert(&MI); 502 #ifndef NDEBUG 503 else 504 BeforeSet.insert(&MI); 505 #endif 506 } 507 508 // All previously inserted TRY markers should be after the TRY because they 509 // are all nested trys. 510 if (MI.getOpcode() == WebAssembly::TRY) 511 AfterSet.insert(&MI); 512 513 #ifndef NDEBUG 514 // All END_(LOOP/TRY) markers should be before the TRY. 515 if (MI.getOpcode() == WebAssembly::END_LOOP || 516 MI.getOpcode() == WebAssembly::END_TRY) 517 BeforeSet.insert(&MI); 518 #endif 519 520 // Terminators should go after the TRY. 521 if (MI.isTerminator()) 522 AfterSet.insert(&MI); 523 } 524 525 // Local expression tree should go after the TRY. 526 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 527 --I) { 528 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 529 continue; 530 if (WebAssembly::isChild(*std::prev(I), MFI)) 531 AfterSet.insert(&*std::prev(I)); 532 else 533 break; 534 } 535 536 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 537 // contain the call within it. So the call should go after the TRY. The 538 // exception is when the header's terminator is a rethrow instruction, in 539 // which case that instruction, not a call instruction before it, is gonna 540 // throw. 541 if (MBB.isPredecessor(Header)) { 542 auto TermPos = Header->getFirstTerminator(); 543 if (TermPos == Header->end() || 544 TermPos->getOpcode() != WebAssembly::RETHROW) { 545 for (const auto &MI : reverse(*Header)) { 546 if (MI.isCall()) { 547 AfterSet.insert(&MI); 548 break; 549 } 550 } 551 } 552 } 553 554 // Add the TRY. 555 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 556 MachineInstr *Begin = 557 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 558 TII.get(WebAssembly::TRY)) 559 .addImm(int64_t(WebAssembly::ExprType::Void)); 560 561 // Decide where in Header to put the END_TRY. 562 BeforeSet.clear(); 563 AfterSet.clear(); 564 for (const auto &MI : *Cont) { 565 #ifndef NDEBUG 566 // END_TRY should precede existing LOOP markers. 567 if (MI.getOpcode() == WebAssembly::LOOP) 568 AfterSet.insert(&MI); 569 570 // All END_TRY markers placed earlier belong to exceptions that contains 571 // this one. 572 if (MI.getOpcode() == WebAssembly::END_TRY) 573 AfterSet.insert(&MI); 574 #endif 575 576 // If there is a previously placed END_LOOP marker and its header is after 577 // where TRY marker is, this loop is contained within the 'catch' part, so 578 // the END_TRY marker should go after that. Otherwise, the whole try-catch 579 // is contained within this loop, so the END_TRY should go before that. 580 if (MI.getOpcode() == WebAssembly::END_LOOP) { 581 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 582 BeforeSet.insert(&MI); 583 #ifndef NDEBUG 584 else 585 AfterSet.insert(&MI); 586 #endif 587 } 588 } 589 590 // Mark the end of the TRY. 591 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet); 592 MachineInstr *End = 593 BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(), 594 TII.get(WebAssembly::END_TRY)); 595 registerTryScope(Begin, End, &MBB); 596 597 // Track the farthest-spanning scope that ends at this point. We create two 598 // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB 599 // with 'try'). We need to create 'catch' -> 'try' mapping here too because 600 // markers should not span across 'catch'. For example, this should not 601 // happen: 602 // 603 // try 604 // block --| (X) 605 // catch | 606 // end_block --| 607 // end_try 608 for (int Number : {Cont->getNumber(), MBB.getNumber()}) { 609 if (!ScopeTops[Number] || 610 ScopeTops[Number]->getNumber() > Header->getNumber()) 611 ScopeTops[Number] = Header; 612 } 613 } 614 615 void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) { 616 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 617 618 // When there is an unconditional branch right before a catch instruction and 619 // it branches to the end of end_try marker, we don't need the branch, because 620 // it there is no exception, the control flow transfers to that point anyway. 621 // bb0: 622 // try 623 // ... 624 // br bb2 <- Not necessary 625 // bb1: 626 // catch 627 // ... 628 // bb2: 629 // end 630 for (auto &MBB : MF) { 631 if (!MBB.isEHPad()) 632 continue; 633 634 MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 635 SmallVector<MachineOperand, 4> Cond; 636 MachineBasicBlock *EHPadLayoutPred = 637 &*std::prev(MachineFunction::iterator(&MBB)); 638 MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent(); 639 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 640 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) || 641 (!Cond.empty() && FBB && FBB == Cont))) 642 TII.removeBranch(*EHPadLayoutPred); 643 } 644 645 // When there are block / end_block markers that overlap with try / end_try 646 // markers, and the block and try markers' return types are the same, the 647 // block /end_block markers are not necessary, because try / end_try markers 648 // also can serve as boundaries for branches. 649 // block <- Not necessary 650 // try 651 // ... 652 // catch 653 // ... 654 // end 655 // end <- Not necessary 656 SmallVector<MachineInstr *, 32> ToDelete; 657 for (auto &MBB : MF) { 658 for (auto &MI : MBB) { 659 if (MI.getOpcode() != WebAssembly::TRY) 660 continue; 661 662 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try]; 663 MachineBasicBlock *TryBB = Try->getParent(); 664 MachineBasicBlock *Cont = EndTry->getParent(); 665 int64_t RetType = Try->getOperand(0).getImm(); 666 for (auto B = MachineBasicBlock::iterator(Try), 667 E = std::next(MachineBasicBlock::iterator(EndTry)); 668 B != TryBB->begin() && E != Cont->end() && 669 std::prev(B)->getOpcode() == WebAssembly::BLOCK && 670 E->getOpcode() == WebAssembly::END_BLOCK && 671 std::prev(B)->getOperand(0).getImm() == RetType; 672 --B, ++E) { 673 ToDelete.push_back(&*std::prev(B)); 674 ToDelete.push_back(&*E); 675 } 676 } 677 } 678 for (auto *MI : ToDelete) { 679 if (MI->getOpcode() == WebAssembly::BLOCK) 680 unregisterScope(MI); 681 MI->eraseFromParent(); 682 } 683 } 684 685 static unsigned 686 getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, 687 const MachineBasicBlock *MBB) { 688 unsigned Depth = 0; 689 for (auto X : reverse(Stack)) { 690 if (X == MBB) 691 break; 692 ++Depth; 693 } 694 assert(Depth < Stack.size() && "Branch destination should be in scope"); 695 return Depth; 696 } 697 698 /// In normal assembly languages, when the end of a function is unreachable, 699 /// because the function ends in an infinite loop or a noreturn call or similar, 700 /// it isn't necessary to worry about the function return type at the end of 701 /// the function, because it's never reached. However, in WebAssembly, blocks 702 /// that end at the function end need to have a return type signature that 703 /// matches the function signature, even though it's unreachable. This function 704 /// checks for such cases and fixes up the signatures. 705 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 706 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 707 assert(MFI.getResults().size() <= 1); 708 709 if (MFI.getResults().empty()) 710 return; 711 712 WebAssembly::ExprType RetType; 713 switch (MFI.getResults().front().SimpleTy) { 714 case MVT::i32: 715 RetType = WebAssembly::ExprType::I32; 716 break; 717 case MVT::i64: 718 RetType = WebAssembly::ExprType::I64; 719 break; 720 case MVT::f32: 721 RetType = WebAssembly::ExprType::F32; 722 break; 723 case MVT::f64: 724 RetType = WebAssembly::ExprType::F64; 725 break; 726 case MVT::v16i8: 727 case MVT::v8i16: 728 case MVT::v4i32: 729 case MVT::v2i64: 730 case MVT::v4f32: 731 case MVT::v2f64: 732 RetType = WebAssembly::ExprType::V128; 733 break; 734 case MVT::ExceptRef: 735 RetType = WebAssembly::ExprType::ExceptRef; 736 break; 737 default: 738 llvm_unreachable("unexpected return type"); 739 } 740 741 for (MachineBasicBlock &MBB : reverse(MF)) { 742 for (MachineInstr &MI : reverse(MBB)) { 743 if (MI.isPosition() || MI.isDebugInstr()) 744 continue; 745 if (MI.getOpcode() == WebAssembly::END_BLOCK) { 746 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 747 continue; 748 } 749 if (MI.getOpcode() == WebAssembly::END_LOOP) { 750 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 751 continue; 752 } 753 // Something other than an `end`. We're done. 754 return; 755 } 756 } 757 } 758 759 // WebAssembly functions end with an end instruction, as if the function body 760 // were a block. 761 static void appendEndToFunction(MachineFunction &MF, 762 const WebAssemblyInstrInfo &TII) { 763 BuildMI(MF.back(), MF.back().end(), 764 MF.back().findPrevDebugLoc(MF.back().end()), 765 TII.get(WebAssembly::END_FUNCTION)); 766 } 767 768 /// Insert LOOP/TRY/BLOCK markers at appropriate places. 769 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 770 // We allocate one more than the number of blocks in the function to 771 // accommodate for the possible fake block we may insert at the end. 772 ScopeTops.resize(MF.getNumBlockIDs() + 1); 773 // Place the LOOP for MBB if MBB is the header of a loop. 774 for (auto &MBB : MF) 775 placeLoopMarker(MBB); 776 // Place the TRY for MBB if MBB is the EH pad of an exception. 777 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 778 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 779 MF.getFunction().hasPersonalityFn()) 780 for (auto &MBB : MF) 781 placeTryMarker(MBB); 782 // Place the BLOCK for MBB if MBB is branched to from above. 783 for (auto &MBB : MF) 784 placeBlockMarker(MBB); 785 } 786 787 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 788 // Now rewrite references to basic blocks to be depth immediates. 789 SmallVector<const MachineBasicBlock *, 8> Stack; 790 for (auto &MBB : reverse(MF)) { 791 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { 792 MachineInstr &MI = *I; 793 switch (MI.getOpcode()) { 794 case WebAssembly::BLOCK: 795 case WebAssembly::TRY: 796 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 797 MBB.getNumber() && 798 "Block/try marker should be balanced"); 799 Stack.pop_back(); 800 break; 801 802 case WebAssembly::LOOP: 803 assert(Stack.back() == &MBB && "Loop top should be balanced"); 804 Stack.pop_back(); 805 break; 806 807 case WebAssembly::END_BLOCK: 808 case WebAssembly::END_TRY: 809 Stack.push_back(&MBB); 810 break; 811 812 case WebAssembly::END_LOOP: 813 Stack.push_back(EndToBegin[&MI]->getParent()); 814 break; 815 816 default: 817 if (MI.isTerminator()) { 818 // Rewrite MBB operands to be depth immediates. 819 SmallVector<MachineOperand, 4> Ops(MI.operands()); 820 while (MI.getNumOperands() > 0) 821 MI.RemoveOperand(MI.getNumOperands() - 1); 822 for (auto MO : Ops) { 823 if (MO.isMBB()) 824 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB())); 825 MI.addOperand(MF, MO); 826 } 827 } 828 break; 829 } 830 } 831 } 832 assert(Stack.empty() && "Control flow should be balanced"); 833 } 834 835 void WebAssemblyCFGStackify::releaseMemory() { 836 ScopeTops.clear(); 837 BeginToEnd.clear(); 838 EndToBegin.clear(); 839 TryToEHPad.clear(); 840 EHPadToTry.clear(); 841 } 842 843 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 844 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 845 "********** Function: " 846 << MF.getName() << '\n'); 847 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 848 849 releaseMemory(); 850 851 // Liveness is not tracked for VALUE_STACK physreg. 852 MF.getRegInfo().invalidateLiveness(); 853 854 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes. 855 placeMarkers(MF); 856 857 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 858 MF.getFunction().hasPersonalityFn()) 859 // Remove unnecessary instructions. 860 removeUnnecessaryInstrs(MF); 861 862 // Convert MBB operands in terminators to relative depth immediates. 863 rewriteDepthImmediates(MF); 864 865 // Fix up block/loop/try signatures at the end of the function to conform to 866 // WebAssembly's rules. 867 fixEndsAtEndOfFunction(MF); 868 869 // Add an end instruction at the end of the function body. 870 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 871 if (!MF.getSubtarget<WebAssemblySubtarget>() 872 .getTargetTriple() 873 .isOSBinFormatELF()) 874 appendEndToFunction(MF, TII); 875 876 return true; 877 } 878