From b8812a1c15dad4efcba6c05f2d4dc8c37174b55d Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Wed, 8 Dec 2010 03:26:16 +0000 Subject: [PATCH] Stub out RegAllocGreedy. This new register allocator is initially identical to RegAllocBasic, but it will receive all of the tricks that RegAllocBasic won't get. RegAllocGreedy will eventually replace linear scan. llvm-svn: 121234 --- .../llvm/CodeGen/LinkAllCodegenComponents.h | 1 + llvm/include/llvm/CodeGen/Passes.h | 5 + llvm/lib/CodeGen/CMakeLists.txt | 1 + llvm/lib/CodeGen/RegAllocGreedy.cpp | 214 ++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 llvm/lib/CodeGen/RegAllocGreedy.cpp diff --git a/llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h b/llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h index bc06d43b8fc5..c931261f6332 100644 --- a/llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h +++ b/llvm/include/llvm/CodeGen/LinkAllCodegenComponents.h @@ -36,6 +36,7 @@ namespace { (void) llvm::createFastRegisterAllocator(); (void) llvm::createBasicRegisterAllocator(); (void) llvm::createLinearScanRegisterAllocator(); + (void) llvm::createGreedyRegisterAllocator(); (void) llvm::createDefaultPBQPRegisterAllocator(); (void) llvm::createSimpleRegisterCoalescer(); diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h index 30dbc4047598..4d9d293bdd6d 100644 --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -103,6 +103,11 @@ namespace llvm { /// FunctionPass *createBasicRegisterAllocator(); + /// Greedy register allocation pass - This pass implements a global register + /// allocator for optimized builds. + /// + FunctionPass *createGreedyRegisterAllocator(); + /// LinearScanRegisterAllocation Pass - This pass implements the linear scan /// register allocation algorithm, a global register allocator. /// diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt index 2f6d60ff5e8b..b5c1ff7f563a 100644 --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -61,6 +61,7 @@ add_llvm_library(LLVMCodeGen PseudoSourceValue.cpp RegAllocBasic.cpp RegAllocFast.cpp + RegAllocGreedy.cpp RegAllocLinearScan.cpp RegAllocPBQP.cpp RegisterCoalescer.cpp diff --git a/llvm/lib/CodeGen/RegAllocGreedy.cpp b/llvm/lib/CodeGen/RegAllocGreedy.cpp new file mode 100644 index 000000000000..d9d8c30e3947 --- /dev/null +++ b/llvm/lib/CodeGen/RegAllocGreedy.cpp @@ -0,0 +1,214 @@ +//===-- RegAllocGreedy.cpp - greedy register allocator --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the RAGreedy function pass for register allocation in +// optimized builds. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "regalloc" +#include "LiveIntervalUnion.h" +#include "RegAllocBase.h" +#include "Spiller.h" +#include "VirtRegMap.h" +#include "VirtRegRewriter.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Function.h" +#include "llvm/PassAnalysisSupport.h" +#include "llvm/CodeGen/CalcSpillWeights.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveStackAnalysis.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/RegisterCoalescer.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static RegisterRegAlloc greedyRegAlloc("greedy", "greedy register allocator", + createGreedyRegisterAllocator); + +namespace { +class RAGreedy : public MachineFunctionPass, public RegAllocBase { + // context + MachineFunction *MF; + const TargetMachine *TM; + MachineRegisterInfo *MRI; + + BitVector ReservedRegs; + + // analyses + LiveStacks *LS; + + // state + std::auto_ptr SpillerInstance; + +public: + RAGreedy(); + + /// Return the pass name. + virtual const char* getPassName() const { + return "Basic Register Allocator"; + } + + /// RAGreedy analysis usage. + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + + virtual void releaseMemory(); + + virtual Spiller &spiller() { return *SpillerInstance; } + + virtual unsigned selectOrSplit(LiveInterval &VirtReg, + SmallVectorImpl &SplitVRegs); + + /// Perform register allocation. + virtual bool runOnMachineFunction(MachineFunction &mf); + + static char ID; +}; +} // end anonymous namespace + +char RAGreedy::ID = 0; + +FunctionPass* llvm::createGreedyRegisterAllocator() { + return new RAGreedy(); +} + +RAGreedy::RAGreedy(): MachineFunctionPass(ID) { + initializeLiveIntervalsPass(*PassRegistry::getPassRegistry()); + initializeSlotIndexesPass(*PassRegistry::getPassRegistry()); + initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry()); + initializeRegisterCoalescerAnalysisGroup(*PassRegistry::getPassRegistry()); + initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry()); + initializeLiveStacksPass(*PassRegistry::getPassRegistry()); + initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry()); + initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry()); + initializeVirtRegMapPass(*PassRegistry::getPassRegistry()); +} + +void RAGreedy::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + if (StrongPHIElim) + AU.addRequiredID(StrongPHIEliminationID); + AU.addRequiredTransitive(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequiredID(MachineDominatorsID); + AU.addPreservedID(MachineDominatorsID); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + MachineFunctionPass::getAnalysisUsage(AU); +} + +void RAGreedy::releaseMemory() { + SpillerInstance.reset(0); + RegAllocBase::releaseMemory(); +} + +unsigned RAGreedy::selectOrSplit(LiveInterval &VirtReg, + SmallVectorImpl &SplitVRegs) { + // Populate a list of physical register spill candidates. + SmallVector PhysRegSpillCands; + + // Check for an available register in this class. + const TargetRegisterClass *TRC = MRI->getRegClass(VirtReg.reg); + DEBUG(dbgs() << "RegClass: " << TRC->getName() << ' '); + + for (TargetRegisterClass::iterator I = TRC->allocation_order_begin(*MF), + E = TRC->allocation_order_end(*MF); + I != E; ++I) { + + unsigned PhysReg = *I; + if (ReservedRegs.test(PhysReg)) continue; + + // Check interference and as a side effect, intialize queries for this + // VirtReg and its aliases. + unsigned interfReg = checkPhysRegInterference(VirtReg, PhysReg); + if (interfReg == 0) { + // Found an available register. + return PhysReg; + } + LiveInterval *interferingVirtReg = + Queries[interfReg].firstInterference().liveUnionPos().value(); + + // The current VirtReg must either spillable, or one of its interferences + // must have less spill weight. + if (interferingVirtReg->weight < VirtReg.weight ) { + PhysRegSpillCands.push_back(PhysReg); + } + } + // Try to spill another interfering reg with less spill weight. + // + // FIXME: RAGreedy will sort this list by spill weight. + for (SmallVectorImpl::iterator PhysRegI = PhysRegSpillCands.begin(), + PhysRegE = PhysRegSpillCands.end(); PhysRegI != PhysRegE; ++PhysRegI) { + + if (!spillInterferences(VirtReg, *PhysRegI, SplitVRegs)) continue; + + assert(checkPhysRegInterference(VirtReg, *PhysRegI) == 0 && + "Interference after spill."); + // Tell the caller to allocate to this newly freed physical register. + return *PhysRegI; + } + // No other spill candidates were found, so spill the current VirtReg. + DEBUG(dbgs() << "spilling: " << VirtReg << '\n'); + SmallVector pendingSpills; + + spiller().spill(&VirtReg, SplitVRegs, pendingSpills); + + // The live virtual register requesting allocation was spilled, so tell + // the caller not to allocate anything during this round. + return 0; +} + +bool RAGreedy::runOnMachineFunction(MachineFunction &mf) { + DEBUG(dbgs() << "********** GREEDY REGISTER ALLOCATION **********\n" + << "********** Function: " + << ((Value*)mf.getFunction())->getName() << '\n'); + + MF = &mf; + TM = &mf.getTarget(); + MRI = &mf.getRegInfo(); + + const TargetRegisterInfo *TRI = TM->getRegisterInfo(); + RegAllocBase::init(*TRI, getAnalysis(), + getAnalysis()); + + ReservedRegs = TRI->getReservedRegs(*MF); + SpillerInstance.reset(createSpiller(*this, *MF, *VRM)); + allocatePhysRegs(); + addMBBLiveIns(MF); + + // Run rewriter + std::auto_ptr rewriter(createVirtRegRewriter()); + rewriter->runOnMachineFunction(*MF, *VRM, LIS); + + // The pass output is in VirtRegMap. Release all the transient data. + releaseMemory(); + + return true; +} +