| //===- 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" |
| #include "llvm/Support/Debug.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); |
| } |