//===- 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 class MachineIDFCalculator final : public IDFCalculatorBase { public: using IDFCalculatorBase = typename llvm::IDFCalculatorBase; using ChildrenGetterTy = typename IDFCalculatorBase::ChildrenGetterTy; MachineIDFCalculator(DominatorTreeBase &DT) : IDFCalculatorBase(DT) {} }; using MachineForwardIDFCalculator = MachineIDFCalculator; using MachineReverseIDFCalculator = MachineIDFCalculator; } // 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 &UsingBlocks, const SmallPtrSetImpl &DefBlocks, SmallPtrSetImpl &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 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 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 DefBlocks; for (auto [BB, V] : Defines) DefBlocks.insert(BB); IDF.setDefiningBlocks(DefBlocks); SmallPtrSet UsingBlocks(UseBlocks.begin(), UseBlocks.end()); SmallVector IDFBlocks; SmallPtrSet 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); }