[PBQP] Replace PBQPBuilder with composable constraints (PBQPRAConstraint).

This patch removes the PBQPBuilder class and its subclasses and replaces them
with a composable constraints class: PBQPRAConstraint. This allows constraints
that are only required for optimisation (e.g. coalescing, soft pairing) to be
mixed and matched.

This patch also introduces support for target writers to supply custom
constraints for their targets by overriding a TargetSubtargetInfo method:

std::unique_ptr<PBQPRAConstraints> getCustomPBQPConstraints() const;

This patch should have no effect on allocations.



git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219421 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Lang Hames
2014-10-09 18:20:51 +00:00
parent d0fb5b1c11
commit 54d63b4fd5
14 changed files with 520 additions and 647 deletions

View File

@@ -22,6 +22,7 @@
#include <set>
#include <type_traits>
namespace llvm {
namespace PBQP {
template <typename CostT,
@@ -104,6 +105,7 @@ private:
MatrixCostPool matrixPool;
};
}
} // namespace PBQP
} // namespace llvm
#endif

View File

@@ -17,11 +17,12 @@
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include <list>
#include <map>
#include <set>
namespace llvm {
namespace PBQP {
class GraphBase {
@@ -195,7 +196,7 @@ namespace PBQP {
EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
NodeId addConstructedNode(const NodeEntry &N) {
NodeId addConstructedNode(NodeEntry N) {
NodeId NId = 0;
if (!FreeNodeIds.empty()) {
NId = FreeNodeIds.back();
@@ -208,7 +209,7 @@ namespace PBQP {
return NId;
}
EdgeId addConstructedEdge(const EdgeEntry &E) {
EdgeId addConstructedEdge(EdgeEntry E) {
assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() &&
"Attempt to add duplicate edge.");
EdgeId EId = 0;
@@ -237,6 +238,12 @@ namespace PBQP {
class NodeItr {
public:
typedef std::forward_iterator_tag iterator_category;
typedef NodeId value_type;
typedef int difference_type;
typedef NodeId* pointer;
typedef NodeId& reference;
NodeItr(NodeId CurNId, const Graph &G)
: CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
this->CurNId = findNextInUse(CurNId); // Move to first in-use node id
@@ -251,7 +258,7 @@ namespace PBQP {
NodeId findNextInUse(NodeId NId) const {
while (NId < EndNId &&
std::find(FreeNodeIds.begin(), FreeNodeIds.end(), NId) !=
FreeNodeIds.end()) {
FreeNodeIds.end()) {
++NId;
}
return NId;
@@ -331,7 +338,10 @@ namespace PBQP {
};
/// @brief Construct an empty PBQP graph.
Graph() : Solver(nullptr) { }
Graph() : Solver(nullptr) {}
/// @brief Construct an empty PBQP graph with the given graph metadata.
Graph(GraphMetadata Metadata) : Metadata(Metadata), Solver(nullptr) {}
/// @brief Get a reference to the graph metadata.
GraphMetadata& getMetadata() { return Metadata; }
@@ -418,9 +428,7 @@ namespace PBQP {
/// @brief Get a node's cost vector (const version).
/// @param NId Node id.
/// @return Node cost vector.
const Vector& getNodeCosts(NodeId NId) const {
return *getNode(NId).Costs;
}
const Vector& getNodeCosts(NodeId NId) const { return *getNode(NId).Costs; }
NodeMetadata& getNodeMetadata(NodeId NId) {
return getNode(NId).Metadata;
@@ -448,7 +456,9 @@ namespace PBQP {
/// @brief Get an edge's cost matrix (const version).
/// @param EId Edge id.
/// @return Edge cost matrix.
const Matrix& getEdgeCosts(EdgeId EId) const { return *getEdge(EId).Costs; }
const Matrix& getEdgeCosts(EdgeId EId) const {
return *getEdge(EId).Costs;
}
EdgeMetadata& getEdgeMetadata(EdgeId NId) {
return getEdge(NId).Metadata;
@@ -507,7 +517,7 @@ namespace PBQP {
NodeEntry &N = getNode(NId);
// TODO: Can this be for-each'd?
for (AdjEdgeItr AEItr = N.adjEdgesBegin(),
AEEnd = N.adjEdgesEnd();
AEEnd = N.adjEdgesEnd();
AEItr != AEEnd;) {
EdgeId EId = *AEItr;
++AEItr;
@@ -588,7 +598,7 @@ namespace PBQP {
/// @brief Dump a graph to an output stream.
template <typename OStream>
void dump(OStream &OS) {
void dumpToStream(OStream &OS) {
OS << nodeIds().size() << " " << edgeIds().size() << "\n";
for (auto NId : nodeIds()) {
@@ -621,6 +631,11 @@ namespace PBQP {
}
}
/// @brief Dump this graph to dbgs().
void dump() {
dumpToStream(dbgs());
}
/// @brief Print a representation of this graph in DOT format.
/// @param OS Output stream to print on.
template <typename OStream>
@@ -645,6 +660,7 @@ namespace PBQP {
}
};
}
} // namespace PBQP
} // namespace llvm
#endif // LLVM_CODEGEN_PBQP_GRAPH_HPP

View File

@@ -14,6 +14,7 @@
#include <cassert>
#include <functional>
namespace llvm {
namespace PBQP {
typedef float PBQPNum;
@@ -433,6 +434,7 @@ private:
Metadata md;
};
}
} // namespace PBQP
} // namespace llvm
#endif // LLVM_CODEGEN_PBQP_MATH_H

View File

@@ -18,6 +18,7 @@
#include "Math.h"
#include "Solution.h"
namespace llvm {
namespace PBQP {
/// \brief Reduce a node of degree one.
@@ -186,6 +187,7 @@ namespace PBQP {
return s;
}
}
} // namespace PBQP
} // namespace llvm
#endif

View File

@@ -26,10 +26,13 @@
#include <limits>
#include <vector>
namespace llvm{
namespace PBQP {
namespace RegAlloc {
/// @brief Spill option index.
inline unsigned getSpillOptionIdx() { return 0; }
/// \brief Metadata to speed allocatability test.
///
/// Keeps track of the number of infinities in each row and column.
@@ -81,6 +84,8 @@ namespace PBQP {
class NodeMetadata {
public:
typedef std::vector<unsigned> OptionToRegMap;
typedef enum { Unprocessed,
OptimallyReducible,
ConservativelyAllocatable,
@@ -89,6 +94,14 @@ namespace PBQP {
NodeMetadata() : RS(Unprocessed), DeniedOpts(0), OptUnsafeEdges(nullptr){}
~NodeMetadata() { delete[] OptUnsafeEdges; }
void setVReg(unsigned VReg) { this->VReg = VReg; }
unsigned getVReg() const { return VReg; }
void setOptionRegs(OptionToRegMap OptionRegs) {
this->OptionRegs = std::move(OptionRegs);
}
const OptionToRegMap& getOptionRegs() const { return OptionRegs; }
void setup(const Vector& Costs) {
NumOpts = Costs.getLength() - 1;
OptUnsafeEdges = new unsigned[NumOpts]();
@@ -124,6 +137,8 @@ namespace PBQP {
unsigned NumOpts;
unsigned DeniedOpts;
unsigned* OptUnsafeEdges;
unsigned VReg;
OptionToRegMap OptionRegs;
};
class RegAllocSolverImpl {
@@ -144,7 +159,36 @@ namespace PBQP {
typedef RegAlloc::NodeMetadata NodeMetadata;
struct EdgeMetadata { };
struct GraphMetadata { };
class GraphMetadata {
public:
GraphMetadata(MachineFunction &MF,
LiveIntervals &LIS,
MachineBlockFrequencyInfo &MBFI)
: MF(MF), LIS(LIS), MBFI(MBFI) {}
MachineFunction &MF;
LiveIntervals &LIS;
MachineBlockFrequencyInfo &MBFI;
void setNodeIdForVReg(unsigned VReg, GraphBase::NodeId NId) {
VRegToNodeId[VReg] = NId;
}
GraphBase::NodeId getNodeIdForVReg(unsigned VReg) const {
auto VRegItr = VRegToNodeId.find(VReg);
if (VRegItr == VRegToNodeId.end())
return GraphBase::invalidNodeId();
return VRegItr->second;
}
void eraseNodeIdForVReg(unsigned VReg) {
VRegToNodeId.erase(VReg);
}
private:
DenseMap<unsigned, NodeId> VRegToNodeId;
};
typedef PBQP::Graph<RegAllocSolverImpl> Graph;
@@ -345,16 +389,21 @@ namespace PBQP {
NodeSet NotProvablyAllocatableNodes;
};
typedef Graph<RegAllocSolverImpl> Graph;
class PBQPRAGraph : public PBQP::Graph<RegAllocSolverImpl> {
private:
typedef PBQP::Graph<RegAllocSolverImpl> BaseT;
public:
PBQPRAGraph(GraphMetadata Metadata) : BaseT(Metadata) {}
};
inline Solution solve(Graph& G) {
inline Solution solve(PBQPRAGraph& G) {
if (G.empty())
return Solution();
RegAllocSolverImpl RegAllocSolver(G);
return RegAllocSolver.solve();
}
}
}
} // namespace RegAlloc
} // namespace PBQP
} // namespace llvm
#endif // LLVM_CODEGEN_PBQP_REGALLOCSOLVER_H

View File

@@ -18,6 +18,7 @@
#include "Math.h"
#include <map>
namespace llvm {
namespace PBQP {
/// \brief Represents a solution to a PBQP problem.
@@ -87,6 +88,7 @@ namespace PBQP {
};
}
} // namespace PBQP
} // namespace llvm
#endif // LLVM_CODEGEN_PBQP_SOLUTION_H

View File

@@ -16,152 +16,15 @@
#ifndef LLVM_CODEGEN_REGALLOCPBQP_H
#define LLVM_CODEGEN_REGALLOCPBQP_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/PBQPRAConstraint.h"
#include "llvm/CodeGen/PBQP/RegAllocSolver.h"
#include <map>
#include <set>
namespace llvm {
class LiveIntervals;
class MachineBlockFrequencyInfo;
class MachineFunction;
class TargetRegisterInfo;
typedef PBQP::RegAlloc::Graph PBQPRAGraph;
/// This class wraps up a PBQP instance representing a register allocation
/// problem, plus the structures necessary to map back from the PBQP solution
/// to a register allocation solution. (i.e. The PBQP-node <--> vreg map,
/// and the PBQP option <--> storage location map).
class PBQPRAProblem {
public:
typedef SmallVector<unsigned, 16> AllowedSet;
PBQPRAGraph& getGraph() { return graph; }
const PBQPRAGraph& getGraph() const { return graph; }
/// Record the mapping between the given virtual register and PBQP node,
/// and the set of allowed pregs for the vreg.
///
/// If you are extending
/// PBQPBuilder you are unlikely to need this: Nodes and options for all
/// vregs will already have been set up for you by the base class.
template <typename AllowedRegsItr>
void recordVReg(unsigned vreg, PBQPRAGraph::NodeId nodeId,
AllowedRegsItr arBegin, AllowedRegsItr arEnd) {
assert(node2VReg.find(nodeId) == node2VReg.end() && "Re-mapping node.");
assert(vreg2Node.find(vreg) == vreg2Node.end() && "Re-mapping vreg.");
assert(allowedSets[vreg].empty() && "vreg already has pregs.");
node2VReg[nodeId] = vreg;
vreg2Node[vreg] = nodeId;
std::copy(arBegin, arEnd, std::back_inserter(allowedSets[vreg]));
}
/// Get the virtual register corresponding to the given PBQP node.
unsigned getVRegForNode(PBQPRAGraph::NodeId nodeId) const;
/// Get the PBQP node corresponding to the given virtual register.
PBQPRAGraph::NodeId getNodeForVReg(unsigned vreg) const;
/// Returns true if the given PBQP option represents a physical register,
/// false otherwise.
bool isPRegOption(unsigned vreg, unsigned option) const {
// At present we only have spills or pregs, so anything that's not a
// spill is a preg. (This might be extended one day to support remat).
return !isSpillOption(vreg, option);
}
/// Returns true if the given PBQP option represents spilling, false
/// otherwise.
bool isSpillOption(unsigned vreg, unsigned option) const {
// We hardcode option zero as the spill option.
return option == 0;
}
/// Returns the allowed set for the given virtual register.
const AllowedSet& getAllowedSet(unsigned vreg) const;
/// Get PReg for option.
unsigned getPRegForOption(unsigned vreg, unsigned option) const;
private:
typedef std::map<PBQPRAGraph::NodeId, unsigned> Node2VReg;
typedef DenseMap<unsigned, PBQPRAGraph::NodeId> VReg2Node;
typedef DenseMap<unsigned, AllowedSet> AllowedSetMap;
PBQPRAGraph graph;
Node2VReg node2VReg;
VReg2Node vreg2Node;
AllowedSetMap allowedSets;
};
/// Builds PBQP instances to represent register allocation problems. Includes
/// spill, interference and coalescing costs by default. You can extend this
/// class to support additional constraints for your architecture.
class PBQPBuilder {
private:
PBQPBuilder(const PBQPBuilder&) LLVM_DELETED_FUNCTION;
void operator=(const PBQPBuilder&) LLVM_DELETED_FUNCTION;
public:
typedef std::set<unsigned> RegSet;
/// Default constructor.
PBQPBuilder() {}
/// Clean up a PBQPBuilder.
virtual ~PBQPBuilder() {}
/// Build a PBQP instance to represent the register allocation problem for
/// the given MachineFunction.
virtual std::unique_ptr<PBQPRAProblem>
build(MachineFunction *mf, const LiveIntervals *lis,
const MachineBlockFrequencyInfo *mbfi, const RegSet &vregs);
private:
void addSpillCosts(PBQP::Vector &costVec, PBQP::PBQPNum spillCost);
void addInterferenceCosts(PBQP::Matrix &costMat,
const PBQPRAProblem::AllowedSet &vr1Allowed,
const PBQPRAProblem::AllowedSet &vr2Allowed,
const TargetRegisterInfo *tri);
};
/// Extended builder which adds coalescing constraints to a problem.
class PBQPBuilderWithCoalescing : public PBQPBuilder {
public:
/// Build a PBQP instance to represent the register allocation problem for
/// the given MachineFunction.
std::unique_ptr<PBQPRAProblem> build(MachineFunction *mf,
const LiveIntervals *lis,
const MachineBlockFrequencyInfo *mbfi,
const RegSet &vregs) override;
private:
void addPhysRegCoalesce(PBQP::Vector &costVec, unsigned pregOption,
PBQP::PBQPNum benefit);
void addVirtRegCoalesce(PBQP::Matrix &costMat,
const PBQPRAProblem::AllowedSet &vr1Allowed,
const PBQPRAProblem::AllowedSet &vr2Allowed,
PBQP::PBQPNum benefit);
};
/// @brief Create a PBQP register allocator instance.
FunctionPass *
createPBQPRegisterAllocator(std::unique_ptr<PBQPBuilder> builder,
char *customPassID = nullptr);
createPBQPRegisterAllocator(char *customPassID = nullptr);
}
#endif /* LLVM_CODEGEN_REGALLOCPBQP_H */