mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-24 22:32:47 +00:00
eb6c8f53b4
For now the allocator still uses the old (internal) construction mechanism by default. This will be phased out soon assuming no issues with the builder system come up. To invoke the new construction mechanism just pass '-regalloc=pbqp -pbqp-builder' to llc. To provide custom constraints a Target just needs to extend PBQPBuilder and pass an instance of their derived builder to the RegAllocPBQP constructor. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@114272 91177308-0d34-0410-b5e6-96231b3b80d8
247 lines
9.3 KiB
C++
247 lines
9.3 KiB
C++
//===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H
|
|
#define LLVM_CODEGEN_PBQP_HEURISTICBASE_H
|
|
|
|
#include "HeuristicSolver.h"
|
|
|
|
namespace PBQP {
|
|
|
|
/// \brief Abstract base class for heuristic implementations.
|
|
///
|
|
/// This class provides a handy base for heuristic implementations with common
|
|
/// solver behaviour implemented for a number of methods.
|
|
///
|
|
/// To implement your own heuristic using this class as a base you'll have to
|
|
/// implement, as a minimum, the following methods:
|
|
/// <ul>
|
|
/// <li> void addToHeuristicList(Graph::NodeItr) : Add a node to the
|
|
/// heuristic reduction list.
|
|
/// <li> void heuristicReduce() : Perform a single heuristic reduction.
|
|
/// <li> void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent)
|
|
/// change to the cost matrix on the given edge (by R2).
|
|
/// <li> void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new
|
|
/// costs on the given edge.
|
|
/// <li> void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new
|
|
/// edge into the PBQP graph (by R2).
|
|
/// <li> void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the
|
|
/// disconnection of the given edge from the given node.
|
|
/// <li> A constructor for your derived class : to pass back a reference to
|
|
/// the solver which is using this heuristic.
|
|
/// </ul>
|
|
///
|
|
/// These methods are implemented in this class for documentation purposes,
|
|
/// but will assert if called.
|
|
///
|
|
/// Note that this class uses the curiously recursive template idiom to
|
|
/// forward calls to the derived class. These methods need not be made
|
|
/// virtual, and indeed probably shouldn't for performance reasons.
|
|
///
|
|
/// You'll also need to provide NodeData and EdgeData structs in your class.
|
|
/// These can be used to attach data relevant to your heuristic to each
|
|
/// node/edge in the PBQP graph.
|
|
|
|
template <typename HImpl>
|
|
class HeuristicBase {
|
|
private:
|
|
|
|
typedef std::list<Graph::NodeItr> OptimalList;
|
|
|
|
HeuristicSolverImpl<HImpl> &s;
|
|
Graph &g;
|
|
OptimalList optimalList;
|
|
|
|
// Return a reference to the derived heuristic.
|
|
HImpl& impl() { return static_cast<HImpl&>(*this); }
|
|
|
|
// Add the given node to the optimal reductions list. Keep an iterator to
|
|
// its location for fast removal.
|
|
void addToOptimalReductionList(Graph::NodeItr nItr) {
|
|
optimalList.insert(optimalList.end(), nItr);
|
|
}
|
|
|
|
public:
|
|
|
|
/// \brief Construct an instance with a reference to the given solver.
|
|
/// @param solver The solver which is using this heuristic instance.
|
|
HeuristicBase(HeuristicSolverImpl<HImpl> &solver)
|
|
: s(solver), g(s.getGraph()) { }
|
|
|
|
/// \brief Get the solver which is using this heuristic instance.
|
|
/// @return The solver which is using this heuristic instance.
|
|
///
|
|
/// You can use this method to get access to the solver in your derived
|
|
/// heuristic implementation.
|
|
HeuristicSolverImpl<HImpl>& getSolver() { return s; }
|
|
|
|
/// \brief Get the graph representing the problem to be solved.
|
|
/// @return The graph representing the problem to be solved.
|
|
Graph& getGraph() { return g; }
|
|
|
|
/// \brief Tell the solver to simplify the graph before the reduction phase.
|
|
/// @return Whether or not the solver should run a simplification phase
|
|
/// prior to the main setup and reduction.
|
|
///
|
|
/// HeuristicBase returns true from this method as it's a sensible default,
|
|
/// however you can over-ride it in your derived class if you want different
|
|
/// behaviour.
|
|
bool solverRunSimplify() const { return true; }
|
|
|
|
/// \brief Decide whether a node should be optimally or heuristically
|
|
/// reduced.
|
|
/// @return Whether or not the given node should be listed for optimal
|
|
/// reduction (via R0, R1 or R2).
|
|
///
|
|
/// HeuristicBase returns true for any node with degree less than 3. This is
|
|
/// sane and sensible for many situations, but not all. You can over-ride
|
|
/// this method in your derived class if you want a different selection
|
|
/// criteria. Note however that your criteria for selecting optimal nodes
|
|
/// should be <i>at least</i> as strong as this. I.e. Nodes of degree 3 or
|
|
/// higher should not be selected under any circumstances.
|
|
bool shouldOptimallyReduce(Graph::NodeItr nItr) {
|
|
if (g.getNodeDegree(nItr) < 3)
|
|
return true;
|
|
// else
|
|
return false;
|
|
}
|
|
|
|
/// \brief Add the given node to the list of nodes to be optimally reduced.
|
|
/// @return nItr Node iterator to be added.
|
|
///
|
|
/// You probably don't want to over-ride this, except perhaps to record
|
|
/// statistics before calling this implementation. HeuristicBase relies on
|
|
/// its behaviour.
|
|
void addToOptimalReduceList(Graph::NodeItr nItr) {
|
|
optimalList.push_back(nItr);
|
|
}
|
|
|
|
/// \brief Initialise the heuristic.
|
|
///
|
|
/// HeuristicBase iterates over all nodes in the problem and adds them to
|
|
/// the appropriate list using addToOptimalReduceList or
|
|
/// addToHeuristicReduceList based on the result of shouldOptimallyReduce.
|
|
///
|
|
/// This behaviour should be fine for most situations.
|
|
void setup() {
|
|
for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
|
|
nItr != nEnd; ++nItr) {
|
|
if (impl().shouldOptimallyReduce(nItr)) {
|
|
addToOptimalReduceList(nItr);
|
|
} else {
|
|
impl().addToHeuristicReduceList(nItr);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// \brief Optimally reduce one of the nodes in the optimal reduce list.
|
|
/// @return True if a reduction takes place, false if the optimal reduce
|
|
/// list is empty.
|
|
///
|
|
/// Selects a node from the optimal reduce list and removes it, applying
|
|
/// R0, R1 or R2 as appropriate based on the selected node's degree.
|
|
bool optimalReduce() {
|
|
if (optimalList.empty())
|
|
return false;
|
|
|
|
Graph::NodeItr nItr = optimalList.front();
|
|
optimalList.pop_front();
|
|
|
|
switch (s.getSolverDegree(nItr)) {
|
|
case 0: s.applyR0(nItr); break;
|
|
case 1: s.applyR1(nItr); break;
|
|
case 2: s.applyR2(nItr); break;
|
|
default: assert(false &&
|
|
"Optimal reductions of degree > 2 nodes is invalid.");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// \brief Perform the PBQP reduction process.
|
|
///
|
|
/// Reduces the problem to the empty graph by repeated application of the
|
|
/// reduction rules R0, R1, R2 and RN.
|
|
/// R0, R1 or R2 are always applied if possible before RN is used.
|
|
void reduce() {
|
|
bool finished = false;
|
|
|
|
while (!finished) {
|
|
if (!optimalReduce()) {
|
|
if (impl().heuristicReduce()) {
|
|
getSolver().recordRN();
|
|
} else {
|
|
finished = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// \brief Add a node to the heuristic reduce list.
|
|
/// @param nItr Node iterator to add to the heuristic reduce list.
|
|
void addToHeuristicList(Graph::NodeItr nItr) {
|
|
assert(false && "Must be implemented in derived class.");
|
|
}
|
|
|
|
/// \brief Heuristically reduce one of the nodes in the heuristic
|
|
/// reduce list.
|
|
/// @return True if a reduction takes place, false if the heuristic reduce
|
|
/// list is empty.
|
|
void heuristicReduce() {
|
|
assert(false && "Must be implemented in derived class.");
|
|
}
|
|
|
|
/// \brief Prepare a change in the costs on the given edge.
|
|
/// @param eItr Edge iterator.
|
|
void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
|
|
assert(false && "Must be implemented in derived class.");
|
|
}
|
|
|
|
/// \brief Handle the change in the costs on the given edge.
|
|
/// @param eItr Edge iterator.
|
|
void postUpdateEdgeCostts(Graph::EdgeItr eItr) {
|
|
assert(false && "Must be implemented in derived class.");
|
|
}
|
|
|
|
/// \brief Handle the addition of a new edge into the PBQP graph.
|
|
/// @param eItr Edge iterator for the added edge.
|
|
void handleAddEdge(Graph::EdgeItr eItr) {
|
|
assert(false && "Must be implemented in derived class.");
|
|
}
|
|
|
|
/// \brief Handle disconnection of an edge from a node.
|
|
/// @param eItr Edge iterator for edge being disconnected.
|
|
/// @param nItr Node iterator for the node being disconnected from.
|
|
///
|
|
/// Edges are frequently removed due to the removal of a node. This
|
|
/// method allows for the effect to be computed only for the remaining
|
|
/// node in the graph.
|
|
void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
|
|
assert(false && "Must be implemented in derived class.");
|
|
}
|
|
|
|
/// \brief Clean up any structures used by HeuristicBase.
|
|
///
|
|
/// At present this just performs a sanity check: that the optimal reduce
|
|
/// list is empty now that reduction has completed.
|
|
///
|
|
/// If your derived class has more complex structures which need tearing
|
|
/// down you should over-ride this method but include a call back to this
|
|
/// implementation.
|
|
void cleanup() {
|
|
assert(optimalList.empty() && "Nodes left over in optimal reduce list?");
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
#endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H
|