| //===- MachineIDFSSAUpdater.cpp - Unstructured SSA Update Tool ------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the MachineIDFSSAUpdater class, which provides an | |
| // efficient SSA form maintenance utility for machine-level IR. It uses the | |
| // iterated dominance frontier (IDF) algorithm via MachineForwardIDFCalculator | |
| // to compute phi-function placement, offering better performance than the | |
| // incremental MachineSSAUpdater approach. The updater requires a single call | |
| // to calculate() after all definitions and uses have been registered. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/CodeGen/MachineIDFSSAUpdater.h" | |
| #include "llvm/ADT/DenseMap.h" | |
| #include "llvm/Analysis/IteratedDominanceFrontier.h" | |
| #include "llvm/CodeGen/MachineBasicBlock.h" | |
| #include "llvm/CodeGen/MachineDominators.h" | |
| #include "llvm/CodeGen/MachineFunction.h" | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/MachineOperand.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/TargetInstrInfo.h" | |
| #include "llvm/CodeGen/TargetOpcodes.h" | |
| #include "llvm/IR/DebugLoc.h" | |
| namespace llvm { | |
| template <bool IsPostDom> | |
| class MachineIDFCalculator final | |
| : public IDFCalculatorBase<MachineBasicBlock, IsPostDom> { | |
| public: | |
| using IDFCalculatorBase = | |
| typename llvm::IDFCalculatorBase<MachineBasicBlock, IsPostDom>; | |
| using ChildrenGetterTy = typename IDFCalculatorBase::ChildrenGetterTy; | |
| MachineIDFCalculator(DominatorTreeBase<MachineBasicBlock, IsPostDom> &DT) | |
| : IDFCalculatorBase(DT) {} | |
| }; | |
| using MachineForwardIDFCalculator = MachineIDFCalculator<false>; | |
| using MachineReverseIDFCalculator = MachineIDFCalculator<true>; | |
| } // namespace llvm | |
| using namespace llvm; | |
| /// Given sets of UsingBlocks and DefBlocks, compute the set of LiveInBlocks. | |
| /// This is basically a subgraph limited by DefBlocks and UsingBlocks. | |
| static void | |
| computeLiveInBlocks(const SmallPtrSetImpl<MachineBasicBlock *> &UsingBlocks, | |
| const SmallPtrSetImpl<MachineBasicBlock *> &DefBlocks, | |
| SmallPtrSetImpl<MachineBasicBlock *> &LiveInBlocks) { | |
| // To determine liveness, we must iterate through the predecessors of blocks | |
| // where the def is live. Blocks are added to the worklist if we need to | |
| // check their predecessors. Start with all the using blocks. | |
| SmallVector<MachineBasicBlock *, 64> LiveInBlockWorklist(UsingBlocks.begin(), | |
| UsingBlocks.end()); | |
| // Now that we have a set of blocks where the phi is live-in, recursively add | |
| // their predecessors until we find the full region the value is live. | |
| while (!LiveInBlockWorklist.empty()) { | |
| MachineBasicBlock *BB = LiveInBlockWorklist.pop_back_val(); | |
| // The block really is live in here, insert it into the set. If already in | |
| // the set, then it has already been processed. | |
| if (!LiveInBlocks.insert(BB).second) | |
| continue; | |
| // Since the value is live into BB, it is either defined in a predecessor or | |
| // live into it to. Add the preds to the worklist unless they are a | |
| // defining block. | |
| for (MachineBasicBlock *P : BB->predecessors()) { | |
| // The value is not live into a predecessor if it defines the value. | |
| if (DefBlocks.count(P)) | |
| continue; | |
| // Otherwise it is, add to the worklist. | |
| LiveInBlockWorklist.push_back(P); | |
| } | |
| } | |
| } | |
| MachineInstrBuilder | |
| MachineIDFSSAUpdater::createInst(unsigned Opc, MachineBasicBlock *BB, | |
| MachineBasicBlock::iterator I) { | |
| return BuildMI(*BB, I, DebugLoc(), TII.get(Opc), | |
| MRI.createVirtualRegister(RegAttrs)); | |
| } | |
| // IsLiveOut indicates whether we are computing live-out values (true) or | |
| // live-in values (false). | |
| Register MachineIDFSSAUpdater::computeValue(MachineBasicBlock *BB, | |
| bool IsLiveOut) { | |
| BBValueInfo *BBInfo = &BBInfos[BB]; | |
| if (IsLiveOut && BBInfo->LiveOutValue) | |
| return BBInfo->LiveOutValue; | |
| if (BBInfo->LiveInValue) | |
| return BBInfo->LiveInValue; | |
| SmallVector<BBValueInfo *, 4> DomPath = {BBInfo}; | |
| MachineBasicBlock *DomBB = BB, *TopDomBB = BB; | |
| Register V; | |
| while (DT.isReachableFromEntry(DomBB) && !DomBB->pred_empty() && | |
| (DomBB = DT.getNode(DomBB)->getIDom()->getBlock())) { | |
| BBInfo = &BBInfos[DomBB]; | |
| if (BBInfo->LiveOutValue) { | |
| V = BBInfo->LiveOutValue; | |
| break; | |
| } | |
| if (BBInfo->LiveInValue) { | |
| V = BBInfo->LiveInValue; | |
| break; | |
| } | |
| TopDomBB = DomBB; | |
| DomPath.emplace_back(BBInfo); | |
| } | |
| if (!V) { | |
| V = createInst(TargetOpcode::IMPLICIT_DEF, TopDomBB, | |
| TopDomBB->getFirstNonPHI()) | |
| .getReg(0); | |
| } | |
| for (BBValueInfo *BBInfo : DomPath) { | |
| // Loop above can insert new entries into the BBInfos map: assume the | |
| // map shouldn't grow as the caller should have been allocated enough | |
| // buckets, see [1]. | |
| BBInfo->LiveInValue = V; | |
| } | |
| return V; | |
| } | |
| /// Perform all the necessary updates, including new PHI-nodes insertion and the | |
| /// requested uses update. | |
| void MachineIDFSSAUpdater::calculate() { | |
| MachineForwardIDFCalculator IDF(DT); | |
| SmallPtrSet<MachineBasicBlock *, 2> DefBlocks; | |
| for (auto [BB, V] : Defines) | |
| DefBlocks.insert(BB); | |
| IDF.setDefiningBlocks(DefBlocks); | |
| SmallPtrSet<MachineBasicBlock *, 2> UsingBlocks(UseBlocks.begin(), | |
| UseBlocks.end()); | |
| SmallVector<MachineBasicBlock *, 4> IDFBlocks; | |
| SmallPtrSet<MachineBasicBlock *, 4> LiveInBlocks; | |
| computeLiveInBlocks(UsingBlocks, DefBlocks, LiveInBlocks); | |
| IDF.setLiveInBlocks(LiveInBlocks); | |
| IDF.calculate(IDFBlocks); | |
| // Reserve sufficient buckets to prevent map growth. [1] | |
| BBInfos.reserve(LiveInBlocks.size() + DefBlocks.size()); | |
| for (auto [BB, V] : Defines) | |
| BBInfos[BB].LiveOutValue = V; | |
| for (MachineBasicBlock *FrontierBB : IDFBlocks) { | |
| Register NewVR = | |
| createInst(TargetOpcode::PHI, FrontierBB, FrontierBB->begin()) | |
| .getReg(0); | |
| BBInfos[FrontierBB].LiveInValue = NewVR; | |
| } | |
| for (MachineBasicBlock *BB : IDFBlocks) { | |
| auto *PHI = &BB->front(); | |
| assert(PHI->isPHI()); | |
| MachineInstrBuilder MIB(*BB->getParent(), PHI); | |
| for (MachineBasicBlock *Pred : BB->predecessors()) | |
| MIB.addReg(computeValue(Pred, /*IsLiveOut=*/true)).addMBB(Pred); | |
| } | |
| } | |
| Register MachineIDFSSAUpdater::getValueInMiddleOfBlock(MachineBasicBlock *BB) { | |
| return computeValue(BB, /*IsLiveOut=*/false); | |
| } |