From 2ca4b270dbb43aebe828f6defd9585a56c7beac6 Mon Sep 17 00:00:00 2001 From: David Greene Date: Thu, 6 Sep 2007 16:18:45 +0000 Subject: [PATCH] Pluggable coalescers inplementation. llvm-svn: 41743 --- .../llvm/CodeGen/LinkAllCodegenComponents.h | 2 + include/llvm/CodeGen/Passes.h | 6 + include/llvm/CodeGen/RegisterCoalescer.h | 159 ++++++++++++++++++ .../llvm/CodeGen/SimpleRegisterCoalescing.h | 9 +- lib/CodeGen/RegAllocLinearScan.cpp | 10 +- lib/CodeGen/RegisterCoalescer.cpp | 43 +++++ lib/CodeGen/SimpleRegisterCoalescing.cpp | 11 ++ 7 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 include/llvm/CodeGen/RegisterCoalescer.h create mode 100644 lib/CodeGen/RegisterCoalescer.cpp diff --git a/include/llvm/CodeGen/LinkAllCodegenComponents.h b/include/llvm/CodeGen/LinkAllCodegenComponents.h index 15021c1eb5d..c3cc906cb8d 100644 --- a/include/llvm/CodeGen/LinkAllCodegenComponents.h +++ b/include/llvm/CodeGen/LinkAllCodegenComponents.h @@ -32,6 +32,8 @@ namespace { (void) llvm::createLocalRegisterAllocator(); (void) llvm::createBigBlockRegisterAllocator(); (void) llvm::createLinearScanRegisterAllocator(); + + (void) llvm::createSimpleRegisterCoalescer(); (void) llvm::createBFS_DAGScheduler(NULL, NULL, NULL); (void) llvm::createSimpleDAGScheduler(NULL, NULL, NULL); diff --git a/include/llvm/CodeGen/Passes.h b/include/llvm/CodeGen/Passes.h index 45129829038..ed96b40a109 100644 --- a/include/llvm/CodeGen/Passes.h +++ b/include/llvm/CodeGen/Passes.h @@ -23,6 +23,7 @@ namespace llvm { class FunctionPass; class PassInfo; class TargetMachine; + class RegisterCoalescer; /// createUnreachableBlockEliminationPass - The LLVM code generator does not /// work well with unreachable basic blocks (what live ranges make sense for a @@ -84,6 +85,11 @@ namespace llvm { /// FunctionPass *createLinearScanRegisterAllocator(); + /// SimpleRegisterCoalescing Pass - Coalesce all copies possible. Can run + /// independently of the register allocator. + /// + RegisterCoalescer *createSimpleRegisterCoalescer(); + /// PrologEpilogCodeInserter Pass - This pass inserts prolog and epilog code, /// and eliminates abstract frame references. /// diff --git a/include/llvm/CodeGen/RegisterCoalescer.h b/include/llvm/CodeGen/RegisterCoalescer.h new file mode 100644 index 00000000000..e7727d54347 --- /dev/null +++ b/include/llvm/CodeGen/RegisterCoalescer.h @@ -0,0 +1,159 @@ +//===-- RegisterCoalescer.h - Register Coalescing Interface ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the abstract interface for register coalescers, +// allowing them to interact with and query register allocators. +// +//===----------------------------------------------------------------------===// + +#include "llvm/System/IncludeFile.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/LiveVariables.h" +#include "llvm/Target/MRegisterInfo.h" +#include "llvm/Support/Debug.h" + +#ifndef LLVM_CODEGEN_REGISTER_COALESCER_H +#define LLVM_CODEGEN_REGISTER_COALESCER_H + +namespace llvm +{ + class MachineFunction; + class RegallocQuery; + class AnalysisUsage; + class LiveIntervals; + class MachineInstr; + class MRegisterInfo; + + /// An abstract interface for register coalescers. Coalescers must + /// implement this interface to be part of the coalescer analysis + /// group. + class RegisterCoalescer { + public: + static char ID; // Class identification, replacement for typeinfo + RegisterCoalescer() {} + virtual ~RegisterCoalescer(); // We want to be subclassed + + /// Run the coalescer on this function, providing interference + /// data to query. Return whether we removed any copies. + virtual bool coalesceFunction(MachineFunction &mf, + RegallocQuery &ifd) = 0; + + /// Reset state. Can be used to allow a coalescer run by + /// PassManager to be run again by the register allocator. + virtual void reset(MachineFunction &mf) {}; + + /// Register allocators must call this from their own + /// getAnalysisUsage to cover the case where the coalescer is not + /// a Pass in the proper sense and isn't managed by PassManager. + /// PassManager needs to know which analyses to make available and + /// which to invalidate when running the register allocator or any + /// pass that might call coalescing. The long-term solution is to + /// allow hierarchies of PassManagers. + virtual void getAnalysisUsage(AnalysisUsage &AU) const {}; + }; + + /// An abstract interface for register allocators to interact with + /// coalescers + /// + /// Example: + /// + /// This is simply an example of how to use the RegallocQuery + /// interface. It is not meant to be used in production. + /// + /// class LinearScanRegallocQuery : public RegallocQuery { + /// private: + /// const LiveIntervals &li; + /// + /// public: + /// LinearScanRegallocQuery(LiveIntervals &intervals) + /// : li(intervals) {}; + /// + /// /// This is pretty slow and conservative, but since linear scan + /// /// allocation doesn't pre-compute interference information it's + /// /// the best we can do. Coalescers are always free to ignore this + /// /// and implement their own discovery strategy. See + /// /// SimpleRegisterCoalescing for an example. + /// void getInterferences(IntervalSet &interferences, + /// const LiveInterval &a) const { + /// for(LiveIntervals::const_iterator iv = li.begin(), + /// ivend = li.end(); + /// iv != ivend; + /// ++iv) { + /// if (interfere(a, iv->second)) { + /// interferences.insert(&iv->second); + /// } + /// } + /// }; + /// + /// /// This is *really* slow and stupid. See above. + /// int getNumberOfInterferences(const LiveInterval &a) const { + /// IntervalSet intervals; + /// getInterferences(intervals, a); + /// return(intervals.size()); + /// }; + /// }; + /// + /// In the allocator: + /// + /// RegisterCoalescer &coalescer = getAnalysis(); + /// + /// // We don't reset the coalescer so if it's already been run this + /// // takes almost no time. + /// LinearScanRegallocQuery ifd(*li_); + /// coalescer.coalesceFunction(fn, ifd); + /// + class RegallocQuery { + public: + typedef SmallPtrSet IntervalSet; + + virtual ~RegallocQuery() {}; + + /// Return whether two live ranges interfere. + virtual bool interfere(const LiveInterval &a, + const LiveInterval &b) const { + // A naive test + return(a.overlaps(b)); + }; + + /// Return the set of intervals that interfere with this one. + virtual void getInterferences(IntervalSet &interferences, + const LiveInterval &a) const = 0; + + /// This can often be cheaper than actually returning the + /// interferences. + virtual int getNumberOfInterferences(const LiveInterval &a) const = 0; + + /// Make any data structure updates necessary to reflect + /// coalescing or other modifications. + virtual void updateDataForMerge(const LiveInterval &a, + const LiveInterval &b, + const MachineInstr ©) {}; + + /// Allow the register allocator to communicate when it doesn't + /// want a copy coalesced. This may be due to assumptions made by + /// the allocator about various invariants and so this question is + /// a matter of legality, not performance. Performance decisions + /// about which copies to coalesce should be made by the + /// coalescer. + virtual bool isLegalToCoalesce(const MachineInstr &inst) const { + return(true); + } + }; +} + +// Because of the way .a files work, we must force the SimpleRC +// implementation to be pulled in if the RegisterCoalescing header is +// included. Otherwise we run the risk of RegisterCoalescing being +// used, but the default implementation not being linked into the tool +// that uses it. +FORCE_DEFINING_FILE_TO_BE_LINKED(RegisterCoalescer) +FORCE_DEFINING_FILE_TO_BE_LINKED(SimpleRegisterCoalescing) + +#endif diff --git a/include/llvm/CodeGen/SimpleRegisterCoalescing.h b/include/llvm/CodeGen/SimpleRegisterCoalescing.h index 2f363d585ea..4e760815b9c 100644 --- a/include/llvm/CodeGen/SimpleRegisterCoalescing.h +++ b/include/llvm/CodeGen/SimpleRegisterCoalescing.h @@ -17,6 +17,7 @@ #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/LiveInterval.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/RegisterCoalescer.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/IndexedMap.h" @@ -27,7 +28,8 @@ namespace llvm { class TargetInstrInfo; class VirtRegMap; - class SimpleRegisterCoalescing : public MachineFunctionPass { + class SimpleRegisterCoalescing : public MachineFunctionPass, + public RegisterCoalescer { MachineFunction* mf_; const TargetMachine* tm_; const MRegisterInfo* mri_; @@ -76,6 +78,11 @@ namespace llvm { /// runOnMachineFunction - pass entry point virtual bool runOnMachineFunction(MachineFunction&); + bool coalesceFunction(MachineFunction &mf, RegallocQuery &) { + // This runs as an independent pass, so don't do anything. + return(false); + }; + /// print - Implement the dump method. virtual void print(std::ostream &O, const Module* = 0) const; void print(std::ostream *O, const Module* M = 0) const { diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index 6929b91645f..2859c24743e 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -21,6 +21,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/RegAllocRegistry.h" +#include "llvm/CodeGen/RegisterCoalescer.h" #include "llvm/CodeGen/SSARegMap.h" #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetMachine.h" @@ -96,7 +97,9 @@ namespace { virtual void getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); - AU.addRequiredID(SimpleRegisterCoalescingID); + // Make sure PassManager knows which analyses to make available + // to coalescing and which analyses coalescing invalidates. + AU.addRequiredTransitive(); MachineFunctionPass::getAnalysisUsage(AU); } @@ -194,6 +197,11 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) { mri_ = tm_->getRegisterInfo(); li_ = &getAnalysis(); + // We don't run the coalescer here because we have no reason to + // interact with it. If the coalescer requires interaction, it + // won't do anything. If it doesn't require interaction, we assume + // it was run as a separate pass. + // If this is the first function compiled, compute the related reg classes. if (RelatedRegClasses.empty()) ComputeRelatedRegClasses(); diff --git a/lib/CodeGen/RegisterCoalescer.cpp b/lib/CodeGen/RegisterCoalescer.cpp new file mode 100644 index 00000000000..cffc2e01cc0 --- /dev/null +++ b/lib/CodeGen/RegisterCoalescer.cpp @@ -0,0 +1,43 @@ +//===- RegisterCoalescer.cpp - Generic Register Coalescing Interface -------==// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by the LLVM research group and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the generic RegisterCoalescer interface which +// is used as the common interface used by all clients and +// implementations of register coalescing. +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/RegisterCoalescer.h" +#include "llvm/CodeGen/LiveIntervalAnalysis.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/Target/MRegisterInfo.h" +#include "llvm/Pass.h" + +using namespace llvm; + +// Register the RegisterCoalescer interface, providing a nice name to refer to. +namespace { + RegisterAnalysisGroup Z("Register Coalescer"); +} +char RegisterCoalescer::ID = 0; + +// RegisterCoalescer destructor: DO NOT move this to the header file +// for RegisterCoalescer or else clients of the RegisterCoalescer +// class may not depend on the RegisterCoalescer.o file in the current +// .a file, causing alias analysis support to not be included in the +// tool correctly! +// +RegisterCoalescer::~RegisterCoalescer() {} + +// Because of the way .a files work, we must force the SimpleRC +// implementation to be pulled in if the RegisterCoalescer classes are +// pulled in. Otherwise we run the risk of RegisterCoalescer being +// used, but the default implementation not being linked into the tool +// that uses it. +DEFINING_FILE_FOR(RegisterCoalescer) diff --git a/lib/CodeGen/SimpleRegisterCoalescing.cpp b/lib/CodeGen/SimpleRegisterCoalescing.cpp index 4d5c0819ad0..779c36a2127 100644 --- a/lib/CodeGen/SimpleRegisterCoalescing.cpp +++ b/lib/CodeGen/SimpleRegisterCoalescing.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/SSARegMap.h" +#include "llvm/CodeGen/RegisterCoalescer.h" #include "llvm/Target/MRegisterInfo.h" #include "llvm/Target/TargetInstrInfo.h" #include "llvm/Target/TargetMachine.h" @@ -48,6 +49,9 @@ namespace { RegisterPass X("simple-register-coalescing", "Simple Register Coalescing"); + + // Declare that we implement the RegisterCoalescer interface + RegisterAnalysisGroup V(X); } const PassInfo *llvm::SimpleRegisterCoalescingID = X.getPassInfo(); @@ -1191,3 +1195,10 @@ bool SimpleRegisterCoalescing::runOnMachineFunction(MachineFunction &fn) { void SimpleRegisterCoalescing::print(std::ostream &O, const Module* m) const { li_->print(O, m); } + +RegisterCoalescer* llvm::createSimpleRegisterCoalescer() { + return new SimpleRegisterCoalescing(); +} + +// Make sure that anything that uses RegisterCoalescer pulls in this file... +DEFINING_FILE_FOR(SimpleRegisterCoalescing)