mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 00:16:48 +00:00 
			
		
		
		
	* Fixed a reduction bug which occasionally led to infinite-cost (invalid) register allocation solutions despite the existence finite-cost solutions. * Significantly reduced memory usage (>50% reduction). * Simplified a lot of the solver code. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@94514 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			243 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			9.2 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())
 | |
|             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
 |