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