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 "WebAssembly.h" 25 #include "WebAssemblyExceptionInfo.h" 26 #include "WebAssemblyMachineFunctionInfo.h" 27 #include "WebAssemblySortRegion.h" 28 #include "WebAssemblySubtarget.h" 29 #include "WebAssemblyUtilities.h" 30 #include "llvm/ADT/Statistic.h" 31 #include "llvm/CodeGen/MachineDominators.h" 32 #include "llvm/CodeGen/MachineInstrBuilder.h" 33 #include "llvm/CodeGen/MachineLoopInfo.h" 34 #include "llvm/MC/MCAsmInfo.h" 35 #include "llvm/Target/TargetMachine.h" 36 using namespace llvm; 37 using WebAssembly::SortRegionInfo; 38 39 #define DEBUG_TYPE "wasm-cfg-stackify" 40 41 STATISTIC(NumUnwindMismatches, "Number of EH pad unwind mismatches found"); 42 43 namespace { 44 class WebAssemblyCFGStackify final : public MachineFunctionPass { 45 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; } 46 47 void getAnalysisUsage(AnalysisUsage &AU) const override { 48 AU.addRequired<MachineDominatorTree>(); 49 AU.addRequired<MachineLoopInfo>(); 50 AU.addRequired<WebAssemblyExceptionInfo>(); 51 MachineFunctionPass::getAnalysisUsage(AU); 52 } 53 54 bool runOnMachineFunction(MachineFunction &MF) override; 55 56 // For each block whose label represents the end of a scope, record the block 57 // which holds the beginning of the scope. This will allow us to quickly skip 58 // over scoped regions when walking blocks. 59 SmallVector<MachineBasicBlock *, 8> ScopeTops; 60 61 // Placing markers. 62 void placeMarkers(MachineFunction &MF); 63 void placeBlockMarker(MachineBasicBlock &MBB); 64 void placeLoopMarker(MachineBasicBlock &MBB); 65 void placeTryMarker(MachineBasicBlock &MBB); 66 void removeUnnecessaryInstrs(MachineFunction &MF); 67 bool fixUnwindMismatches(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 // There can be an appendix block at the end of each function, shared for: 81 // - creating a correct signature for fallthrough returns 82 // - target for rethrows that need to unwind to the caller, but are trapped 83 // inside another try/catch 84 MachineBasicBlock *AppendixBB = nullptr; 85 MachineBasicBlock *getAppendixBlock(MachineFunction &MF) { 86 if (!AppendixBB) { 87 AppendixBB = MF.CreateMachineBasicBlock(); 88 // Give it a fake predecessor so that AsmPrinter prints its label. 89 AppendixBB->addSuccessor(AppendixBB); 90 MF.push_back(AppendixBB); 91 } 92 return AppendixBB; 93 } 94 95 // Helper functions to register / unregister scope information created by 96 // marker instructions. 97 void registerScope(MachineInstr *Begin, MachineInstr *End); 98 void registerTryScope(MachineInstr *Begin, MachineInstr *End, 99 MachineBasicBlock *EHPad); 100 void unregisterScope(MachineInstr *Begin); 101 102 public: 103 static char ID; // Pass identification, replacement for typeid 104 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {} 105 ~WebAssemblyCFGStackify() override { releaseMemory(); } 106 void releaseMemory() override; 107 }; 108 } // end anonymous namespace 109 110 char WebAssemblyCFGStackify::ID = 0; 111 INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE, 112 "Insert BLOCK/LOOP/TRY markers for WebAssembly scopes", false, 113 false) 114 115 FunctionPass *llvm::createWebAssemblyCFGStackify() { 116 return new WebAssemblyCFGStackify(); 117 } 118 119 /// Test whether Pred has any terminators explicitly branching to MBB, as 120 /// opposed to falling through. Note that it's possible (eg. in unoptimized 121 /// code) for a branch instruction to both branch to a block and fallthrough 122 /// to it, so we check the actual branch operands to see if there are any 123 /// explicit mentions. 124 static bool explicitlyBranchesTo(MachineBasicBlock *Pred, 125 MachineBasicBlock *MBB) { 126 for (MachineInstr &MI : Pred->terminators()) 127 for (MachineOperand &MO : MI.explicit_operands()) 128 if (MO.isMBB() && MO.getMBB() == MBB) 129 return true; 130 return false; 131 } 132 133 // Returns an iterator to the earliest position possible within the MBB, 134 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 135 // contains instructions that should go before the marker, and AfterSet contains 136 // ones that should go after the marker. In this function, AfterSet is only 137 // used for sanity checking. 138 static MachineBasicBlock::iterator 139 getEarliestInsertPos(MachineBasicBlock *MBB, 140 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 141 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 142 auto InsertPos = MBB->end(); 143 while (InsertPos != MBB->begin()) { 144 if (BeforeSet.count(&*std::prev(InsertPos))) { 145 #ifndef NDEBUG 146 // Sanity check 147 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos) 148 assert(!AfterSet.count(&*std::prev(Pos))); 149 #endif 150 break; 151 } 152 --InsertPos; 153 } 154 return InsertPos; 155 } 156 157 // Returns an iterator to the latest position possible within the MBB, 158 // satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet 159 // contains instructions that should go before the marker, and AfterSet contains 160 // ones that should go after the marker. In this function, BeforeSet is only 161 // used for sanity checking. 162 static MachineBasicBlock::iterator 163 getLatestInsertPos(MachineBasicBlock *MBB, 164 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet, 165 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) { 166 auto InsertPos = MBB->begin(); 167 while (InsertPos != MBB->end()) { 168 if (AfterSet.count(&*InsertPos)) { 169 #ifndef NDEBUG 170 // Sanity check 171 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos) 172 assert(!BeforeSet.count(&*Pos)); 173 #endif 174 break; 175 } 176 ++InsertPos; 177 } 178 return InsertPos; 179 } 180 181 // Find a catch instruction and its destination register within an EH pad. 182 static MachineInstr *findCatch(MachineBasicBlock *EHPad, Register &ExnReg) { 183 assert(EHPad->isEHPad()); 184 MachineInstr *Catch = nullptr; 185 for (auto &MI : *EHPad) { 186 if (WebAssembly::isCatch(MI.getOpcode())) { 187 Catch = &MI; 188 ExnReg = Catch->getOperand(0).getReg(); 189 break; 190 } 191 } 192 assert(Catch && "EH pad does not have a catch"); 193 assert(ExnReg != 0 && "Invalid register"); 194 return Catch; 195 } 196 197 static MachineInstr *findCatch(MachineBasicBlock *EHPad) { 198 Register Dummy; 199 return findCatch(EHPad, Dummy); 200 } 201 202 void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin, 203 MachineInstr *End) { 204 BeginToEnd[Begin] = End; 205 EndToBegin[End] = Begin; 206 } 207 208 void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin, 209 MachineInstr *End, 210 MachineBasicBlock *EHPad) { 211 registerScope(Begin, End); 212 TryToEHPad[Begin] = EHPad; 213 EHPadToTry[EHPad] = Begin; 214 } 215 216 void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) { 217 assert(BeginToEnd.count(Begin)); 218 MachineInstr *End = BeginToEnd[Begin]; 219 assert(EndToBegin.count(End)); 220 BeginToEnd.erase(Begin); 221 EndToBegin.erase(End); 222 MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin); 223 if (EHPad) { 224 assert(EHPadToTry.count(EHPad)); 225 TryToEHPad.erase(Begin); 226 EHPadToTry.erase(EHPad); 227 } 228 } 229 230 /// Insert a BLOCK marker for branches to MBB (if needed). 231 // TODO Consider a more generalized way of handling block (and also loop and 232 // try) signatures when we implement the multi-value proposal later. 233 void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) { 234 assert(!MBB.isEHPad()); 235 MachineFunction &MF = *MBB.getParent(); 236 auto &MDT = getAnalysis<MachineDominatorTree>(); 237 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 238 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 239 240 // First compute the nearest common dominator of all forward non-fallthrough 241 // predecessors so that we minimize the time that the BLOCK is on the stack, 242 // which reduces overall stack height. 243 MachineBasicBlock *Header = nullptr; 244 bool IsBranchedTo = false; 245 bool IsBrOnExn = false; 246 MachineInstr *BrOnExn = nullptr; 247 int MBBNumber = MBB.getNumber(); 248 for (MachineBasicBlock *Pred : MBB.predecessors()) { 249 if (Pred->getNumber() < MBBNumber) { 250 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 251 if (explicitlyBranchesTo(Pred, &MBB)) { 252 IsBranchedTo = true; 253 if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) { 254 IsBrOnExn = true; 255 assert(!BrOnExn && "There should be only one br_on_exn per block"); 256 BrOnExn = &*Pred->getFirstTerminator(); 257 } 258 } 259 } 260 } 261 if (!Header) 262 return; 263 if (!IsBranchedTo) 264 return; 265 266 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors"); 267 MachineBasicBlock *LayoutPred = MBB.getPrevNode(); 268 269 // If the nearest common dominator is inside a more deeply nested context, 270 // walk out to the nearest scope which isn't more deeply nested. 271 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 272 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 273 if (ScopeTop->getNumber() > Header->getNumber()) { 274 // Skip over an intervening scope. 275 I = std::next(ScopeTop->getIterator()); 276 } else { 277 // We found a scope level at an appropriate depth. 278 Header = ScopeTop; 279 break; 280 } 281 } 282 } 283 284 // Decide where in Header to put the BLOCK. 285 286 // Instructions that should go before the BLOCK. 287 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 288 // Instructions that should go after the BLOCK. 289 SmallPtrSet<const MachineInstr *, 4> AfterSet; 290 for (const auto &MI : *Header) { 291 // If there is a previously placed LOOP marker and the bottom block of the 292 // loop is above MBB, it should be after the BLOCK, because the loop is 293 // nested in this BLOCK. Otherwise it should be before the BLOCK. 294 if (MI.getOpcode() == WebAssembly::LOOP) { 295 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 296 if (MBB.getNumber() > LoopBottom->getNumber()) 297 AfterSet.insert(&MI); 298 #ifndef NDEBUG 299 else 300 BeforeSet.insert(&MI); 301 #endif 302 } 303 304 // If there is a previously placed BLOCK/TRY marker and its corresponding 305 // END marker is before the current BLOCK's END marker, that should be 306 // placed after this BLOCK. Otherwise it should be placed before this BLOCK 307 // marker. 308 if (MI.getOpcode() == WebAssembly::BLOCK || 309 MI.getOpcode() == WebAssembly::TRY) { 310 if (BeginToEnd[&MI]->getParent()->getNumber() <= MBB.getNumber()) 311 AfterSet.insert(&MI); 312 #ifndef NDEBUG 313 else 314 BeforeSet.insert(&MI); 315 #endif 316 } 317 318 #ifndef NDEBUG 319 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK. 320 if (MI.getOpcode() == WebAssembly::END_BLOCK || 321 MI.getOpcode() == WebAssembly::END_LOOP || 322 MI.getOpcode() == WebAssembly::END_TRY) 323 BeforeSet.insert(&MI); 324 #endif 325 326 // Terminators should go after the BLOCK. 327 if (MI.isTerminator()) 328 AfterSet.insert(&MI); 329 } 330 331 // Local expression tree should go after the BLOCK. 332 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E; 333 --I) { 334 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 335 continue; 336 if (WebAssembly::isChild(*std::prev(I), MFI)) 337 AfterSet.insert(&*std::prev(I)); 338 else 339 break; 340 } 341 342 // Add the BLOCK. 343 344 // 'br_on_exn' extracts exnref object and pushes variable number of values 345 // depending on its tag. For C++ exception, its a single i32 value, and the 346 // generated code will be in the form of: 347 // block i32 348 // br_on_exn 0, $__cpp_exception 349 // rethrow 350 // end_block 351 WebAssembly::BlockType ReturnType = WebAssembly::BlockType::Void; 352 if (IsBrOnExn) { 353 const char *TagName = BrOnExn->getOperand(1).getSymbolName(); 354 if (std::strcmp(TagName, "__cpp_exception") != 0) 355 llvm_unreachable("Only C++ exception is supported"); 356 ReturnType = WebAssembly::BlockType::I32; 357 } 358 359 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 360 MachineInstr *Begin = 361 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 362 TII.get(WebAssembly::BLOCK)) 363 .addImm(int64_t(ReturnType)); 364 365 // Decide where in Header to put the END_BLOCK. 366 BeforeSet.clear(); 367 AfterSet.clear(); 368 for (auto &MI : MBB) { 369 #ifndef NDEBUG 370 // END_BLOCK should precede existing LOOP and TRY markers. 371 if (MI.getOpcode() == WebAssembly::LOOP || 372 MI.getOpcode() == WebAssembly::TRY) 373 AfterSet.insert(&MI); 374 #endif 375 376 // If there is a previously placed END_LOOP marker and the header of the 377 // loop is above this block's header, the END_LOOP should be placed after 378 // the BLOCK, because the loop contains this block. Otherwise the END_LOOP 379 // should be placed before the BLOCK. The same for END_TRY. 380 if (MI.getOpcode() == WebAssembly::END_LOOP || 381 MI.getOpcode() == WebAssembly::END_TRY) { 382 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber()) 383 BeforeSet.insert(&MI); 384 #ifndef NDEBUG 385 else 386 AfterSet.insert(&MI); 387 #endif 388 } 389 } 390 391 // Mark the end of the block. 392 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 393 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos), 394 TII.get(WebAssembly::END_BLOCK)); 395 registerScope(Begin, End); 396 397 // Track the farthest-spanning scope that ends at this point. 398 int Number = MBB.getNumber(); 399 if (!ScopeTops[Number] || 400 ScopeTops[Number]->getNumber() > Header->getNumber()) 401 ScopeTops[Number] = Header; 402 } 403 404 /// Insert a LOOP marker for a loop starting at MBB (if it's a loop header). 405 void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) { 406 MachineFunction &MF = *MBB.getParent(); 407 const auto &MLI = getAnalysis<MachineLoopInfo>(); 408 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 409 SortRegionInfo SRI(MLI, WEI); 410 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 411 412 MachineLoop *Loop = MLI.getLoopFor(&MBB); 413 if (!Loop || Loop->getHeader() != &MBB) 414 return; 415 416 // The operand of a LOOP is the first block after the loop. If the loop is the 417 // bottom of the function, insert a dummy block at the end. 418 MachineBasicBlock *Bottom = SRI.getBottom(Loop); 419 auto Iter = std::next(Bottom->getIterator()); 420 if (Iter == MF.end()) { 421 getAppendixBlock(MF); 422 Iter = std::next(Bottom->getIterator()); 423 } 424 MachineBasicBlock *AfterLoop = &*Iter; 425 426 // Decide where in Header to put the LOOP. 427 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 428 SmallPtrSet<const MachineInstr *, 4> AfterSet; 429 for (const auto &MI : MBB) { 430 // LOOP marker should be after any existing loop that ends here. Otherwise 431 // we assume the instruction belongs to the loop. 432 if (MI.getOpcode() == WebAssembly::END_LOOP) 433 BeforeSet.insert(&MI); 434 #ifndef NDEBUG 435 else 436 AfterSet.insert(&MI); 437 #endif 438 } 439 440 // Mark the beginning of the loop. 441 auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet); 442 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos), 443 TII.get(WebAssembly::LOOP)) 444 .addImm(int64_t(WebAssembly::BlockType::Void)); 445 446 // Decide where in Header to put the END_LOOP. 447 BeforeSet.clear(); 448 AfterSet.clear(); 449 #ifndef NDEBUG 450 for (const auto &MI : MBB) 451 // Existing END_LOOP markers belong to parent loops of this loop 452 if (MI.getOpcode() == WebAssembly::END_LOOP) 453 AfterSet.insert(&MI); 454 #endif 455 456 // Mark the end of the loop (using arbitrary debug location that branched to 457 // the loop end as its location). 458 InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet); 459 DebugLoc EndDL = AfterLoop->pred_empty() 460 ? DebugLoc() 461 : (*AfterLoop->pred_rbegin())->findBranchDebugLoc(); 462 MachineInstr *End = 463 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP)); 464 registerScope(Begin, End); 465 466 assert((!ScopeTops[AfterLoop->getNumber()] || 467 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) && 468 "With block sorting the outermost loop for a block should be first."); 469 if (!ScopeTops[AfterLoop->getNumber()]) 470 ScopeTops[AfterLoop->getNumber()] = &MBB; 471 } 472 473 void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) { 474 assert(MBB.isEHPad()); 475 MachineFunction &MF = *MBB.getParent(); 476 auto &MDT = getAnalysis<MachineDominatorTree>(); 477 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 478 const auto &MLI = getAnalysis<MachineLoopInfo>(); 479 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>(); 480 SortRegionInfo SRI(MLI, WEI); 481 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 482 483 // Compute the nearest common dominator of all unwind predecessors 484 MachineBasicBlock *Header = nullptr; 485 int MBBNumber = MBB.getNumber(); 486 for (auto *Pred : MBB.predecessors()) { 487 if (Pred->getNumber() < MBBNumber) { 488 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred; 489 assert(!explicitlyBranchesTo(Pred, &MBB) && 490 "Explicit branch to an EH pad!"); 491 } 492 } 493 if (!Header) 494 return; 495 496 // If this try is at the bottom of the function, insert a dummy block at the 497 // end. 498 WebAssemblyException *WE = WEI.getExceptionFor(&MBB); 499 assert(WE); 500 MachineBasicBlock *Bottom = SRI.getBottom(WE); 501 502 auto Iter = std::next(Bottom->getIterator()); 503 if (Iter == MF.end()) { 504 getAppendixBlock(MF); 505 Iter = std::next(Bottom->getIterator()); 506 } 507 MachineBasicBlock *Cont = &*Iter; 508 509 assert(Cont != &MF.front()); 510 MachineBasicBlock *LayoutPred = Cont->getPrevNode(); 511 512 // If the nearest common dominator is inside a more deeply nested context, 513 // walk out to the nearest scope which isn't more deeply nested. 514 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) { 515 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) { 516 if (ScopeTop->getNumber() > Header->getNumber()) { 517 // Skip over an intervening scope. 518 I = std::next(ScopeTop->getIterator()); 519 } else { 520 // We found a scope level at an appropriate depth. 521 Header = ScopeTop; 522 break; 523 } 524 } 525 } 526 527 // Decide where in Header to put the TRY. 528 529 // Instructions that should go before the TRY. 530 SmallPtrSet<const MachineInstr *, 4> BeforeSet; 531 // Instructions that should go after the TRY. 532 SmallPtrSet<const MachineInstr *, 4> AfterSet; 533 for (const auto &MI : *Header) { 534 // If there is a previously placed LOOP marker and the bottom block of the 535 // loop is above MBB, it should be after the TRY, because the loop is nested 536 // in this TRY. Otherwise it should be before the TRY. 537 if (MI.getOpcode() == WebAssembly::LOOP) { 538 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode(); 539 if (MBB.getNumber() > LoopBottom->getNumber()) 540 AfterSet.insert(&MI); 541 #ifndef NDEBUG 542 else 543 BeforeSet.insert(&MI); 544 #endif 545 } 546 547 // All previously inserted BLOCK/TRY markers should be after the TRY because 548 // they are all nested trys. 549 if (MI.getOpcode() == WebAssembly::BLOCK || 550 MI.getOpcode() == WebAssembly::TRY) 551 AfterSet.insert(&MI); 552 553 #ifndef NDEBUG 554 // All END_(BLOCK/LOOP/TRY) markers should be before the TRY. 555 if (MI.getOpcode() == WebAssembly::END_BLOCK || 556 MI.getOpcode() == WebAssembly::END_LOOP || 557 MI.getOpcode() == WebAssembly::END_TRY) 558 BeforeSet.insert(&MI); 559 #endif 560 561 // Terminators should go after the TRY. 562 if (MI.isTerminator()) 563 AfterSet.insert(&MI); 564 } 565 566 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should 567 // contain the call within it. So the call should go after the TRY. The 568 // exception is when the header's terminator is a rethrow instruction, in 569 // which case that instruction, not a call instruction before it, is gonna 570 // throw. 571 MachineInstr *ThrowingCall = nullptr; 572 if (MBB.isPredecessor(Header)) { 573 auto TermPos = Header->getFirstTerminator(); 574 if (TermPos == Header->end() || 575 TermPos->getOpcode() != WebAssembly::RETHROW) { 576 for (auto &MI : reverse(*Header)) { 577 if (MI.isCall()) { 578 AfterSet.insert(&MI); 579 ThrowingCall = &MI; 580 // Possibly throwing calls are usually wrapped by EH_LABEL 581 // instructions. We don't want to split them and the call. 582 if (MI.getIterator() != Header->begin() && 583 std::prev(MI.getIterator())->isEHLabel()) { 584 AfterSet.insert(&*std::prev(MI.getIterator())); 585 ThrowingCall = &*std::prev(MI.getIterator()); 586 } 587 break; 588 } 589 } 590 } 591 } 592 593 // Local expression tree should go after the TRY. 594 // For BLOCK placement, we start the search from the previous instruction of a 595 // BB's terminator, but in TRY's case, we should start from the previous 596 // instruction of a call that can throw, or a EH_LABEL that precedes the call, 597 // because the return values of the call's previous instructions can be 598 // stackified and consumed by the throwing call. 599 auto SearchStartPt = ThrowingCall ? MachineBasicBlock::iterator(ThrowingCall) 600 : Header->getFirstTerminator(); 601 for (auto I = SearchStartPt, E = Header->begin(); I != E; --I) { 602 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition()) 603 continue; 604 if (WebAssembly::isChild(*std::prev(I), MFI)) 605 AfterSet.insert(&*std::prev(I)); 606 else 607 break; 608 } 609 610 // Add the TRY. 611 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet); 612 MachineInstr *Begin = 613 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos), 614 TII.get(WebAssembly::TRY)) 615 .addImm(int64_t(WebAssembly::BlockType::Void)); 616 617 // Decide where in Header to put the END_TRY. 618 BeforeSet.clear(); 619 AfterSet.clear(); 620 for (const auto &MI : *Cont) { 621 #ifndef NDEBUG 622 // END_TRY should precede existing LOOP and BLOCK markers. 623 if (MI.getOpcode() == WebAssembly::LOOP || 624 MI.getOpcode() == WebAssembly::BLOCK) 625 AfterSet.insert(&MI); 626 627 // All END_TRY markers placed earlier belong to exceptions that contains 628 // this one. 629 if (MI.getOpcode() == WebAssembly::END_TRY) 630 AfterSet.insert(&MI); 631 #endif 632 633 // If there is a previously placed END_LOOP marker and its header is after 634 // where TRY marker is, this loop is contained within the 'catch' part, so 635 // the END_TRY marker should go after that. Otherwise, the whole try-catch 636 // is contained within this loop, so the END_TRY should go before that. 637 if (MI.getOpcode() == WebAssembly::END_LOOP) { 638 // For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they 639 // are in the same BB, LOOP is always before TRY. 640 if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber()) 641 BeforeSet.insert(&MI); 642 #ifndef NDEBUG 643 else 644 AfterSet.insert(&MI); 645 #endif 646 } 647 648 // It is not possible for an END_BLOCK to be already in this block. 649 } 650 651 // Mark the end of the TRY. 652 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet); 653 MachineInstr *End = 654 BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(), 655 TII.get(WebAssembly::END_TRY)); 656 registerTryScope(Begin, End, &MBB); 657 658 // Track the farthest-spanning scope that ends at this point. We create two 659 // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB 660 // with 'try'). We need to create 'catch' -> 'try' mapping here too because 661 // markers should not span across 'catch'. For example, this should not 662 // happen: 663 // 664 // try 665 // block --| (X) 666 // catch | 667 // end_block --| 668 // end_try 669 for (int Number : {Cont->getNumber(), MBB.getNumber()}) { 670 if (!ScopeTops[Number] || 671 ScopeTops[Number]->getNumber() > Header->getNumber()) 672 ScopeTops[Number] = Header; 673 } 674 } 675 676 void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) { 677 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 678 679 // When there is an unconditional branch right before a catch instruction and 680 // it branches to the end of end_try marker, we don't need the branch, because 681 // it there is no exception, the control flow transfers to that point anyway. 682 // bb0: 683 // try 684 // ... 685 // br bb2 <- Not necessary 686 // bb1: 687 // catch 688 // ... 689 // bb2: 690 // end 691 for (auto &MBB : MF) { 692 if (!MBB.isEHPad()) 693 continue; 694 695 MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 696 SmallVector<MachineOperand, 4> Cond; 697 MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode(); 698 MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent(); 699 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond); 700 // This condition means either 701 // 1. This BB ends with a single unconditional branch whose destinaion is 702 // Cont. 703 // 2. This BB ends with a conditional branch followed by an unconditional 704 // branch, and the unconditional branch's destination is Cont. 705 // In both cases, we want to remove the last (= unconditional) branch. 706 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) || 707 (!Cond.empty() && FBB && FBB == Cont))) { 708 bool ErasedUncondBr = false; 709 (void)ErasedUncondBr; 710 for (auto I = EHPadLayoutPred->end(), E = EHPadLayoutPred->begin(); 711 I != E; --I) { 712 auto PrevI = std::prev(I); 713 if (PrevI->isTerminator()) { 714 assert(PrevI->getOpcode() == WebAssembly::BR); 715 PrevI->eraseFromParent(); 716 ErasedUncondBr = true; 717 break; 718 } 719 } 720 assert(ErasedUncondBr && "Unconditional branch not erased!"); 721 } 722 } 723 724 // When there are block / end_block markers that overlap with try / end_try 725 // markers, and the block and try markers' return types are the same, the 726 // block /end_block markers are not necessary, because try / end_try markers 727 // also can serve as boundaries for branches. 728 // block <- Not necessary 729 // try 730 // ... 731 // catch 732 // ... 733 // end 734 // end <- Not necessary 735 SmallVector<MachineInstr *, 32> ToDelete; 736 for (auto &MBB : MF) { 737 for (auto &MI : MBB) { 738 if (MI.getOpcode() != WebAssembly::TRY) 739 continue; 740 741 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try]; 742 MachineBasicBlock *TryBB = Try->getParent(); 743 MachineBasicBlock *Cont = EndTry->getParent(); 744 int64_t RetType = Try->getOperand(0).getImm(); 745 for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator()); 746 B != TryBB->begin() && E != Cont->end() && 747 std::prev(B)->getOpcode() == WebAssembly::BLOCK && 748 E->getOpcode() == WebAssembly::END_BLOCK && 749 std::prev(B)->getOperand(0).getImm() == RetType; 750 --B, ++E) { 751 ToDelete.push_back(&*std::prev(B)); 752 ToDelete.push_back(&*E); 753 } 754 } 755 } 756 for (auto *MI : ToDelete) { 757 if (MI->getOpcode() == WebAssembly::BLOCK) 758 unregisterScope(MI); 759 MI->eraseFromParent(); 760 } 761 } 762 763 // Get the appropriate copy opcode for the given register class. 764 static unsigned getCopyOpcode(const TargetRegisterClass *RC) { 765 if (RC == &WebAssembly::I32RegClass) 766 return WebAssembly::COPY_I32; 767 if (RC == &WebAssembly::I64RegClass) 768 return WebAssembly::COPY_I64; 769 if (RC == &WebAssembly::F32RegClass) 770 return WebAssembly::COPY_F32; 771 if (RC == &WebAssembly::F64RegClass) 772 return WebAssembly::COPY_F64; 773 if (RC == &WebAssembly::V128RegClass) 774 return WebAssembly::COPY_V128; 775 if (RC == &WebAssembly::FUNCREFRegClass) 776 return WebAssembly::COPY_FUNCREF; 777 if (RC == &WebAssembly::EXTERNREFRegClass) 778 return WebAssembly::COPY_EXTERNREF; 779 if (RC == &WebAssembly::EXNREFRegClass) 780 return WebAssembly::COPY_EXNREF; 781 llvm_unreachable("Unexpected register class"); 782 } 783 784 // When MBB is split into MBB and Split, we should unstackify defs in MBB that 785 // have their uses in Split. 786 // FIXME This function will be used when fixing unwind mismatches, but the old 787 // version of that function was removed for the moment and the new version has 788 // not yet been added. So 'LLVM_ATTRIBUTE_UNUSED' is added to suppress the 789 // warning. Remove the attribute after the new functionality is added. 790 LLVM_ATTRIBUTE_UNUSED static void 791 unstackifyVRegsUsedInSplitBB(MachineBasicBlock &MBB, MachineBasicBlock &Split, 792 WebAssemblyFunctionInfo &MFI, 793 MachineRegisterInfo &MRI, 794 const WebAssemblyInstrInfo &TII) { 795 for (auto &MI : Split) { 796 for (auto &MO : MI.explicit_uses()) { 797 if (!MO.isReg() || Register::isPhysicalRegister(MO.getReg())) 798 continue; 799 if (MachineInstr *Def = MRI.getUniqueVRegDef(MO.getReg())) 800 if (Def->getParent() == &MBB) 801 MFI.unstackifyVReg(MO.getReg()); 802 } 803 } 804 805 // In RegStackify, when a register definition is used multiple times, 806 // Reg = INST ... 807 // INST ..., Reg, ... 808 // INST ..., Reg, ... 809 // INST ..., Reg, ... 810 // 811 // we introduce a TEE, which has the following form: 812 // DefReg = INST ... 813 // TeeReg, Reg = TEE_... DefReg 814 // INST ..., TeeReg, ... 815 // INST ..., Reg, ... 816 // INST ..., Reg, ... 817 // with DefReg and TeeReg stackified but Reg not stackified. 818 // 819 // But the invariant that TeeReg should be stackified can be violated while we 820 // unstackify registers in the split BB above. In this case, we convert TEEs 821 // into two COPYs. This COPY will be eventually eliminated in ExplicitLocals. 822 // DefReg = INST ... 823 // TeeReg = COPY DefReg 824 // Reg = COPY DefReg 825 // INST ..., TeeReg, ... 826 // INST ..., Reg, ... 827 // INST ..., Reg, ... 828 for (auto I = MBB.begin(), E = MBB.end(); I != E;) { 829 MachineInstr &MI = *I++; 830 if (!WebAssembly::isTee(MI.getOpcode())) 831 continue; 832 Register TeeReg = MI.getOperand(0).getReg(); 833 Register Reg = MI.getOperand(1).getReg(); 834 Register DefReg = MI.getOperand(2).getReg(); 835 if (!MFI.isVRegStackified(TeeReg)) { 836 // Now we are not using TEE anymore, so unstackify DefReg too 837 MFI.unstackifyVReg(DefReg); 838 unsigned CopyOpc = getCopyOpcode(MRI.getRegClass(DefReg)); 839 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), TeeReg) 840 .addReg(DefReg); 841 BuildMI(MBB, &MI, MI.getDebugLoc(), TII.get(CopyOpc), Reg).addReg(DefReg); 842 MI.eraseFromParent(); 843 } 844 } 845 } 846 847 bool WebAssemblyCFGStackify::fixUnwindMismatches(MachineFunction &MF) { 848 // TODO Implement this 849 return false; 850 } 851 852 static unsigned 853 getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack, 854 const MachineBasicBlock *MBB) { 855 unsigned Depth = 0; 856 for (auto X : reverse(Stack)) { 857 if (X == MBB) 858 break; 859 ++Depth; 860 } 861 assert(Depth < Stack.size() && "Branch destination should be in scope"); 862 return Depth; 863 } 864 865 /// In normal assembly languages, when the end of a function is unreachable, 866 /// because the function ends in an infinite loop or a noreturn call or similar, 867 /// it isn't necessary to worry about the function return type at the end of 868 /// the function, because it's never reached. However, in WebAssembly, blocks 869 /// that end at the function end need to have a return type signature that 870 /// matches the function signature, even though it's unreachable. This function 871 /// checks for such cases and fixes up the signatures. 872 void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) { 873 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); 874 875 if (MFI.getResults().empty()) 876 return; 877 878 // MCInstLower will add the proper types to multivalue signatures based on the 879 // function return type 880 WebAssembly::BlockType RetType = 881 MFI.getResults().size() > 1 882 ? WebAssembly::BlockType::Multivalue 883 : WebAssembly::BlockType( 884 WebAssembly::toValType(MFI.getResults().front())); 885 886 SmallVector<MachineBasicBlock::reverse_iterator, 4> Worklist; 887 Worklist.push_back(MF.rbegin()->rbegin()); 888 889 auto Process = [&](MachineBasicBlock::reverse_iterator It) { 890 auto *MBB = It->getParent(); 891 while (It != MBB->rend()) { 892 MachineInstr &MI = *It++; 893 if (MI.isPosition() || MI.isDebugInstr()) 894 continue; 895 switch (MI.getOpcode()) { 896 case WebAssembly::END_TRY: { 897 // If a 'try''s return type is fixed, both its try body and catch body 898 // should satisfy the return type, so we need to search 'end' 899 // instructions before its corresponding 'catch' too. 900 auto *EHPad = TryToEHPad.lookup(EndToBegin[&MI]); 901 assert(EHPad); 902 Worklist.push_back(std::next(findCatch(EHPad)->getReverseIterator())); 903 LLVM_FALLTHROUGH; 904 } 905 case WebAssembly::END_BLOCK: 906 case WebAssembly::END_LOOP: 907 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType)); 908 continue; 909 default: 910 // Something other than an `end`. We're done for this BB. 911 return; 912 } 913 } 914 // We've reached the beginning of a BB. Continue the search in the previous 915 // BB. 916 Worklist.push_back(MBB->getPrevNode()->rbegin()); 917 }; 918 919 while (!Worklist.empty()) 920 Process(Worklist.pop_back_val()); 921 } 922 923 // WebAssembly functions end with an end instruction, as if the function body 924 // were a block. 925 static void appendEndToFunction(MachineFunction &MF, 926 const WebAssemblyInstrInfo &TII) { 927 BuildMI(MF.back(), MF.back().end(), 928 MF.back().findPrevDebugLoc(MF.back().end()), 929 TII.get(WebAssembly::END_FUNCTION)); 930 } 931 932 /// Insert LOOP/TRY/BLOCK markers at appropriate places. 933 void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) { 934 // We allocate one more than the number of blocks in the function to 935 // accommodate for the possible fake block we may insert at the end. 936 ScopeTops.resize(MF.getNumBlockIDs() + 1); 937 // Place the LOOP for MBB if MBB is the header of a loop. 938 for (auto &MBB : MF) 939 placeLoopMarker(MBB); 940 941 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 942 for (auto &MBB : MF) { 943 if (MBB.isEHPad()) { 944 // Place the TRY for MBB if MBB is the EH pad of an exception. 945 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 946 MF.getFunction().hasPersonalityFn()) 947 placeTryMarker(MBB); 948 } else { 949 // Place the BLOCK for MBB if MBB is branched to from above. 950 placeBlockMarker(MBB); 951 } 952 } 953 // Fix mismatches in unwind destinations induced by linearizing the code. 954 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 955 MF.getFunction().hasPersonalityFn()) 956 fixUnwindMismatches(MF); 957 } 958 959 void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) { 960 // Now rewrite references to basic blocks to be depth immediates. 961 SmallVector<const MachineBasicBlock *, 8> Stack; 962 for (auto &MBB : reverse(MF)) { 963 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) { 964 MachineInstr &MI = *I; 965 switch (MI.getOpcode()) { 966 case WebAssembly::BLOCK: 967 case WebAssembly::TRY: 968 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <= 969 MBB.getNumber() && 970 "Block/try marker should be balanced"); 971 Stack.pop_back(); 972 break; 973 974 case WebAssembly::LOOP: 975 assert(Stack.back() == &MBB && "Loop top should be balanced"); 976 Stack.pop_back(); 977 break; 978 979 case WebAssembly::END_BLOCK: 980 case WebAssembly::END_TRY: 981 Stack.push_back(&MBB); 982 break; 983 984 case WebAssembly::END_LOOP: 985 Stack.push_back(EndToBegin[&MI]->getParent()); 986 break; 987 988 default: 989 if (MI.isTerminator()) { 990 // Rewrite MBB operands to be depth immediates. 991 SmallVector<MachineOperand, 4> Ops(MI.operands()); 992 while (MI.getNumOperands() > 0) 993 MI.RemoveOperand(MI.getNumOperands() - 1); 994 for (auto MO : Ops) { 995 if (MO.isMBB()) 996 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB())); 997 MI.addOperand(MF, MO); 998 } 999 } 1000 break; 1001 } 1002 } 1003 } 1004 assert(Stack.empty() && "Control flow should be balanced"); 1005 } 1006 1007 void WebAssemblyCFGStackify::releaseMemory() { 1008 ScopeTops.clear(); 1009 BeginToEnd.clear(); 1010 EndToBegin.clear(); 1011 TryToEHPad.clear(); 1012 EHPadToTry.clear(); 1013 AppendixBB = nullptr; 1014 } 1015 1016 bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { 1017 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n" 1018 "********** Function: " 1019 << MF.getName() << '\n'); 1020 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo(); 1021 1022 releaseMemory(); 1023 1024 // Liveness is not tracked for VALUE_STACK physreg. 1025 MF.getRegInfo().invalidateLiveness(); 1026 1027 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes. 1028 placeMarkers(MF); 1029 1030 // Remove unnecessary instructions possibly introduced by try/end_trys. 1031 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm && 1032 MF.getFunction().hasPersonalityFn()) 1033 removeUnnecessaryInstrs(MF); 1034 1035 // Convert MBB operands in terminators to relative depth immediates. 1036 rewriteDepthImmediates(MF); 1037 1038 // Fix up block/loop/try signatures at the end of the function to conform to 1039 // WebAssembly's rules. 1040 fixEndsAtEndOfFunction(MF); 1041 1042 // Add an end instruction at the end of the function body. 1043 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); 1044 if (!MF.getSubtarget<WebAssemblySubtarget>() 1045 .getTargetTriple() 1046 .isOSBinFormatELF()) 1047 appendEndToFunction(MF, TII); 1048 1049 MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified(); 1050 return true; 1051 } 1052