From 6699fb27091927528f9f6059c3034d566dbed623 Mon Sep 17 00:00:00 2001 From: Lang Hames Date: Thu, 6 Aug 2009 23:32:48 +0000 Subject: [PATCH] New C++ PBQP solver. Currently about as fast (read _slow_) as the old C based solver, but I'll be working to improve that. The PBQP allocator has been updated to use the new solver. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@78354 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/PBQP.cpp | 1395 -------------------------- lib/CodeGen/PBQP.h | 284 ------ lib/CodeGen/PBQP/AnnotatedGraph.h | 170 ++++ lib/CodeGen/PBQP/ExhaustiveSolver.h | 93 ++ lib/CodeGen/PBQP/GraphBase.h | 570 +++++++++++ lib/CodeGen/PBQP/GraphGenerator.h | 195 ++++ lib/CodeGen/PBQP/HeuristicSolver.h | 799 +++++++++++++++ lib/CodeGen/PBQP/Heuristics/Briggs.h | 385 +++++++ lib/CodeGen/PBQP/PBQPMath.h | 279 ++++++ lib/CodeGen/PBQP/SimpleGraph.h | 86 ++ lib/CodeGen/PBQP/Solution.h | 74 ++ lib/CodeGen/PBQP/Solver.h | 21 + lib/CodeGen/RegAllocPBQP.cpp | 276 +++-- 13 files changed, 2846 insertions(+), 1781 deletions(-) delete mode 100644 lib/CodeGen/PBQP.cpp delete mode 100644 lib/CodeGen/PBQP.h create mode 100644 lib/CodeGen/PBQP/AnnotatedGraph.h create mode 100644 lib/CodeGen/PBQP/ExhaustiveSolver.h create mode 100644 lib/CodeGen/PBQP/GraphBase.h create mode 100644 lib/CodeGen/PBQP/GraphGenerator.h create mode 100644 lib/CodeGen/PBQP/HeuristicSolver.h create mode 100644 lib/CodeGen/PBQP/Heuristics/Briggs.h create mode 100644 lib/CodeGen/PBQP/PBQPMath.h create mode 100644 lib/CodeGen/PBQP/SimpleGraph.h create mode 100644 lib/CodeGen/PBQP/Solution.h create mode 100644 lib/CodeGen/PBQP/Solver.h diff --git a/lib/CodeGen/PBQP.cpp b/lib/CodeGen/PBQP.cpp deleted file mode 100644 index 562300f94e1..00000000000 --- a/lib/CodeGen/PBQP.cpp +++ /dev/null @@ -1,1395 +0,0 @@ -//===---------------- PBQP.cpp --------- PBQP Solver ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Developed by: Bernhard Scholz -// The University of Sydney -// http://www.it.usyd.edu.au/~scholz -//===----------------------------------------------------------------------===// - -#include "PBQP.h" -#include "llvm/Config/alloca.h" -#include -#include -#include - -namespace llvm { - -/************************************************************************** - * Data Structures - **************************************************************************/ - -/* edge of PBQP graph */ -typedef struct adjnode { - struct adjnode *prev, /* doubly chained list */ - *succ, - *reverse; /* reverse edge */ - int adj; /* adj. node */ - PBQPMatrix *costs; /* cost matrix of edge */ - - bool tc_valid; /* flag whether following fields are valid */ - int *tc_safe_regs; /* safe registers */ - int tc_impact; /* impact */ -} adjnode; - -/* bucket node */ -typedef struct bucketnode { - struct bucketnode *prev; /* doubly chained list */ - struct bucketnode *succ; - int u; /* node */ -} bucketnode; - -/* data structure of partitioned boolean quadratic problem */ -struct pbqp { - int num_nodes; /* number of nodes */ - int max_deg; /* maximal degree of a node */ - bool solved; /* flag that indicates whether PBQP has been solved yet */ - bool optimal; /* flag that indicates whether PBQP is optimal */ - PBQPNum min; - bool changed; /* flag whether graph has changed in simplification */ - - /* node fields */ - PBQPVector **node_costs; /* cost vectors of nodes */ - int *node_deg; /* node degree of nodes */ - int *solution; /* solution for node */ - adjnode **adj_list; /* adj. list */ - bucketnode **bucket_ptr; /* bucket pointer of a node */ - - /* node stack */ - int *stack; /* stack of nodes */ - int stack_ptr; /* stack pointer */ - - /* bucket fields */ - bucketnode **bucket_list; /* bucket list */ - - int num_r0; /* counters for number statistics */ - int num_ri; - int num_rii; - int num_rn; - int num_rn_special; -}; - -bool isInf(PBQPNum n) { return n == std::numeric_limits::infinity(); } - -/***************************************************************************** - * allocation/de-allocation of pbqp problem - ****************************************************************************/ - -/* allocate new partitioned boolean quadratic program problem */ -pbqp *alloc_pbqp(int num_nodes) -{ - pbqp *this_; - int u; - - assert(num_nodes > 0); - - /* allocate memory for pbqp data structure */ - this_ = (pbqp *)malloc(sizeof(pbqp)); - - /* Initialize pbqp fields */ - this_->num_nodes = num_nodes; - this_->solved = false; - this_->optimal = true; - this_->min = 0.0; - this_->max_deg = 0; - this_->changed = false; - this_->num_r0 = 0; - this_->num_ri = 0; - this_->num_rii = 0; - this_->num_rn = 0; - this_->num_rn_special = 0; - - /* initialize/allocate stack fields of pbqp */ - this_->stack = (int *) malloc(sizeof(int)*num_nodes); - this_->stack_ptr = 0; - - /* initialize/allocate node fields of pbqp */ - this_->adj_list = (adjnode **) malloc(sizeof(adjnode *)*num_nodes); - this_->node_deg = (int *) malloc(sizeof(int)*num_nodes); - this_->solution = (int *) malloc(sizeof(int)*num_nodes); - this_->bucket_ptr = (bucketnode **) malloc(sizeof(bucketnode **)*num_nodes); - this_->node_costs = (PBQPVector**) malloc(sizeof(PBQPVector*) * num_nodes); - for(u=0;usolution[u]=-1; - this_->adj_list[u]=NULL; - this_->node_deg[u]=0; - this_->bucket_ptr[u]=NULL; - this_->node_costs[u]=NULL; - } - - /* initialize bucket list */ - this_->bucket_list = NULL; - - return this_; -} - -/* free pbqp problem */ -void free_pbqp(pbqp *this_) -{ - int u; - int deg; - adjnode *adj_ptr,*adj_next; - bucketnode *bucket,*bucket_next; - - assert(this_ != NULL); - - /* free node cost fields */ - for(u=0;u < this_->num_nodes;u++) { - delete this_->node_costs[u]; - } - free(this_->node_costs); - - /* free bucket list */ - for(deg=0;deg<=this_->max_deg;deg++) { - for(bucket=this_->bucket_list[deg];bucket!=NULL;bucket=bucket_next) { - this_->bucket_ptr[bucket->u] = NULL; - bucket_next = bucket-> succ; - free(bucket); - } - } - free(this_->bucket_list); - - /* free adj. list */ - assert(this_->adj_list != NULL); - for(u=0;u < this_->num_nodes; u++) { - for(adj_ptr = this_->adj_list[u]; adj_ptr != NULL; adj_ptr = adj_next) { - adj_next = adj_ptr -> succ; - if (u < adj_ptr->adj) { - assert(adj_ptr != NULL); - delete adj_ptr->costs; - } - if (adj_ptr -> tc_safe_regs != NULL) { - free(adj_ptr -> tc_safe_regs); - } - free(adj_ptr); - } - } - free(this_->adj_list); - - /* free other node fields */ - free(this_->node_deg); - free(this_->solution); - free(this_->bucket_ptr); - - /* free stack */ - free(this_->stack); - - /* free pbqp data structure itself */ - free(this_); -} - - -/**************************************************************************** - * adj. node routines - ****************************************************************************/ - -/* find data structure of adj. node of a given node */ -static -adjnode *find_adjnode(pbqp *this_,int u,int v) -{ - adjnode *adj_ptr; - - assert (this_ != NULL); - assert (u >= 0 && u < this_->num_nodes); - assert (v >= 0 && v < this_->num_nodes); - assert(this_->adj_list != NULL); - - for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - if (adj_ptr->adj == v) { - return adj_ptr; - } - } - return NULL; -} - -/* allocate a new data structure for adj. node */ -static -adjnode *alloc_adjnode(pbqp *this_,int u, PBQPMatrix *costs) -{ - adjnode *p; - - assert(this_ != NULL); - assert(costs != NULL); - assert(u >= 0 && u < this_->num_nodes); - - p = (adjnode *)malloc(sizeof(adjnode)); - assert(p != NULL); - - p->adj = u; - p->costs = costs; - - p->tc_valid= false; - p->tc_safe_regs = NULL; - p->tc_impact = 0; - - return p; -} - -/* insert adjacence node to adj. list */ -static -void insert_adjnode(pbqp *this_, int u, adjnode *adj_ptr) -{ - - assert(this_ != NULL); - assert(adj_ptr != NULL); - assert(u >= 0 && u < this_->num_nodes); - - /* if adjacency list of node is not empty -> update - first node of the list */ - if (this_ -> adj_list[u] != NULL) { - assert(this_->adj_list[u]->prev == NULL); - this_->adj_list[u] -> prev = adj_ptr; - } - - /* update doubly chained list pointers of pointers */ - adj_ptr -> succ = this_->adj_list[u]; - adj_ptr -> prev = NULL; - - /* update adjacency list pointer of node u */ - this_->adj_list[u] = adj_ptr; -} - -/* remove entry in an adj. list */ -static -void remove_adjnode(pbqp *this_, int u, adjnode *adj_ptr) -{ - assert(this_!= NULL); - assert(u >= 0 && u <= this_->num_nodes); - assert(this_->adj_list != NULL); - assert(adj_ptr != NULL); - - if (adj_ptr -> prev == NULL) { - this_->adj_list[u] = adj_ptr -> succ; - } else { - adj_ptr -> prev -> succ = adj_ptr -> succ; - } - - if (adj_ptr -> succ != NULL) { - adj_ptr -> succ -> prev = adj_ptr -> prev; - } - - if(adj_ptr->reverse != NULL) { - adjnode *rev = adj_ptr->reverse; - rev->reverse = NULL; - } - - if (adj_ptr -> tc_safe_regs != NULL) { - free(adj_ptr -> tc_safe_regs); - } - - free(adj_ptr); -} - -/***************************************************************************** - * node functions - ****************************************************************************/ - -/* get degree of a node */ -static -int get_deg(pbqp *this_,int u) -{ - adjnode *adj_ptr; - int deg = 0; - - assert(this_ != NULL); - assert(u >= 0 && u < this_->num_nodes); - assert(this_->adj_list != NULL); - - for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - deg ++; - } - return deg; -} - -/* reinsert node */ -static -void reinsert_node(pbqp *this_,int u) -{ - adjnode *adj_u, - *adj_v; - - assert(this_!= NULL); - assert(u >= 0 && u <= this_->num_nodes); - assert(this_->adj_list != NULL); - - for(adj_u = this_ -> adj_list[u]; adj_u != NULL; adj_u = adj_u -> succ) { - int v = adj_u -> adj; - adj_v = alloc_adjnode(this_,u,adj_u->costs); - insert_adjnode(this_,v,adj_v); - } -} - -/* remove node */ -static -void remove_node(pbqp *this_,int u) -{ - adjnode *adj_ptr; - - assert(this_!= NULL); - assert(u >= 0 && u <= this_->num_nodes); - assert(this_->adj_list != NULL); - - for(adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - remove_adjnode(this_,adj_ptr->adj,adj_ptr -> reverse); - } -} - -/***************************************************************************** - * edge functions - ****************************************************************************/ - -/* insert edge to graph */ -/* (does not check whether edge exists in graph */ -static -void insert_edge(pbqp *this_, int u, int v, PBQPMatrix *costs) -{ - adjnode *adj_u, - *adj_v; - - /* create adjanceny entry for u */ - adj_u = alloc_adjnode(this_,v,costs); - insert_adjnode(this_,u,adj_u); - - - /* create adjanceny entry for v */ - adj_v = alloc_adjnode(this_,u,costs); - insert_adjnode(this_,v,adj_v); - - /* create link for reverse edge */ - adj_u -> reverse = adj_v; - adj_v -> reverse = adj_u; -} - -/* delete edge */ -static -void delete_edge(pbqp *this_,int u,int v) -{ - adjnode *adj_ptr; - adjnode *rev; - - assert(this_ != NULL); - assert( u >= 0 && u < this_->num_nodes); - assert( v >= 0 && v < this_->num_nodes); - - adj_ptr=find_adjnode(this_,u,v); - assert(adj_ptr != NULL); - assert(adj_ptr->reverse != NULL); - - delete adj_ptr -> costs; - - rev = adj_ptr->reverse; - remove_adjnode(this_,u,adj_ptr); - remove_adjnode(this_,v,rev); -} - -/***************************************************************************** - * cost functions - ****************************************************************************/ - -/* Note: Since cost(u,v) = transpose(cost(v,u)), it would be necessary to store - two matrices for both edges (u,v) and (v,u). However, we only store the - matrix for the case u < v. For the other case we transpose the stored matrix - if required. -*/ - -/* add costs to cost vector of a node */ -void add_pbqp_nodecosts(pbqp *this_,int u, PBQPVector *costs) -{ - assert(this_ != NULL); - assert(costs != NULL); - assert(u >= 0 && u <= this_->num_nodes); - - if (!this_->node_costs[u]) { - this_->node_costs[u] = new PBQPVector(*costs); - } else { - *this_->node_costs[u] += *costs; - } -} - -/* get cost matrix ptr */ -static -PBQPMatrix *get_costmatrix_ptr(pbqp *this_, int u, int v) -{ - adjnode *adj_ptr; - PBQPMatrix *m = NULL; - - assert (this_ != NULL); - assert (u >= 0 && u < this_->num_nodes); - assert (v >= 0 && v < this_->num_nodes); - - adj_ptr = find_adjnode(this_,u,v); - - if (adj_ptr != NULL) { - m = adj_ptr -> costs; - } - - return m; -} - -/* get cost matrix ptr */ -/* Note: only the pointer is returned for - cost(u,v), if u < v. -*/ -static -PBQPMatrix *pbqp_get_costmatrix(pbqp *this_, int u, int v) -{ - adjnode *adj_ptr = find_adjnode(this_,u,v); - - if (adj_ptr != NULL) { - if ( u < v) { - return new PBQPMatrix(*adj_ptr->costs); - } else { - return new PBQPMatrix(adj_ptr->costs->transpose()); - } - } else { - return NULL; - } -} - -/* add costs to cost matrix of an edge */ -void add_pbqp_edgecosts(pbqp *this_,int u,int v, PBQPMatrix *costs) -{ - PBQPMatrix *adj_costs; - - assert(this_!= NULL); - assert(costs != NULL); - assert(u >= 0 && u <= this_->num_nodes); - assert(v >= 0 && v <= this_->num_nodes); - - /* does the edge u-v exists ? */ - if (u == v) { - PBQPVector *diag = new PBQPVector(costs->diagonalize()); - add_pbqp_nodecosts(this_,v,diag); - delete diag; - } else if ((adj_costs = get_costmatrix_ptr(this_,u,v))!=NULL) { - if ( u < v) { - *adj_costs += *costs; - } else { - *adj_costs += costs->transpose(); - } - } else { - adj_costs = new PBQPMatrix((u < v) ? *costs : costs->transpose()); - insert_edge(this_,u,v,adj_costs); - } -} - -/* remove bucket from bucket list */ -static -void pbqp_remove_bucket(pbqp *this_, bucketnode *bucket) -{ - int u = bucket->u; - - assert(this_ != NULL); - assert(u >= 0 && u < this_->num_nodes); - assert(this_->bucket_list != NULL); - assert(this_->bucket_ptr[u] != NULL); - - /* update predecessor node in bucket list - (if no preceeding bucket exists, then - the bucket_list pointer needs to be - updated.) - */ - if (bucket->prev != NULL) { - bucket->prev-> succ = bucket->succ; - } else { - this_->bucket_list[this_->node_deg[u]] = bucket -> succ; - } - - /* update successor node in bucket list */ - if (bucket->succ != NULL) { - bucket->succ-> prev = bucket->prev; - } -} - -/********************************************************************************** - * pop functions - **********************************************************************************/ - -/* pop node of given degree */ -static -int pop_node(pbqp *this_,int deg) -{ - bucketnode *bucket; - int u; - - assert(this_ != NULL); - assert(deg >= 0 && deg <= this_->max_deg); - assert(this_->bucket_list != NULL); - - /* get first bucket of bucket list */ - bucket = this_->bucket_list[deg]; - assert(bucket != NULL); - - /* remove bucket */ - pbqp_remove_bucket(this_,bucket); - u = bucket->u; - free(bucket); - return u; -} - -/********************************************************************************** - * reorder functions - **********************************************************************************/ - -/* add bucket to bucketlist */ -static -void add_to_bucketlist(pbqp *this_,bucketnode *bucket, int deg) -{ - bucketnode *old_head; - - assert(bucket != NULL); - assert(this_ != NULL); - assert(deg >= 0 && deg <= this_->max_deg); - assert(this_->bucket_list != NULL); - - /* store node degree (for re-ordering purposes)*/ - this_->node_deg[bucket->u] = deg; - - /* put bucket to front of doubly chained list */ - old_head = this_->bucket_list[deg]; - bucket -> prev = NULL; - bucket -> succ = old_head; - this_ -> bucket_list[deg] = bucket; - if (bucket -> succ != NULL ) { - assert ( old_head -> prev == NULL); - old_head -> prev = bucket; - } -} - - -/* reorder node in bucket list according to - current node degree */ -static -void reorder_node(pbqp *this_, int u) -{ - int deg; - - assert(this_ != NULL); - assert(u>= 0 && u < this_->num_nodes); - assert(this_->bucket_list != NULL); - assert(this_->bucket_ptr[u] != NULL); - - /* get current node degree */ - deg = get_deg(this_,u); - - /* remove bucket from old bucket list only - if degree of node has changed. */ - if (deg != this_->node_deg[u]) { - pbqp_remove_bucket(this_,this_->bucket_ptr[u]); - add_to_bucketlist(this_,this_->bucket_ptr[u],deg); - } -} - -/* reorder adj. nodes of a node */ -static -void reorder_adjnodes(pbqp *this_,int u) -{ - adjnode *adj_ptr; - - assert(this_!= NULL); - assert(u >= 0 && u <= this_->num_nodes); - assert(this_->adj_list != NULL); - - for(adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - reorder_node(this_,adj_ptr->adj); - } -} - -/********************************************************************************** - * creation functions - **********************************************************************************/ - -/* create new bucket entry */ -/* consistency of the bucket list is not checked! */ -static -void create_bucket(pbqp *this_,int u,int deg) -{ - bucketnode *bucket; - - assert(this_ != NULL); - assert(u >= 0 && u < this_->num_nodes); - assert(this_->bucket_list != NULL); - - bucket = (bucketnode *)malloc(sizeof(bucketnode)); - assert(bucket != NULL); - - bucket -> u = u; - this_->bucket_ptr[u] = bucket; - - add_to_bucketlist(this_,bucket,deg); -} - -/* create bucket list */ -static -void create_bucketlist(pbqp *this_) -{ - int u; - int max_deg; - int deg; - - assert(this_ != NULL); - assert(this_->bucket_list == NULL); - - /* determine max. degree of the nodes */ - max_deg = 2; /* at least of degree two! */ - for(u=0;unum_nodes;u++) { - deg = this_->node_deg[u] = get_deg(this_,u); - if (deg > max_deg) { - max_deg = deg; - } - } - this_->max_deg = max_deg; - - /* allocate bucket list */ - this_ -> bucket_list = (bucketnode **)malloc(sizeof(bucketnode *)*(max_deg + 1)); - memset(this_->bucket_list,0,sizeof(bucketnode *)*(max_deg + 1)); - assert(this_->bucket_list != NULL); - - /* insert nodes to the list */ - for(u=0;unum_nodes;u++) { - create_bucket(this_,u,this_->node_deg[u]); - } -} - -/***************************************************************************** - * PBQP simplification for trivial nodes - ****************************************************************************/ - -/* remove trivial node with cost vector length of one */ -static -void disconnect_trivialnode(pbqp *this_,int u) -{ - int v; - adjnode *adj_ptr, - *next; - PBQPMatrix *c_uv; - PBQPVector *c_v; - - assert(this_ != NULL); - assert(this_->node_costs != NULL); - assert(u >= 0 && u < this_ -> num_nodes); - assert(this_->node_costs[u]->getLength() == 1); - - /* add edge costs to node costs of adj. nodes */ - for(adj_ptr = this_->adj_list[u]; adj_ptr != NULL; adj_ptr = next){ - next = adj_ptr -> succ; - v = adj_ptr -> adj; - assert(v >= 0 && v < this_ -> num_nodes); - - /* convert matrix to cost vector offset for adj. node */ - c_uv = pbqp_get_costmatrix(this_,u,v); - c_v = new PBQPVector(c_uv->getRowAsVector(0)); - *this_->node_costs[v] += *c_v; - - /* delete edge & free vec/mat */ - delete c_v; - delete c_uv; - delete_edge(this_,u,v); - } -} - -/* find all trivial nodes and disconnect them */ -static -void eliminate_trivial_nodes(pbqp *this_) -{ - int u; - - assert(this_ != NULL); - assert(this_ -> node_costs != NULL); - - for(u=0;u < this_ -> num_nodes; u++) { - if (this_->node_costs[u]->getLength() == 1) { - disconnect_trivialnode(this_,u); - } - } -} - -/***************************************************************************** - * Normal form for PBQP - ****************************************************************************/ - -/* simplify a cost matrix. If the matrix - is independent, then simplify_matrix - returns true - otherwise false. In - vectors u and v the offset values of - the decomposition are stored. -*/ - -static -bool normalize_matrix(PBQPMatrix *m, PBQPVector *u, PBQPVector *v) -{ - assert( m != NULL); - assert( u != NULL); - assert( v != NULL); - assert( u->getLength() > 0); - assert( v->getLength() > 0); - - assert(m->getRows() == u->getLength()); - assert(m->getCols() == v->getLength()); - - /* determine u vector */ - for(unsigned r = 0; r < m->getRows(); ++r) { - PBQPNum min = m->getRowMin(r); - (*u)[r] += min; - if (!isInf(min)) { - m->subFromRow(r, min); - } else { - m->setRow(r, 0); - } - } - - /* determine v vector */ - for(unsigned c = 0; c < m->getCols(); ++c) { - PBQPNum min = m->getColMin(c); - (*v)[c] += min; - if (!isInf(min)) { - m->subFromCol(c, min); - } else { - m->setCol(c, 0); - } - } - - /* determine whether matrix is - independent or not. - */ - return m->isZero(); -} - -/* simplify single edge */ -static -void simplify_edge(pbqp *this_,int u,int v) -{ - PBQPMatrix *costs; - bool is_zero; - - assert (this_ != NULL); - assert (u >= 0 && u num_nodes); - assert (v >= 0 && v num_nodes); - assert (u != v); - - /* swap u and v if u > v in order to avoid un-necessary - tranpositions of the cost matrix */ - - if (u > v) { - int swap = u; - u = v; - v = swap; - } - - /* get cost matrix and simplify it */ - costs = get_costmatrix_ptr(this_,u,v); - is_zero=normalize_matrix(costs,this_->node_costs[u],this_->node_costs[v]); - - /* delete edge */ - if(is_zero){ - delete_edge(this_,u,v); - this_->changed = true; - } -} - -/* normalize cost matrices and remove - edges in PBQP if they ary independent, - i.e. can be decomposed into two - cost vectors. -*/ -static -void eliminate_independent_edges(pbqp *this_) -{ - int u,v; - adjnode *adj_ptr,*next; - - assert(this_ != NULL); - assert(this_ -> adj_list != NULL); - - this_->changed = false; - for(u=0;u < this_->num_nodes;u++) { - for (adj_ptr = this_ -> adj_list[u]; adj_ptr != NULL; adj_ptr = next) { - next = adj_ptr -> succ; - v = adj_ptr -> adj; - assert(v >= 0 && v < this_->num_nodes); - if (u < v) { - simplify_edge(this_,u,v); - } - } - } -} - - -/***************************************************************************** - * PBQP reduction rules - ****************************************************************************/ - -/* RI reduction - This reduction rule is applied for nodes - of degree one. */ - -static -void apply_RI(pbqp *this_,int x) -{ - int y; - unsigned xlen, - ylen; - PBQPMatrix *c_yx; - PBQPVector *c_x, *delta; - - assert(this_ != NULL); - assert(x >= 0 && x < this_->num_nodes); - assert(this_ -> adj_list[x] != NULL); - assert(this_ -> adj_list[x] -> succ == NULL); - - /* get adjacence matrix */ - y = this_ -> adj_list[x] -> adj; - assert(y >= 0 && y < this_->num_nodes); - - /* determine length of cost vectors for node x and y */ - xlen = this_ -> node_costs[x]->getLength(); - ylen = this_ -> node_costs[y]->getLength(); - - /* get cost vector c_x and matrix c_yx */ - c_x = this_ -> node_costs[x]; - c_yx = pbqp_get_costmatrix(this_,y,x); - assert (c_yx != NULL); - - - /* allocate delta vector */ - delta = new PBQPVector(ylen); - - /* compute delta vector */ - for(unsigned i = 0; i < ylen; ++i) { - PBQPNum min = (*c_yx)[i][0] + (*c_x)[0]; - for(unsigned j = 1; j < xlen; ++j) { - PBQPNum c = (*c_yx)[i][j] + (*c_x)[j]; - if ( c < min ) - min = c; - } - (*delta)[i] = min; - } - - /* add delta vector */ - *this_ -> node_costs[y] += *delta; - - /* delete node x */ - remove_node(this_,x); - - /* reorder adj. nodes of node x */ - reorder_adjnodes(this_,x); - - /* push node x on stack */ - assert(this_ -> stack_ptr < this_ -> num_nodes); - this_->stack[this_ -> stack_ptr++] = x; - - /* free vec/mat */ - delete c_yx; - delete delta; - - /* increment counter for number statistic */ - this_->num_ri++; -} - -/* RII reduction - This reduction rule is applied for nodes - of degree two. */ - -static -void apply_RII(pbqp *this_,int x) -{ - int y,z; - unsigned xlen,ylen,zlen; - adjnode *adj_yz; - - PBQPMatrix *c_yx, *c_zx; - PBQPVector *cx; - PBQPMatrix *delta; - - assert(this_ != NULL); - assert(x >= 0 && x < this_->num_nodes); - assert(this_ -> adj_list[x] != NULL); - assert(this_ -> adj_list[x] -> succ != NULL); - assert(this_ -> adj_list[x] -> succ -> succ == NULL); - - /* get adjacence matrix */ - y = this_ -> adj_list[x] -> adj; - z = this_ -> adj_list[x] -> succ -> adj; - assert(y >= 0 && y < this_->num_nodes); - assert(z >= 0 && z < this_->num_nodes); - - /* determine length of cost vectors for node x and y */ - xlen = this_ -> node_costs[x]->getLength(); - ylen = this_ -> node_costs[y]->getLength(); - zlen = this_ -> node_costs[z]->getLength(); - - /* get cost vector c_x and matrix c_yx */ - cx = this_ -> node_costs[x]; - c_yx = pbqp_get_costmatrix(this_,y,x); - c_zx = pbqp_get_costmatrix(this_,z,x); - assert(c_yx != NULL); - assert(c_zx != NULL); - - /* Colour Heuristic */ - if ( (adj_yz = find_adjnode(this_,y,z)) != NULL) { - adj_yz->tc_valid = false; - adj_yz->reverse->tc_valid = false; - } - - /* allocate delta matrix */ - delta = new PBQPMatrix(ylen, zlen); - - /* compute delta matrix */ - for(unsigned i=0;i stack_ptr < this_ -> num_nodes); - this_->stack[this_ -> stack_ptr++] = x; - - /* free vec/mat */ - delete c_yx; - delete c_zx; - delete delta; - - /* increment counter for number statistic */ - this_->num_rii++; - -} - -/* RN reduction */ -static -void apply_RN(pbqp *this_,int x) -{ - unsigned xlen; - - assert(this_ != NULL); - assert(x >= 0 && x < this_->num_nodes); - assert(this_ -> node_costs[x] != NULL); - - xlen = this_ -> node_costs[x] -> getLength(); - - /* after application of RN rule no optimality - can be guaranteed! */ - this_ -> optimal = false; - - /* push node x on stack */ - assert(this_ -> stack_ptr < this_ -> num_nodes); - this_->stack[this_ -> stack_ptr++] = x; - - /* delete node x */ - remove_node(this_,x); - - /* reorder adj. nodes of node x */ - reorder_adjnodes(this_,x); - - /* increment counter for number statistic */ - this_->num_rn++; -} - - -static -void compute_tc_info(pbqp *this_, adjnode *p) -{ - adjnode *r; - PBQPMatrix *m; - int x,y; - PBQPVector *c_x, *c_y; - int *row_inf_counts; - - assert(p->reverse != NULL); - - /* set flags */ - r = p->reverse; - p->tc_valid = true; - r->tc_valid = true; - - /* get edge */ - x = r->adj; - y = p->adj; - - /* get cost vectors */ - c_x = this_ -> node_costs[x]; - c_y = this_ -> node_costs[y]; - - /* get cost matrix */ - m = pbqp_get_costmatrix(this_, x, y); - - - /* allocate allowed set for edge (x,y) and (y,x) */ - if (p->tc_safe_regs == NULL) { - p->tc_safe_regs = (int *) malloc(sizeof(int) * c_x->getLength()); - } - - if (r->tc_safe_regs == NULL ) { - r->tc_safe_regs = (int *) malloc(sizeof(int) * c_y->getLength()); - } - - p->tc_impact = r->tc_impact = 0; - - row_inf_counts = (int *) alloca(sizeof(int) * c_x->getLength()); - - /* init arrays */ - p->tc_safe_regs[0] = 0; - row_inf_counts[0] = 0; - for(unsigned i = 1; i < c_x->getLength(); ++i){ - p->tc_safe_regs[i] = 1; - row_inf_counts[i] = 0; - } - - r->tc_safe_regs[0] = 0; - for(unsigned j = 1; j < c_y->getLength(); ++j){ - r->tc_safe_regs[j] = 1; - } - - for(unsigned j = 0; j < c_y->getLength(); ++j) { - int col_inf_counts = 0; - for (unsigned i = 0; i < c_x->getLength(); ++i) { - if (isInf((*m)[i][j])) { - ++col_inf_counts; - ++row_inf_counts[i]; - - p->tc_safe_regs[i] = 0; - r->tc_safe_regs[j] = 0; - } - } - if (col_inf_counts > p->tc_impact) { - p->tc_impact = col_inf_counts; - } - } - - for(unsigned i = 0; i < c_x->getLength(); ++i){ - if (row_inf_counts[i] > r->tc_impact) - { - r->tc_impact = row_inf_counts[i]; - } - } - - delete m; -} - -/* - * Checks whether node x can be locally coloured. - */ -static -int is_colorable(pbqp *this_,int x) -{ - adjnode *adj_ptr; - PBQPVector *c_x; - int result = 1; - int *allowed; - int num_allowed = 0; - unsigned total_impact = 0; - - assert(this_ != NULL); - assert(x >= 0 && x < this_->num_nodes); - assert(this_ -> node_costs[x] != NULL); - - c_x = this_ -> node_costs[x]; - - /* allocate allowed set */ - allowed = (int *)malloc(sizeof(int) * c_x->getLength()); - for(unsigned i = 0; i < c_x->getLength(); ++i){ - if (!isInf((*c_x)[i]) && i > 0) { - allowed[i] = 1; - ++num_allowed; - } else { - allowed[i] = 0; - } - } - - /* determine local minimum */ - for(adj_ptr=this_->adj_list[x] ;adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - if (!adj_ptr -> tc_valid) { - compute_tc_info(this_, adj_ptr); - } - - total_impact += adj_ptr->tc_impact; - - if (num_allowed > 0) { - for (unsigned i = 1; i < c_x->getLength(); ++i){ - if (allowed[i]){ - if (!adj_ptr->tc_safe_regs[i]){ - allowed[i] = 0; - --num_allowed; - if (num_allowed == 0) - break; - } - } - } - } - - if ( total_impact >= c_x->getLength() - 1 && num_allowed == 0 ) { - result = 0; - break; - } - } - free(allowed); - - return result; -} - -/* use briggs heuristic - note: this_ is not a general heuristic. it only is useful for - interference graphs. - */ -int pop_colorablenode(pbqp *this_) -{ - int deg; - bucketnode *min_bucket=NULL; - PBQPNum min = std::numeric_limits::infinity(); - - /* select node where the number of colors is less than the node degree */ - for(deg=this_->max_deg;deg > 2;deg--) { - bucketnode *bucket; - for(bucket=this_->bucket_list[deg];bucket!= NULL;bucket = bucket -> succ) { - int u = bucket->u; - if (is_colorable(this_,u)) { - pbqp_remove_bucket(this_,bucket); - this_->num_rn_special++; - free(bucket); - return u; - } - } - } - - /* select node with minimal ratio between average node costs and degree of node */ - for(deg=this_->max_deg;deg >2; deg--) { - bucketnode *bucket; - for(bucket=this_->bucket_list[deg];bucket!= NULL;bucket = bucket -> succ) { - PBQPNum h; - int u; - - u = bucket->u; - assert(u>=0 && u < this_->num_nodes); - h = (*this_->node_costs[u])[0] / (PBQPNum) deg; - if (h < min) { - min_bucket = bucket; - min = h; - } - } - } - - /* return node and free bucket */ - if (min_bucket != NULL) { - int u; - - pbqp_remove_bucket(this_,min_bucket); - u = min_bucket->u; - free(min_bucket); - return u; - } else { - return -1; - } -} - - -/***************************************************************************** - * PBQP graph parsing - ****************************************************************************/ - -/* reduce pbqp problem (first phase) */ -static -void reduce_pbqp(pbqp *this_) -{ - int u; - - assert(this_ != NULL); - assert(this_->bucket_list != NULL); - - for(;;){ - - if (this_->bucket_list[1] != NULL) { - u = pop_node(this_,1); - apply_RI(this_,u); - } else if (this_->bucket_list[2] != NULL) { - u = pop_node(this_,2); - apply_RII(this_,u); - } else if ((u = pop_colorablenode(this_)) != -1) { - apply_RN(this_,u); - } else { - break; - } - } -} - -/***************************************************************************** - * PBQP back propagation - ****************************************************************************/ - -/* determine solution of a reduced node. Either - RI or RII was applied for this_ node. */ -static -void determine_solution(pbqp *this_,int x) -{ - PBQPVector *v = new PBQPVector(*this_ -> node_costs[x]); - adjnode *adj_ptr; - - assert(this_ != NULL); - assert(x >= 0 && x < this_->num_nodes); - assert(this_ -> adj_list != NULL); - assert(this_ -> solution != NULL); - - for(adj_ptr=this_->adj_list[x] ;adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - int y = adj_ptr -> adj; - int y_sol = this_ -> solution[y]; - - PBQPMatrix *c_yx = pbqp_get_costmatrix(this_,y,x); - assert(y_sol >= 0 && y_sol < (int)this_->node_costs[y]->getLength()); - (*v) += c_yx->getRowAsVector(y_sol); - delete c_yx; - } - this_ -> solution[x] = v->minIndex(); - - delete v; -} - -/* back popagation phase of PBQP */ -static -void back_propagate(pbqp *this_) -{ - int i; - - assert(this_ != NULL); - assert(this_->stack != NULL); - assert(this_->stack_ptr < this_->num_nodes); - - for(i=this_ -> stack_ptr-1;i>=0;i--) { - int x = this_ -> stack[i]; - assert( x >= 0 && x < this_ -> num_nodes); - reinsert_node(this_,x); - determine_solution(this_,x); - } -} - -/* solve trivial nodes of degree zero */ -static -void determine_trivialsolution(pbqp *this_) -{ - int u; - PBQPNum delta; - - assert( this_ != NULL); - assert( this_ -> bucket_list != NULL); - - /* determine trivial solution */ - while (this_->bucket_list[0] != NULL) { - u = pop_node(this_,0); - - assert( u >= 0 && u < this_ -> num_nodes); - - this_->solution[u] = this_->node_costs[u]->minIndex(); - delta = (*this_->node_costs[u])[this_->solution[u]]; - this_->min = this_->min + delta; - - /* increment counter for number statistic */ - this_->num_r0++; - } -} - -/***************************************************************************** - * debug facilities - ****************************************************************************/ -static -void check_pbqp(pbqp *this_) -{ - int u,v; - PBQPMatrix *costs; - adjnode *adj_ptr; - - assert( this_ != NULL); - - for(u=0;u< this_->num_nodes; u++) { - assert (this_ -> node_costs[u] != NULL); - for(adj_ptr = this_ -> adj_list[u];adj_ptr != NULL; adj_ptr = adj_ptr -> succ) { - v = adj_ptr -> adj; - assert( v>= 0 && v < this_->num_nodes); - if (u < v ) { - costs = adj_ptr -> costs; - assert( costs->getRows() == this_->node_costs[u]->getLength() && - costs->getCols() == this_->node_costs[v]->getLength()); - } - } - } -} - -/***************************************************************************** - * PBQP solve routines - ****************************************************************************/ - -/* solve PBQP problem */ -void solve_pbqp(pbqp *this_) -{ - assert(this_ != NULL); - assert(!this_->solved); - - /* check vector & matrix dimensions */ - check_pbqp(this_); - - /* simplify PBQP problem */ - - /* eliminate trivial nodes, i.e. - nodes with cost vectors of length one. */ - eliminate_trivial_nodes(this_); - - /* eliminate edges with independent - cost matrices and normalize matrices */ - eliminate_independent_edges(this_); - - /* create bucket list for graph parsing */ - create_bucketlist(this_); - - /* reduce phase */ - reduce_pbqp(this_); - - /* solve trivial nodes */ - determine_trivialsolution(this_); - - /* back propagation phase */ - back_propagate(this_); - - this_->solved = true; -} - -/* get solution of a node */ -int get_pbqp_solution(pbqp *this_,int x) -{ - assert(this_ != NULL); - assert(this_->solution != NULL); - assert(this_ -> solved); - - return this_->solution[x]; -} - -/* is solution optimal? */ -bool is_pbqp_optimal(pbqp *this_) -{ - assert(this_ -> solved); - return this_->optimal; -} - -} - -/* end of pbqp.c */ diff --git a/lib/CodeGen/PBQP.h b/lib/CodeGen/PBQP.h deleted file mode 100644 index 5fd2c06c335..00000000000 --- a/lib/CodeGen/PBQP.h +++ /dev/null @@ -1,284 +0,0 @@ -//===---------------- PBQP.cpp --------- PBQP Solver ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Developed by: Bernhard Scholz -// The University of Sydney -// http://www.it.usyd.edu.au/~scholz -//===----------------------------------------------------------------------===// - -// TODO: -// -// * Default to null costs on vector initialisation? -// * C++-ify the rest of the solver. - -#ifndef LLVM_CODEGEN_PBQPSOLVER_H -#define LLVM_CODEGEN_PBQPSOLVER_H - -#include -#include -#include - -namespace llvm { - -//! \brief Floating point type to use in PBQP solver. -typedef double PBQPNum; - -//! \brief PBQP Vector class. -class PBQPVector { -public: - - //! \brief Construct a PBQP vector of the given size. - explicit PBQPVector(unsigned length) : - length(length), data(new PBQPNum[length]) { - std::fill(data, data + length, 0); - } - - //! \brief Copy construct a PBQP vector. - PBQPVector(const PBQPVector &v) : - length(v.length), data(new PBQPNum[length]) { - std::copy(v.data, v.data + length, data); - } - - ~PBQPVector() { delete[] data; } - - //! \brief Assignment operator. - PBQPVector& operator=(const PBQPVector &v) { - delete[] data; - length = v.length; - data = new PBQPNum[length]; - std::copy(v.data, v.data + length, data); - return *this; - } - - //! \brief Return the length of the vector - unsigned getLength() const throw () { - return length; - } - - //! \brief Element access. - PBQPNum& operator[](unsigned index) { - assert(index < length && "PBQPVector element access out of bounds."); - return data[index]; - } - - //! \brief Const element access. - const PBQPNum& operator[](unsigned index) const { - assert(index < length && "PBQPVector element access out of bounds."); - return data[index]; - } - - //! \brief Add another vector to this one. - PBQPVector& operator+=(const PBQPVector &v) { - assert(length == v.length && "PBQPVector length mismatch."); - std::transform(data, data + length, v.data, data, std::plus()); - return *this; - } - - //! \brief Subtract another vector from this one. - PBQPVector& operator-=(const PBQPVector &v) { - assert(length == v.length && "PBQPVector length mismatch."); - std::transform(data, data + length, v.data, data, std::minus()); - return *this; - } - - //! \brief Returns the index of the minimum value in this vector - unsigned minIndex() const { - return std::min_element(data, data + length) - data; - } - -private: - unsigned length; - PBQPNum *data; -}; - - -//! \brief PBQP Matrix class -class PBQPMatrix { -public: - - //! \brief Construct a PBQP Matrix with the given dimensions. - PBQPMatrix(unsigned rows, unsigned cols) : - rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { - std::fill(data, data + (rows * cols), 0); - } - - //! \brief Copy construct a PBQP matrix. - PBQPMatrix(const PBQPMatrix &m) : - rows(m.rows), cols(m.cols), data(new PBQPNum[rows * cols]) { - std::copy(m.data, m.data + (rows * cols), data); - } - - ~PBQPMatrix() { delete[] data; } - - //! \brief Assignment operator. - PBQPMatrix& operator=(const PBQPMatrix &m) { - delete[] data; - rows = m.rows; cols = m.cols; - data = new PBQPNum[rows * cols]; - std::copy(m.data, m.data + (rows * cols), data); - return *this; - } - - //! \brief Return the number of rows in this matrix. - unsigned getRows() const throw () { return rows; } - - //! \brief Return the number of cols in this matrix. - unsigned getCols() const throw () { return cols; } - - //! \brief Matrix element access. - PBQPNum* operator[](unsigned r) { - assert(r < rows && "Row out of bounds."); - return data + (r * cols); - } - - //! \brief Matrix element access. - const PBQPNum* operator[](unsigned r) const { - assert(r < rows && "Row out of bounds."); - return data + (r * cols); - } - - //! \brief Returns the given row as a vector. - PBQPVector getRowAsVector(unsigned r) const { - PBQPVector v(cols); - for (unsigned c = 0; c < cols; ++c) - v[c] = (*this)[r][c]; - return v; - } - - //! \brief Reset the matrix to the given value. - PBQPMatrix& reset(PBQPNum val = 0) { - std::fill(data, data + (rows * cols), val); - return *this; - } - - //! \brief Set a single row of this matrix to the given value. - PBQPMatrix& setRow(unsigned r, PBQPNum val) { - assert(r < rows && "Row out of bounds."); - std::fill(data + (r * cols), data + ((r + 1) * cols), val); - return *this; - } - - //! \brief Set a single column of this matrix to the given value. - PBQPMatrix& setCol(unsigned c, PBQPNum val) { - assert(c < cols && "Column out of bounds."); - for (unsigned r = 0; r < rows; ++r) - (*this)[r][c] = val; - return *this; - } - - //! \brief Matrix transpose. - PBQPMatrix transpose() const { - PBQPMatrix m(cols, rows); - for (unsigned r = 0; r < rows; ++r) - for (unsigned c = 0; c < cols; ++c) - m[c][r] = (*this)[r][c]; - return m; - } - - //! \brief Returns the diagonal of the matrix as a vector. - //! - //! Matrix must be square. - PBQPVector diagonalize() const { - assert(rows == cols && "Attempt to diagonalize non-square matrix."); - - PBQPVector v(rows); - for (unsigned r = 0; r < rows; ++r) - v[r] = (*this)[r][r]; - return v; - } - - //! \brief Add the given matrix to this one. - PBQPMatrix& operator+=(const PBQPMatrix &m) { - assert(rows == m.rows && cols == m.cols && - "Matrix dimensions mismatch."); - std::transform(data, data + (rows * cols), m.data, data, - std::plus()); - return *this; - } - - //! \brief Returns the minimum of the given row - PBQPNum getRowMin(unsigned r) const { - assert(r < rows && "Row out of bounds"); - return *std::min_element(data + (r * cols), data + ((r + 1) * cols)); - } - - //! \brief Returns the minimum of the given column - PBQPNum getColMin(unsigned c) const { - PBQPNum minElem = (*this)[0][c]; - for (unsigned r = 1; r < rows; ++r) - if ((*this)[r][c] < minElem) minElem = (*this)[r][c]; - return minElem; - } - - //! \brief Subtracts the given scalar from the elements of the given row. - PBQPMatrix& subFromRow(unsigned r, PBQPNum val) { - assert(r < rows && "Row out of bounds"); - std::transform(data + (r * cols), data + ((r + 1) * cols), - data + (r * cols), - std::bind2nd(std::minus(), val)); - return *this; - } - - //! \brief Subtracts the given scalar from the elements of the given column. - PBQPMatrix& subFromCol(unsigned c, PBQPNum val) { - for (unsigned r = 0; r < rows; ++r) - (*this)[r][c] -= val; - return *this; - } - - //! \brief Returns true if this is a zero matrix. - bool isZero() const { - return find_if(data, data + (rows * cols), - std::bind2nd(std::not_equal_to(), 0)) == - data + (rows * cols); - } - -private: - unsigned rows, cols; - PBQPNum *data; -}; - -#define EPS (1E-8) - -#ifndef PBQP_TYPE -#define PBQP_TYPE -struct pbqp; -typedef struct pbqp pbqp; -#endif - -/***************** - * PBQP routines * - *****************/ - -/* allocate pbqp problem */ -pbqp *alloc_pbqp(int num); - -/* add node costs */ -void add_pbqp_nodecosts(pbqp *this_,int u, PBQPVector *costs); - -/* add edge mat */ -void add_pbqp_edgecosts(pbqp *this_,int u,int v,PBQPMatrix *costs); - -/* solve PBQP problem */ -void solve_pbqp(pbqp *this_); - -/* get solution of a node */ -int get_pbqp_solution(pbqp *this_,int u); - -/* alloc PBQP */ -pbqp *alloc_pbqp(int num); - -/* free PBQP */ -void free_pbqp(pbqp *this_); - -/* is optimal */ -bool is_pbqp_optimal(pbqp *this_); - -} -#endif diff --git a/lib/CodeGen/PBQP/AnnotatedGraph.h b/lib/CodeGen/PBQP/AnnotatedGraph.h new file mode 100644 index 00000000000..801b01e3337 --- /dev/null +++ b/lib/CodeGen/PBQP/AnnotatedGraph.h @@ -0,0 +1,170 @@ +#ifndef LLVM_CODEGEN_PBQP_ANNOTATEDGRAPH_H +#define LLVM_CODEGEN_PBQP_ANNOTATEDGRAPH_H + +#include "GraphBase.h" + +namespace PBQP { + + +template class AnnotatedEdge; + +template +class AnnotatedNode : public NodeBase, + AnnotatedEdge > { +private: + + NodeData nodeData; + +public: + + AnnotatedNode(const Vector &costs, const NodeData &nodeData) : + NodeBase, + AnnotatedEdge >(costs), + nodeData(nodeData) {} + + NodeData& getNodeData() { return nodeData; } + const NodeData& getNodeData() const { return nodeData; } + +}; + +template +class AnnotatedEdge : public EdgeBase, + AnnotatedEdge > { +private: + + typedef typename GraphBase, + AnnotatedEdge >::NodeIterator + NodeIterator; + + EdgeData edgeData; + +public: + + + AnnotatedEdge(const NodeIterator &node1Itr, const NodeIterator &node2Itr, + const Matrix &costs, const EdgeData &edgeData) : + EdgeBase, + AnnotatedEdge >(node1Itr, node2Itr, costs), + edgeData(edgeData) {} + + EdgeData& getEdgeData() { return edgeData; } + const EdgeData& getEdgeData() const { return edgeData; } + +}; + +template +class AnnotatedGraph : public GraphBase, + AnnotatedEdge > { +private: + + typedef GraphBase, + AnnotatedEdge > PGraph; + + typedef AnnotatedNode NodeEntry; + typedef AnnotatedEdge EdgeEntry; + + + void copyFrom(const AnnotatedGraph &other) { + if (!other.areNodeIDsValid()) { + other.assignNodeIDs(); + } + std::vector newNodeItrs(other.getNumNodes()); + + for (ConstNodeIterator nItr = other.nodesBegin(), nEnd = other.nodesEnd(); + nItr != nEnd; ++nItr) { + newNodeItrs[other.getNodeID(nItr)] = addNode(other.getNodeCosts(nItr)); + } + + for (ConstEdgeIterator eItr = other.edgesBegin(), eEnd = other.edgesEnd(); + eItr != eEnd; ++eItr) { + + unsigned node1ID = other.getNodeID(other.getEdgeNode1(eItr)), + node2ID = other.getNodeID(other.getEdgeNode2(eItr)); + + addEdge(newNodeItrs[node1ID], newNodeItrs[node2ID], + other.getEdgeCosts(eItr), other.getEdgeData(eItr)); + } + + } + +public: + + typedef typename PGraph::NodeIterator NodeIterator; + typedef typename PGraph::ConstNodeIterator ConstNodeIterator; + typedef typename PGraph::EdgeIterator EdgeIterator; + typedef typename PGraph::ConstEdgeIterator ConstEdgeIterator; + + AnnotatedGraph() {} + + AnnotatedGraph(const AnnotatedGraph &other) { + copyFrom(other); + } + + AnnotatedGraph& operator=(const AnnotatedGraph &other) { + PGraph::clear(); + copyFrom(other); + return *this; + } + + NodeIterator addNode(const Vector &costs, const NodeData &data) { + return PGraph::addConstructedNode(NodeEntry(costs, data)); + } + + EdgeIterator addEdge(const NodeIterator &node1Itr, + const NodeIterator &node2Itr, + const Matrix &costs, const EdgeData &data) { + return PGraph::addConstructedEdge(EdgeEntry(node1Itr, node2Itr, + costs, data)); + } + + NodeData& getNodeData(const NodeIterator &nodeItr) { + return getNodeEntry(nodeItr).getNodeData(); + } + + const NodeData& getNodeData(const NodeIterator &nodeItr) const { + return getNodeEntry(nodeItr).getNodeData(); + } + + EdgeData& getEdgeData(const EdgeIterator &edgeItr) { + return getEdgeEntry(edgeItr).getEdgeData(); + } + + const EdgeEntry& getEdgeData(const EdgeIterator &edgeItr) const { + return getEdgeEntry(edgeItr).getEdgeData(); + } + + SimpleGraph toSimpleGraph() const { + SimpleGraph g; + + if (!PGraph::areNodeIDsValid()) { + PGraph::assignNodeIDs(); + } + std::vector newNodeItrs(PGraph::getNumNodes()); + + for (ConstNodeIterator nItr = PGraph::nodesBegin(), + nEnd = PGraph::nodesEnd(); + nItr != nEnd; ++nItr) { + + newNodeItrs[getNodeID(nItr)] = g.addNode(getNodeCosts(nItr)); + } + + for (ConstEdgeIterator + eItr = PGraph::edgesBegin(), eEnd = PGraph::edgesEnd(); + eItr != eEnd; ++eItr) { + + unsigned node1ID = getNodeID(getEdgeNode1(eItr)), + node2ID = getNodeID(getEdgeNode2(eItr)); + + g.addEdge(newNodeItrs[node1ID], newNodeItrs[node2ID], + getEdgeCosts(eItr)); + } + + return g; + } + +}; + + +} + +#endif // LLVM_CODEGEN_PBQP_ANNOTATEDGRAPH_H diff --git a/lib/CodeGen/PBQP/ExhaustiveSolver.h b/lib/CodeGen/PBQP/ExhaustiveSolver.h new file mode 100644 index 00000000000..98f7140ff09 --- /dev/null +++ b/lib/CodeGen/PBQP/ExhaustiveSolver.h @@ -0,0 +1,93 @@ +#ifndef LLVM_CODEGEN_PBQP_EXHAUSTIVESOLVER_H +#define LLVM_CODEGEN_PBQP_EXHAUSTIVESOLVER_H + +#include "Solver.h" + +namespace PBQP { + +class ExhaustiveSolverImpl { +private: + + const SimpleGraph &g; + + PBQPNum getSolutionCost(const Solution &solution) const { + PBQPNum cost = 0.0; + + for (SimpleGraph::ConstNodeIterator + nodeItr = g.nodesBegin(), nodeEnd = g.nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + + unsigned nodeId = g.getNodeID(nodeItr); + + cost += g.getNodeCosts(nodeItr)[solution.getSelection(nodeId)]; + } + + for (SimpleGraph::ConstEdgeIterator + edgeItr = g.edgesBegin(), edgeEnd = g.edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + + SimpleGraph::ConstNodeIterator n1 = g.getEdgeNode1Itr(edgeItr), + n2 = g.getEdgeNode2Itr(edgeItr); + unsigned sol1 = solution.getSelection(g.getNodeID(n1)), + sol2 = solution.getSelection(g.getNodeID(n2)); + + cost += g.getEdgeCosts(edgeItr)[sol1][sol2]; + } + + return cost; + } + +public: + + ExhaustiveSolverImpl(const SimpleGraph &g) : g(g) {} + + Solution solve() const { + Solution current(g.getNumNodes(), true), optimal(current); + + PBQPNum bestCost = std::numeric_limits::infinity(); + bool finished = false; + + while (!finished) { + PBQPNum currentCost = getSolutionCost(current); + + if (currentCost < bestCost) { + optimal = current; + bestCost = currentCost; + } + + // assume we're done. + finished = true; + + for (unsigned i = 0; i < g.getNumNodes(); ++i) { + if (current.getSelection(i) == + (g.getNodeCosts(g.getNodeItr(i)).getLength() - 1)) { + current.setSelection(i, 0); + } + else { + current.setSelection(i, current.getSelection(i) + 1); + finished = false; + break; + } + } + + } + + optimal.setSolutionCost(bestCost); + + return optimal; + } + +}; + +class ExhaustiveSolver : public Solver { +public: + ~ExhaustiveSolver() {} + Solution solve(const SimpleGraph &g) const { + ExhaustiveSolverImpl solver(g); + return solver.solve(); + } +}; + +} + +#endif // LLVM_CODGEN_PBQP_EXHAUSTIVESOLVER_HPP diff --git a/lib/CodeGen/PBQP/GraphBase.h b/lib/CodeGen/PBQP/GraphBase.h new file mode 100644 index 00000000000..bda5952e22a --- /dev/null +++ b/lib/CodeGen/PBQP/GraphBase.h @@ -0,0 +1,570 @@ +#ifndef LLVM_CODEGEN_PBQP_GRAPHBASE_H +#define LLVM_CODEGEN_PBQP_GRAPHBASE_H + +#include "PBQPMath.h" + +#include +#include + +namespace PBQP { + +// UGLY, but I'm not sure there's a good way around this: We need to be able to +// look up a Node's "adjacent edge list" structure type before the Node type is +// fully constructed. We can enable this by pushing the choice of data type +// out into this traits class. +template +class NodeBaseTraits { + public: + typedef std::list AdjEdgeList; + typedef typename AdjEdgeList::iterator AdjEdgeIterator; + typedef typename AdjEdgeList::const_iterator ConstAdjEdgeIterator; +}; + +/// \brief Base for concrete graph classes. Provides a basic set of graph +/// operations which are useful for PBQP solvers. +template +class GraphBase { +private: + + typedef GraphBase ThisGraphT; + + typedef std::list NodeList; + typedef std::list EdgeList; + + NodeList nodeList; + unsigned nodeListSize; + + EdgeList edgeList; + unsigned edgeListSize; + + GraphBase(const ThisGraphT &other) { abort(); } + void operator=(const ThisGraphT &other) { abort(); } + +public: + + /// \brief Iterates over the nodes of a graph. + typedef typename NodeList::iterator NodeIterator; + /// \brief Iterates over the nodes of a const graph. + typedef typename NodeList::const_iterator ConstNodeIterator; + /// \brief Iterates over the edges of a graph. + typedef typename EdgeList::iterator EdgeIterator; + /// \brief Iterates over the edges of a const graph. + typedef typename EdgeList::const_iterator ConstEdgeIterator; + + /// \brief Iterates over the edges attached to a node. + typedef typename NodeBaseTraits::AdjEdgeIterator + AdjEdgeIterator; + + /// \brief Iterates over the edges attached to a node in a const graph. + typedef typename NodeBaseTraits::ConstAdjEdgeIterator + ConstAdjEdgeIterator; + +private: + + typedef std::vector IDToNodeMap; + + IDToNodeMap idToNodeMap; + bool nodeIDsValid; + + void invalidateNodeIDs() { + if (nodeIDsValid) { + idToNodeMap.clear(); + nodeIDsValid = false; + } + } + + template + bool iteratorInRange(ItrT itr, const ItrT &begin, const ItrT &end) { + for (ItrT t = begin; t != end; ++t) { + if (itr == t) + return true; + } + + return false; + } + +protected: + + GraphBase() : nodeListSize(0), edgeListSize(0), nodeIDsValid(false) {} + + NodeEntry& getNodeEntry(const NodeIterator &nodeItr) { return *nodeItr; } + const NodeEntry& getNodeEntry(const ConstNodeIterator &nodeItr) const { + return *nodeItr; + } + + EdgeEntry& getEdgeEntry(const EdgeIterator &edgeItr) { return *edgeItr; } + const EdgeEntry& getEdgeEntry(const ConstEdgeIterator &edgeItr) const { + return *edgeItr; + } + + NodeIterator addConstructedNode(const NodeEntry &nodeEntry) { + ++nodeListSize; + + invalidateNodeIDs(); + + NodeIterator newNodeItr = nodeList.insert(nodeList.end(), nodeEntry); + + return newNodeItr; + } + + EdgeIterator addConstructedEdge(const EdgeEntry &edgeEntry) { + + assert((findEdge(edgeEntry.getNode1Itr(), edgeEntry.getNode2Itr()) + == edgeList.end()) && "Attempt to add duplicate edge."); + + ++edgeListSize; + + // Add the edge to the graph. + EdgeIterator edgeItr = edgeList.insert(edgeList.end(), edgeEntry); + + // Get a reference to the version in the graph. + EdgeEntry &newEdgeEntry = getEdgeEntry(edgeItr); + + // Node entries: + NodeEntry &node1Entry = getNodeEntry(newEdgeEntry.getNode1Itr()), + &node2Entry = getNodeEntry(newEdgeEntry.getNode2Itr()); + + unsigned n1Len = node1Entry.getCosts().getLength(), + n2Len = node2Entry.getCosts().getLength(), + mRows = newEdgeEntry.getCosts().getRows(), + mCols = newEdgeEntry.getCosts().getCols(); + + // Sanity check on matrix dimensions. + assert((n1Len == mRows) && (n2Len == mCols) && + "Matrix dimensions do not match cost vector dimensions."); + + // Create links between nodes and edges. + newEdgeEntry.setNode1ThisEdgeItr( + node1Entry.addAdjEdge(edgeItr)); + newEdgeEntry.setNode2ThisEdgeItr( + node2Entry.addAdjEdge(edgeItr)); + + return edgeItr; + } + +public: + + /// \brief Returns the number of nodes in this graph. + unsigned getNumNodes() const { return nodeListSize; } + + /// \brief Returns the number of edges in this graph. + unsigned getNumEdges() const { return edgeListSize; } + + /// \brief Return the cost vector for the given node. + Vector& getNodeCosts(const NodeIterator &nodeItr) { + return getNodeEntry(nodeItr).getCosts(); + } + + /// \brief Return the cost vector for the give node. + const Vector& getNodeCosts(const ConstNodeIterator &nodeItr) const { + return getNodeEntry(nodeItr).getCosts(); + } + + /// \brief Return the degree of the given node. + unsigned getNodeDegree(const NodeIterator &nodeItr) const { + return getNodeEntry(nodeItr).getDegree(); + } + + /// \brief Assigns sequential IDs to the nodes, starting at 0, which + /// remain valid until the next addition or removal of a node. + void assignNodeIDs() { + unsigned curID = 0; + idToNodeMap.resize(getNumNodes()); + for (NodeIterator nodeItr = nodesBegin(), nodeEnd = nodesEnd(); + nodeItr != nodeEnd; ++nodeItr, ++curID) { + getNodeEntry(nodeItr).setID(curID); + idToNodeMap[curID] = nodeItr; + } + nodeIDsValid = true; + } + + /// \brief Assigns sequential IDs to the nodes using the ordering of the + /// given vector. + void assignNodeIDs(const std::vector &nodeOrdering) { + assert((getNumNodes() == nodeOrdering.size()) && + "Wrong number of nodes in node ordering."); + idToNodeMap = nodeOrdering; + for (unsigned nodeID = 0; nodeID < idToNodeMap.size(); ++nodeID) { + getNodeEntry(idToNodeMap[nodeID]).setID(nodeID); + } + nodeIDsValid = true; + } + + /// \brief Returns true if valid node IDs are assigned, false otherwise. + bool areNodeIDsValid() const { return nodeIDsValid; } + + /// \brief Return the numeric ID of the given node. + /// + /// Calls to this method will result in an assertion failure if there have + /// been any node additions or removals since the last call to + /// assignNodeIDs(). + unsigned getNodeID(const ConstNodeIterator &nodeItr) const { + assert(nodeIDsValid && "Attempt to retrieve invalid ID."); + return getNodeEntry(nodeItr).getID(); + } + + /// \brief Returns the iterator associated with the given node ID. + NodeIterator getNodeItr(unsigned nodeID) { + assert(nodeIDsValid && "Attempt to retrieve iterator with invalid ID."); + return idToNodeMap[nodeID]; + } + + /// \brief Returns the iterator associated with the given node ID. + ConstNodeIterator getNodeItr(unsigned nodeID) const { + assert(nodeIDsValid && "Attempt to retrieve iterator with invalid ID."); + return idToNodeMap[nodeID]; + } + + /// \brief Removes the given node (and all attached edges) from the graph. + void removeNode(const NodeIterator &nodeItr) { + assert(iteratorInRange(nodeItr, nodeList.begin(), nodeList.end()) && + "Iterator does not belong to this graph!"); + + invalidateNodeIDs(); + + NodeEntry &nodeEntry = getNodeEntry(nodeItr); + + // We need to copy this out because it will be destroyed as the edges are + // removed. + typedef std::vector AdjEdgeList; + typedef typename AdjEdgeList::iterator AdjEdgeListItr; + + AdjEdgeList adjEdges; + adjEdges.reserve(nodeEntry.getDegree()); + std::copy(nodeEntry.adjEdgesBegin(), nodeEntry.adjEdgesEnd(), + std::back_inserter(adjEdges)); + + // Iterate over the copied out edges and remove them from the graph. + for (AdjEdgeListItr itr = adjEdges.begin(), end = adjEdges.end(); + itr != end; ++itr) { + removeEdge(*itr); + } + + // Erase the node from the nodelist. + nodeList.erase(nodeItr); + --nodeListSize; + } + + NodeIterator nodesBegin() { return nodeList.begin(); } + ConstNodeIterator nodesBegin() const { return nodeList.begin(); } + NodeIterator nodesEnd() { return nodeList.end(); } + ConstNodeIterator nodesEnd() const { return nodeList.end(); } + + AdjEdgeIterator adjEdgesBegin(const NodeIterator &nodeItr) { + return getNodeEntry(nodeItr).adjEdgesBegin(); + } + + ConstAdjEdgeIterator adjEdgesBegin(const ConstNodeIterator &nodeItr) const { + return getNodeEntry(nodeItr).adjEdgesBegin(); + } + + AdjEdgeIterator adjEdgesEnd(const NodeIterator &nodeItr) { + return getNodeEntry(nodeItr).adjEdgesEnd(); + } + + ConstAdjEdgeIterator adjEdgesEnd(const ConstNodeIterator &nodeItr) const { + getNodeEntry(nodeItr).adjEdgesEnd(); + } + + EdgeIterator findEdge(const NodeIterator &node1Itr, + const NodeIterator &node2Itr) { + + for (AdjEdgeIterator adjEdgeItr = adjEdgesBegin(node1Itr), + adjEdgeEnd = adjEdgesEnd(node1Itr); + adjEdgeItr != adjEdgeEnd; ++adjEdgeItr) { + if ((getEdgeNode1Itr(*adjEdgeItr) == node2Itr) || + (getEdgeNode2Itr(*adjEdgeItr) == node2Itr)) { + return *adjEdgeItr; + } + } + + return edgeList.end(); + } + + ConstEdgeIterator findEdge(const ConstNodeIterator &node1Itr, + const ConstNodeIterator &node2Itr) const { + + for (ConstAdjEdgeIterator adjEdgeItr = adjEdgesBegin(node1Itr), + adjEdgeEnd = adjEdgesEnd(node1Itr); + adjEdgeItr != adjEdgesEnd; ++adjEdgeItr) { + if ((getEdgeNode1Itr(*adjEdgeItr) == node2Itr) || + (getEdgeNode2Itr(*adjEdgeItr) == node2Itr)) { + return *adjEdgeItr; + } + } + + return edgeList.end(); + } + + Matrix& getEdgeCosts(const EdgeIterator &edgeItr) { + return getEdgeEntry(edgeItr).getCosts(); + } + + const Matrix& getEdgeCosts(const ConstEdgeIterator &edgeItr) const { + return getEdgeEntry(edgeItr).getCosts(); + } + + NodeIterator getEdgeNode1Itr(const EdgeIterator &edgeItr) { + return getEdgeEntry(edgeItr).getNode1Itr(); + } + + ConstNodeIterator getEdgeNode1Itr(const ConstEdgeIterator &edgeItr) const { + return getEdgeEntry(edgeItr).getNode1Itr(); + } + + NodeIterator getEdgeNode2Itr(const EdgeIterator &edgeItr) { + return getEdgeEntry(edgeItr).getNode2Itr(); + } + + ConstNodeIterator getEdgeNode2Itr(const ConstEdgeIterator &edgeItr) const { + return getEdgeEntry(edgeItr).getNode2Itr(); + } + + NodeIterator getEdgeOtherNode(const EdgeIterator &edgeItr, + const NodeIterator &nodeItr) { + + EdgeEntry &edgeEntry = getEdgeEntry(edgeItr); + if (nodeItr == edgeEntry.getNode1Itr()) { + return edgeEntry.getNode2Itr(); + } + //else + return edgeEntry.getNode1Itr(); + } + + ConstNodeIterator getEdgeOtherNode(const ConstEdgeIterator &edgeItr, + const ConstNodeIterator &nodeItr) const { + + const EdgeEntry &edgeEntry = getEdgeEntry(edgeItr); + if (nodeItr == edgeEntry.getNode1Itr()) { + return edgeEntry.getNode2Itr(); + } + //else + return edgeEntry.getNode1Itr(); + } + + void removeEdge(const EdgeIterator &edgeItr) { + assert(iteratorInRange(edgeItr, edgeList.begin(), edgeList.end()) && + "Iterator does not belong to this graph!"); + + --edgeListSize; + + // Get the edge entry. + EdgeEntry &edgeEntry = getEdgeEntry(edgeItr); + + // Get the nodes entry. + NodeEntry &node1Entry(getNodeEntry(edgeEntry.getNode1Itr())), + &node2Entry(getNodeEntry(edgeEntry.getNode2Itr())); + + // Disconnect the edge from the nodes. + node1Entry.removeAdjEdge(edgeEntry.getNode1ThisEdgeItr()); + node2Entry.removeAdjEdge(edgeEntry.getNode2ThisEdgeItr()); + + // Remove the edge from the graph. + edgeList.erase(edgeItr); + } + + EdgeIterator edgesBegin() { return edgeList.begin(); } + ConstEdgeIterator edgesBegin() const { return edgeList.begin(); } + EdgeIterator edgesEnd() { return edgeList.end(); } + ConstEdgeIterator edgesEnd() const { return edgeList.end(); } + + void clear() { + nodeList.clear(); + nodeListSize = 0; + edgeList.clear(); + edgeListSize = 0; + idToNodeMap.clear(); + } + + template + void printDot(OStream &os) const { + + assert(areNodeIDsValid() && + "Cannot print a .dot of a graph unless IDs have been assigned."); + + os << "graph {\n"; + + for (ConstNodeIterator nodeItr = nodesBegin(), nodeEnd = nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + + os << " node" << getNodeID(nodeItr) << " [ label=\"" + << getNodeID(nodeItr) << ": " << getNodeCosts(nodeItr) << "\" ]\n"; + } + + os << " edge [ len=" << getNumNodes() << " ]\n"; + + for (ConstEdgeIterator edgeItr = edgesBegin(), edgeEnd = edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + + os << " node" << getNodeID(getEdgeNode1Itr(edgeItr)) + << " -- node" << getNodeID(getEdgeNode2Itr(edgeItr)) + << " [ label=\""; + + const Matrix &edgeCosts = getEdgeCosts(edgeItr); + + for (unsigned i = 0; i < edgeCosts.getRows(); ++i) { + os << edgeCosts.getRowAsVector(i) << "\\n"; + } + + os << "\" ]\n"; + } + + os << "}\n"; + } + + template + void printDot(OStream &os) { + if (!areNodeIDsValid()) { + assignNodeIDs(); + } + + const_cast(this)->printDot(os); + } + + template + void dumpTo(OStream &os) const { + typedef ConstNodeIterator ConstNodeID; + + assert(areNodeIDsValid() && + "Cannot dump a graph unless IDs have been assigned."); + + for (ConstNodeIterator nItr = nodesBegin(), nEnd = nodesEnd(); + nItr != nEnd; ++nItr) { + os << getNodeID(nItr) << "\n"; + } + + unsigned edgeNumber = 1; + for (ConstEdgeIterator eItr = edgesBegin(), eEnd = edgesEnd(); + eItr != eEnd; ++eItr) { + + os << edgeNumber++ << ": { " + << getNodeID(getEdgeNode1Itr(eItr)) << ", " + << getNodeID(getEdgeNode2Itr(eItr)) << " }\n"; + } + + } + + template + void dumpTo(OStream &os) { + if (!areNodeIDsValid()) { + assignNodeIDs(); + } + + const_cast(this)->dumpTo(os); + } + +}; + +/// \brief Provides a base from which to derive nodes for GraphBase. +template +class NodeBase { +private: + + typedef GraphBase GraphBaseT; + typedef NodeBaseTraits ThisNodeBaseTraits; + +public: + typedef typename GraphBaseT::EdgeIterator EdgeIterator; + +private: + typedef typename ThisNodeBaseTraits::AdjEdgeList AdjEdgeList; + + unsigned degree, id; + Vector costs; + AdjEdgeList adjEdges; + + void operator=(const NodeBase& other) { + assert(false && "Can't assign NodeEntrys."); + } + +public: + + typedef typename ThisNodeBaseTraits::AdjEdgeIterator AdjEdgeIterator; + typedef typename ThisNodeBaseTraits::ConstAdjEdgeIterator + ConstAdjEdgeIterator; + + NodeBase(const Vector &costs) : degree(0), costs(costs) { + assert((costs.getLength() > 0) && "Can't have zero-length cost vector."); + } + + Vector& getCosts() { return costs; } + const Vector& getCosts() const { return costs; } + + unsigned getDegree() const { return degree; } + + void setID(unsigned id) { this->id = id; } + unsigned getID() const { return id; } + + AdjEdgeIterator addAdjEdge(const EdgeIterator &edgeItr) { + ++degree; + return adjEdges.insert(adjEdges.end(), edgeItr); + } + + void removeAdjEdge(const AdjEdgeIterator &adjEdgeItr) { + --degree; + adjEdges.erase(adjEdgeItr); + } + + AdjEdgeIterator adjEdgesBegin() { return adjEdges.begin(); } + ConstAdjEdgeIterator adjEdgesBegin() const { return adjEdges.begin(); } + AdjEdgeIterator adjEdgesEnd() { return adjEdges.end(); } + ConstAdjEdgeIterator adjEdgesEnd() const { return adjEdges.end(); } + +}; + +template +class EdgeBase { +public: + typedef typename GraphBase::NodeIterator NodeIterator; + typedef typename GraphBase::EdgeIterator EdgeIterator; + + typedef typename NodeImpl::AdjEdgeIterator NodeAdjEdgeIterator; + +private: + + NodeIterator node1Itr, node2Itr; + NodeAdjEdgeIterator node1ThisEdgeItr, node2ThisEdgeItr; + Matrix costs; + + void operator=(const EdgeBase &other) { + assert(false && "Can't assign EdgeEntrys."); + } + +public: + + EdgeBase(const NodeIterator &node1Itr, const NodeIterator &node2Itr, + const Matrix &costs) : + node1Itr(node1Itr), node2Itr(node2Itr), costs(costs) { + + assert((costs.getRows() > 0) && (costs.getCols() > 0) && + "Can't have zero-dimensioned cost matrices"); + } + + Matrix& getCosts() { return costs; } + const Matrix& getCosts() const { return costs; } + + const NodeIterator& getNode1Itr() const { return node1Itr; } + const NodeIterator& getNode2Itr() const { return node2Itr; } + + void setNode1ThisEdgeItr(const NodeAdjEdgeIterator &node1ThisEdgeItr) { + this->node1ThisEdgeItr = node1ThisEdgeItr; + } + + const NodeAdjEdgeIterator& getNode1ThisEdgeItr() const { + return node1ThisEdgeItr; + } + + void setNode2ThisEdgeItr(const NodeAdjEdgeIterator &node2ThisEdgeItr) { + this->node2ThisEdgeItr = node2ThisEdgeItr; + } + + const NodeAdjEdgeIterator& getNode2ThisEdgeItr() const { + return node2ThisEdgeItr; + } + +}; + + +} + +#endif // LLVM_CODEGEN_PBQP_GRAPHBASE_HPP diff --git a/lib/CodeGen/PBQP/GraphGenerator.h b/lib/CodeGen/PBQP/GraphGenerator.h new file mode 100644 index 00000000000..620e21e2762 --- /dev/null +++ b/lib/CodeGen/PBQP/GraphGenerator.h @@ -0,0 +1,195 @@ +#ifndef LLVM_CODEGEN_PBQP_GRAPHGENERATOR_H +#define LLVM_CODEGEN_PBQP_GRAPHGENERATOR_H + +#include "PBQPMath.h" + +namespace PBQP { + +unsigned randRange(unsigned min, unsigned max) { + return min + (rand() % (max - min + 1)); +} + +class BasicNodeCostsGenerator { +private: + + unsigned maxDegree, minCost, maxCost; + + +public: + + BasicNodeCostsGenerator(unsigned maxDegree, unsigned minCost, + unsigned maxCost) : + maxDegree(maxDegree), minCost(minCost), maxCost(maxCost) { } + + Vector operator()() const { + Vector v(randRange(1, maxDegree)); + for (unsigned i = 0; i < v.getLength(); ++i) { + v[i] = randRange(minCost, maxCost); + } + return v; + }; + +}; + +class FixedDegreeSpillCostGenerator { +private: + + unsigned degree, spillCostMin, spillCostMax; + +public: + + FixedDegreeSpillCostGenerator(unsigned degree, unsigned spillCostMin, + unsigned spillCostMax) : + degree(degree), spillCostMin(spillCostMin), spillCostMax(spillCostMax) { } + + Vector operator()() const { + Vector v(degree, 0); + v[0] = randRange(spillCostMin, spillCostMax); + return v; + } + +}; + +class BasicEdgeCostsGenerator { +private: + + unsigned minCost, maxCost; + +public: + + BasicEdgeCostsGenerator(unsigned minCost, unsigned maxCost) : + minCost(minCost), maxCost(maxCost) {} + + Matrix operator()(const SimpleGraph &g, + const SimpleGraph::ConstNodeIterator &n1, + const SimpleGraph::ConstNodeIterator &n2) const { + + Matrix m(g.getNodeCosts(n1).getLength(), + g.getNodeCosts(n2).getLength()); + + for (unsigned i = 0; i < m.getRows(); ++i) { + for (unsigned j = 0; j < m.getCols(); ++j) { + m[i][j] = randRange(minCost, maxCost); + } + } + + return m; + } + +}; + +class InterferenceCostsGenerator { +public: + + Matrix operator()(const SimpleGraph &g, + const SimpleGraph::ConstNodeIterator &n1, + const SimpleGraph::ConstNodeIterator &n2) const { + + unsigned len = g.getNodeCosts(n1).getLength(); + + assert(len == g.getNodeCosts(n2).getLength()); + + Matrix m(len, len); + + m[0][0] = 0; + for (unsigned i = 1; i < len; ++i) { + m[i][i] = std::numeric_limits::infinity(); + } + + return m; + } +}; + +class RingEdgeGenerator { +public: + + template + void operator()(SimpleGraph &g, EdgeCostsGenerator &edgeCostsGen) { + + assert(g.areNodeIDsValid() && "Graph must have valid node IDs."); + + if (g.getNumNodes() < 2) + return; + + if (g.getNumNodes() == 2) { + SimpleGraph::NodeIterator n1 = g.getNodeItr(0), + n2 = g.getNodeItr(1); + g.addEdge(n1, n2, edgeCostsGen(g, n1, n2)); + return; + } + + // Else |V| > 2: + for (unsigned i = 0; i < g.getNumNodes(); ++i) { + SimpleGraph::NodeIterator + n1 = g.getNodeItr(i), + n2 = g.getNodeItr((i + 1) % g.getNumNodes()); + g.addEdge(n1, n2, edgeCostsGen(g, n1, n2)); + } + } + +}; + +class FullyConnectedEdgeGenerator { +public: + + template + void operator()(SimpleGraph &g, EdgeCostsGenerator &edgeCostsGen) { + assert(g.areNodeIDsValid() && "Graph must have valid node IDs."); + + for (unsigned i = 0; i < g.getNumNodes(); ++i) { + for (unsigned j = i + 1; j < g.getNumNodes(); ++j) { + SimpleGraph::NodeIterator + n1 = g.getNodeItr(i), + n2 = g.getNodeItr(j); + g.addEdge(n1, n2, edgeCostsGen(g, n1, n2)); + } + } + } + +}; + +class RandomEdgeGenerator { +public: + + template + void operator()(SimpleGraph &g, EdgeCostsGenerator &edgeCostsGen) { + + assert(g.areNodeIDsValid() && "Graph must have valid node IDs."); + + for (unsigned i = 0; i < g.getNumNodes(); ++i) { + for (unsigned j = i + 1; j < g.getNumNodes(); ++j) { + if (rand() % 2 == 0) { + SimpleGraph::NodeIterator + n1 = g.getNodeItr(i), + n2 = g.getNodeItr(j); + g.addEdge(n1, n2, edgeCostsGen(g, n1, n2)); + } + } + } + } + +}; + +template +SimpleGraph createRandomGraph(unsigned numNodes, + NodeCostsGenerator nodeCostsGen, + EdgesGenerator edgeGen, + EdgeCostsGenerator edgeCostsGen) { + + SimpleGraph g; + for (unsigned n = 0; n < numNodes; ++n) { + g.addNode(nodeCostsGen()); + } + + g.assignNodeIDs(); + + edgeGen(g, edgeCostsGen); + + return g; +} + +} + +#endif // LLVM_CODEGEN_PBQP_GRAPHGENERATOR_H diff --git a/lib/CodeGen/PBQP/HeuristicSolver.h b/lib/CodeGen/PBQP/HeuristicSolver.h new file mode 100644 index 00000000000..7088f364568 --- /dev/null +++ b/lib/CodeGen/PBQP/HeuristicSolver.h @@ -0,0 +1,799 @@ +#ifndef LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H +#define LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H + +#include "Solver.h" +#include "AnnotatedGraph.h" + +#include +#include + +namespace PBQP { + +/// \brief Important types for the HeuristicSolverImpl. +/// +/// Declared seperately to allow access to heuristic classes before the solver +/// is fully constructed. +template +class HSITypes { +public: + + class NodeData; + class EdgeData; + + typedef AnnotatedGraph SolverGraph; + typedef typename SolverGraph::NodeIterator GraphNodeIterator; + typedef typename SolverGraph::EdgeIterator GraphEdgeIterator; + typedef typename SolverGraph::AdjEdgeIterator GraphAdjEdgeIterator; + + typedef std::list NodeList; + typedef typename NodeList::iterator NodeListIterator; + + typedef std::vector NodeStack; + typedef typename NodeStack::iterator NodeStackIterator; + + class NodeData { + friend class EdgeData; + + private: + + typedef std::list LinksList; + + unsigned numLinks; + LinksList links, solvedLinks; + NodeListIterator bucketItr; + HeuristicNodeData heuristicData; + + public: + + typedef typename LinksList::iterator AdjLinkIterator; + + private: + + AdjLinkIterator addLink(const GraphEdgeIterator &edgeItr) { + ++numLinks; + return links.insert(links.end(), edgeItr); + } + + void delLink(const AdjLinkIterator &adjLinkItr) { + --numLinks; + links.erase(adjLinkItr); + } + + public: + + NodeData() : numLinks(0) {} + + unsigned getLinkDegree() const { return numLinks; } + + HeuristicNodeData& getHeuristicData() { return heuristicData; } + const HeuristicNodeData& getHeuristicData() const { + return heuristicData; + } + + void setBucketItr(const NodeListIterator &bucketItr) { + this->bucketItr = bucketItr; + } + + const NodeListIterator& getBucketItr() const { + return bucketItr; + } + + AdjLinkIterator adjLinksBegin() { + return links.begin(); + } + + AdjLinkIterator adjLinksEnd() { + return links.end(); + } + + void addSolvedLink(const GraphEdgeIterator &solvedLinkItr) { + solvedLinks.push_back(solvedLinkItr); + } + + AdjLinkIterator solvedLinksBegin() { + return solvedLinks.begin(); + } + + AdjLinkIterator solvedLinksEnd() { + return solvedLinks.end(); + } + + }; + + class EdgeData { + private: + + SolverGraph &g; + GraphNodeIterator node1Itr, node2Itr; + HeuristicEdgeData heuristicData; + typename NodeData::AdjLinkIterator node1ThisEdgeItr, node2ThisEdgeItr; + + public: + + EdgeData(SolverGraph &g) : g(g) {} + + HeuristicEdgeData& getHeuristicData() { return heuristicData; } + const HeuristicEdgeData& getHeuristicData() const { + return heuristicData; + } + + void setup(const GraphEdgeIterator &thisEdgeItr) { + node1Itr = g.getEdgeNode1Itr(thisEdgeItr); + node2Itr = g.getEdgeNode2Itr(thisEdgeItr); + + node1ThisEdgeItr = g.getNodeData(node1Itr).addLink(thisEdgeItr); + node2ThisEdgeItr = g.getNodeData(node2Itr).addLink(thisEdgeItr); + } + + void unlink() { + g.getNodeData(node1Itr).delLink(node1ThisEdgeItr); + g.getNodeData(node2Itr).delLink(node2ThisEdgeItr); + } + + }; + +}; + +template +class HeuristicSolverImpl { +public: + // Typedefs to make life easier: + typedef HSITypes HSIT; + typedef typename HSIT::SolverGraph SolverGraph; + typedef typename HSIT::NodeData NodeData; + typedef typename HSIT::EdgeData EdgeData; + typedef typename HSIT::GraphNodeIterator GraphNodeIterator; + typedef typename HSIT::GraphEdgeIterator GraphEdgeIterator; + typedef typename HSIT::GraphAdjEdgeIterator GraphAdjEdgeIterator; + + typedef typename HSIT::NodeList NodeList; + typedef typename HSIT::NodeListIterator NodeListIterator; + + typedef std::vector NodeStack; + typedef typename NodeStack::iterator NodeStackIterator; + + /*! + * \brief Constructor, which performs all the actual solver work. + */ + HeuristicSolverImpl(const SimpleGraph &orig) : + solution(orig.getNumNodes(), true) + { + copyGraph(orig); + simplify(); + setup(); + computeSolution(); + computeSolutionCost(orig); + } + + /*! + * \brief Returns the graph for this solver. + */ + SolverGraph& getGraph() { return g; } + + /*! + * \brief Return the solution found by this solver. + */ + const Solution& getSolution() const { return solution; } + +private: + + /*! + * \brief Add the given node to the appropriate bucket for its link + * degree. + */ + void addToBucket(const GraphNodeIterator &nodeItr) { + NodeData &nodeData = g.getNodeData(nodeItr); + + switch (nodeData.getLinkDegree()) { + case 0: nodeData.setBucketItr( + r0Bucket.insert(r0Bucket.end(), nodeItr)); + break; + case 1: nodeData.setBucketItr( + r1Bucket.insert(r1Bucket.end(), nodeItr)); + break; + case 2: nodeData.setBucketItr( + r2Bucket.insert(r2Bucket.end(), nodeItr)); + break; + default: heuristic.addToRNBucket(nodeItr); + break; + } + } + + /*! + * \brief Remove the given node from the appropriate bucket for its link + * degree. + */ + void removeFromBucket(const GraphNodeIterator &nodeItr) { + NodeData &nodeData = g.getNodeData(nodeItr); + + switch (nodeData.getLinkDegree()) { + case 0: r0Bucket.erase(nodeData.getBucketItr()); break; + case 1: r1Bucket.erase(nodeData.getBucketItr()); break; + case 2: r2Bucket.erase(nodeData.getBucketItr()); break; + default: heuristic.removeFromRNBucket(nodeItr); break; + } + } + +public: + + /*! + * \brief Add a link. + */ + void addLink(const GraphEdgeIterator &edgeItr) { + g.getEdgeData(edgeItr).setup(edgeItr); + + if ((g.getNodeData(g.getEdgeNode1Itr(edgeItr)).getLinkDegree() > 2) || + (g.getNodeData(g.getEdgeNode2Itr(edgeItr)).getLinkDegree() > 2)) { + heuristic.handleAddLink(edgeItr); + } + } + + /*! + * \brief Remove link, update info for node. + * + * Only updates information for the given node, since usually the other + * is about to be removed. + */ + void removeLink(const GraphEdgeIterator &edgeItr, + const GraphNodeIterator &nodeItr) { + + if (g.getNodeData(nodeItr).getLinkDegree() > 2) { + heuristic.handleRemoveLink(edgeItr, nodeItr); + } + g.getEdgeData(edgeItr).unlink(); + } + + /*! + * \brief Remove link, update info for both nodes. Useful for R2 only. + */ + void removeLinkR2(const GraphEdgeIterator &edgeItr) { + GraphNodeIterator node1Itr = g.getEdgeNode1Itr(edgeItr); + + if (g.getNodeData(node1Itr).getLinkDegree() > 2) { + heuristic.handleRemoveLink(edgeItr, node1Itr); + } + removeLink(edgeItr, g.getEdgeNode2Itr(edgeItr)); + } + + /*! + * \brief Removes all links connected to the given node. + */ + void unlinkNode(const GraphNodeIterator &nodeItr) { + NodeData &nodeData = g.getNodeData(nodeItr); + + typedef std::vector TempEdgeList; + + TempEdgeList edgesToUnlink; + edgesToUnlink.reserve(nodeData.getLinkDegree()); + + // Copy adj edges into a temp vector. We want to destroy them during + // the unlink, and we can't do that while we're iterating over them. + std::copy(nodeData.adjLinksBegin(), nodeData.adjLinksEnd(), + std::back_inserter(edgesToUnlink)); + + for (typename TempEdgeList::iterator + edgeItr = edgesToUnlink.begin(), edgeEnd = edgesToUnlink.end(); + edgeItr != edgeEnd; ++edgeItr) { + + GraphNodeIterator otherNode = g.getEdgeOtherNode(*edgeItr, nodeItr); + + removeFromBucket(otherNode); + removeLink(*edgeItr, otherNode); + addToBucket(otherNode); + } + } + + /*! + * \brief Push the given node onto the stack to be solved with + * backpropagation. + */ + void pushStack(const GraphNodeIterator &nodeItr) { + stack.push_back(nodeItr); + } + + /*! + * \brief Set the solution of the given node. + */ + void setSolution(const GraphNodeIterator &nodeItr, unsigned solIndex) { + solution.setSelection(g.getNodeID(nodeItr), solIndex); + + for (GraphAdjEdgeIterator adjEdgeItr = g.adjEdgesBegin(nodeItr), + adjEdgeEnd = g.adjEdgesEnd(nodeItr); + adjEdgeItr != adjEdgeEnd; ++adjEdgeItr) { + GraphEdgeIterator edgeItr(*adjEdgeItr); + GraphNodeIterator adjNodeItr(g.getEdgeOtherNode(edgeItr, nodeItr)); + g.getNodeData(adjNodeItr).addSolvedLink(edgeItr); + } + } + +private: + + SolverGraph g; + Heuristic heuristic; + Solution solution; + + NodeList r0Bucket, + r1Bucket, + r2Bucket; + + NodeStack stack; + + // Copy the SimpleGraph into an annotated graph which we can use for reduction. + void copyGraph(const SimpleGraph &orig) { + + assert((g.getNumEdges() == 0) && (g.getNumNodes() == 0) && + "Graph should be empty prior to solver setup."); + + assert(orig.areNodeIDsValid() && + "Cannot copy from a graph with invalid node IDs."); + + std::vector newNodeItrs; + + for (unsigned nodeID = 0; nodeID < orig.getNumNodes(); ++nodeID) { + newNodeItrs.push_back( + g.addNode(orig.getNodeCosts(orig.getNodeItr(nodeID)), NodeData())); + } + + for (SimpleGraph::ConstEdgeIterator + origEdgeItr = orig.edgesBegin(), origEdgeEnd = orig.edgesEnd(); + origEdgeItr != origEdgeEnd; ++origEdgeItr) { + + unsigned id1 = orig.getNodeID(orig.getEdgeNode1Itr(origEdgeItr)), + id2 = orig.getNodeID(orig.getEdgeNode2Itr(origEdgeItr)); + + g.addEdge(newNodeItrs[id1], newNodeItrs[id2], + orig.getEdgeCosts(origEdgeItr), EdgeData(g)); + } + + // Assign IDs to the new nodes using the ordering from the old graph, + // this will lead to nodes in the new graph getting the same ID as the + // corresponding node in the old graph. + g.assignNodeIDs(newNodeItrs); + } + + // Simplify the annotated graph by eliminating independent edges and trivial + // nodes. + void simplify() { + disconnectTrivialNodes(); + eliminateIndependentEdges(); + } + + // Eliminate trivial nodes. + void disconnectTrivialNodes() { + for (GraphNodeIterator nodeItr = g.nodesBegin(), nodeEnd = g.nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + + if (g.getNodeCosts(nodeItr).getLength() == 1) { + + std::vector edgesToRemove; + + for (GraphAdjEdgeIterator adjEdgeItr = g.adjEdgesBegin(nodeItr), + adjEdgeEnd = g.adjEdgesEnd(nodeItr); + adjEdgeItr != adjEdgeEnd; ++adjEdgeItr) { + + GraphEdgeIterator edgeItr = *adjEdgeItr; + + if (g.getEdgeNode1Itr(edgeItr) == nodeItr) { + GraphNodeIterator otherNodeItr = g.getEdgeNode2Itr(edgeItr); + g.getNodeCosts(otherNodeItr) += + g.getEdgeCosts(edgeItr).getRowAsVector(0); + } + else { + GraphNodeIterator otherNodeItr = g.getEdgeNode1Itr(edgeItr); + g.getNodeCosts(otherNodeItr) += + g.getEdgeCosts(edgeItr).getColAsVector(0); + } + + edgesToRemove.push_back(edgeItr); + } + + while (!edgesToRemove.empty()) { + g.removeEdge(edgesToRemove.back()); + edgesToRemove.pop_back(); + } + } + } + } + + void eliminateIndependentEdges() { + std::vector edgesToProcess; + + for (GraphEdgeIterator edgeItr = g.edgesBegin(), edgeEnd = g.edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + edgesToProcess.push_back(edgeItr); + } + + while (!edgesToProcess.empty()) { + tryToEliminateEdge(edgesToProcess.back()); + edgesToProcess.pop_back(); + } + } + + void tryToEliminateEdge(const GraphEdgeIterator &edgeItr) { + if (tryNormaliseEdgeMatrix(edgeItr)) { + g.removeEdge(edgeItr); + } + } + + bool tryNormaliseEdgeMatrix(const GraphEdgeIterator &edgeItr) { + + Matrix &edgeCosts = g.getEdgeCosts(edgeItr); + Vector &uCosts = g.getNodeCosts(g.getEdgeNode1Itr(edgeItr)), + &vCosts = g.getNodeCosts(g.getEdgeNode2Itr(edgeItr)); + + for (unsigned r = 0; r < edgeCosts.getRows(); ++r) { + PBQPNum rowMin = edgeCosts.getRowMin(r); + uCosts[r] += rowMin; + if (rowMin != std::numeric_limits::infinity()) { + edgeCosts.subFromRow(r, rowMin); + } + else { + edgeCosts.setRow(r, 0); + } + } + + for (unsigned c = 0; c < edgeCosts.getCols(); ++c) { + PBQPNum colMin = edgeCosts.getColMin(c); + vCosts[c] += colMin; + if (colMin != std::numeric_limits::infinity()) { + edgeCosts.subFromCol(c, colMin); + } + else { + edgeCosts.setCol(c, 0); + } + } + + return edgeCosts.isZero(); + } + + void setup() { + setupLinks(); + heuristic.initialise(*this); + setupBuckets(); + } + + void setupLinks() { + for (GraphEdgeIterator edgeItr = g.edgesBegin(), edgeEnd = g.edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + g.getEdgeData(edgeItr).setup(edgeItr); + } + } + + void setupBuckets() { + for (GraphNodeIterator nodeItr = g.nodesBegin(), nodeEnd = g.nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + addToBucket(nodeItr); + } + } + + void computeSolution() { + assert(g.areNodeIDsValid() && + "Nodes cannot be added/removed during reduction."); + + reduce(); + computeTrivialSolutions(); + backpropagate(); + } + + void printNode(const GraphNodeIterator &nodeItr) { + + std::cerr << "Node " << g.getNodeID(nodeItr) << " (" << &*nodeItr << "):\n" + << " costs = " << g.getNodeCosts(nodeItr) << "\n" + << " link degree = " << g.getNodeData(nodeItr).getLinkDegree() << "\n" + << " links = [ "; + + for (typename HSIT::NodeData::AdjLinkIterator + aeItr = g.getNodeData(nodeItr).adjLinksBegin(), + aeEnd = g.getNodeData(nodeItr).adjLinksEnd(); + aeItr != aeEnd; ++aeItr) { + std::cerr << "(" << g.getNodeID(g.getEdgeNode1Itr(*aeItr)) + << ", " << g.getNodeID(g.getEdgeNode2Itr(*aeItr)) + << ") "; + } + std::cout << "]\n"; + } + + void dumpState() { + + std::cerr << "\n"; + + for (GraphNodeIterator nodeItr = g.nodesBegin(), nodeEnd = g.nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + printNode(nodeItr); + } + + NodeList* buckets[] = { &r0Bucket, &r1Bucket, &r2Bucket }; + + for (unsigned b = 0; b < 3; ++b) { + NodeList &bucket = *buckets[b]; + + std::cerr << "Bucket " << b << ": [ "; + + for (NodeListIterator nItr = bucket.begin(), nEnd = bucket.end(); + nItr != nEnd; ++nItr) { + std::cerr << g.getNodeID(*nItr) << " "; + } + + std::cerr << "]\n"; + } + + std::cerr << "Stack: [ "; + for (NodeStackIterator nsItr = stack.begin(), nsEnd = stack.end(); + nsItr != nsEnd; ++nsItr) { + std::cerr << g.getNodeID(*nsItr) << " "; + } + std::cerr << "]\n"; + } + + void reduce() { + bool reductionFinished = r1Bucket.empty() && r2Bucket.empty() && + heuristic.rNBucketEmpty(); + + while (!reductionFinished) { + + if (!r1Bucket.empty()) { + processR1(); + } + else if (!r2Bucket.empty()) { + processR2(); + } + else if (!heuristic.rNBucketEmpty()) { + solution.setProvedOptimal(false); + solution.incRNReductions(); + heuristic.processRN(); + } + else reductionFinished = true; + } + + }; + + void processR1() { + + // Remove the first node in the R0 bucket: + GraphNodeIterator xNodeItr = r1Bucket.front(); + r1Bucket.pop_front(); + + solution.incR1Reductions(); + + //std::cerr << "Applying R1 to " << g.getNodeID(xNodeItr) << "\n"; + + assert((g.getNodeData(xNodeItr).getLinkDegree() == 1) && + "Node in R1 bucket has degree != 1"); + + GraphEdgeIterator edgeItr = *g.getNodeData(xNodeItr).adjLinksBegin(); + + const Matrix &edgeCosts = g.getEdgeCosts(edgeItr); + + const Vector &xCosts = g.getNodeCosts(xNodeItr); + unsigned xLen = xCosts.getLength(); + + // Duplicate a little code to avoid transposing matrices: + if (xNodeItr == g.getEdgeNode1Itr(edgeItr)) { + GraphNodeIterator yNodeItr = g.getEdgeNode2Itr(edgeItr); + Vector &yCosts = g.getNodeCosts(yNodeItr); + unsigned yLen = yCosts.getLength(); + + for (unsigned j = 0; j < yLen; ++j) { + PBQPNum min = edgeCosts[0][j] + xCosts[0]; + for (unsigned i = 1; i < xLen; ++i) { + PBQPNum c = edgeCosts[i][j] + xCosts[i]; + if (c < min) + min = c; + } + yCosts[j] += min; + } + } + else { + GraphNodeIterator yNodeItr = g.getEdgeNode1Itr(edgeItr); + Vector &yCosts = g.getNodeCosts(yNodeItr); + unsigned yLen = yCosts.getLength(); + + for (unsigned i = 0; i < yLen; ++i) { + PBQPNum min = edgeCosts[i][0] + xCosts[0]; + + for (unsigned j = 1; j < xLen; ++j) { + PBQPNum c = edgeCosts[i][j] + xCosts[j]; + if (c < min) + min = c; + } + yCosts[i] += min; + } + } + + unlinkNode(xNodeItr); + pushStack(xNodeItr); + } + + void processR2() { + + GraphNodeIterator xNodeItr = r2Bucket.front(); + r2Bucket.pop_front(); + + solution.incR2Reductions(); + + // Unlink is unsafe here. At some point it may optimistically more a node + // to a lower-degree list when its degree will later rise, or vice versa, + // violating the assumption that node degrees monotonically decrease + // during the reduction phase. Instead we'll bucket shuffle manually. + pushStack(xNodeItr); + + assert((g.getNodeData(xNodeItr).getLinkDegree() == 2) && + "Node in R2 bucket has degree != 2"); + + const Vector &xCosts = g.getNodeCosts(xNodeItr); + + typename NodeData::AdjLinkIterator tempItr = + g.getNodeData(xNodeItr).adjLinksBegin(); + + GraphEdgeIterator yxEdgeItr = *tempItr, + zxEdgeItr = *(++tempItr); + + GraphNodeIterator yNodeItr = g.getEdgeOtherNode(yxEdgeItr, xNodeItr), + zNodeItr = g.getEdgeOtherNode(zxEdgeItr, xNodeItr); + + removeFromBucket(yNodeItr); + removeFromBucket(zNodeItr); + + removeLink(yxEdgeItr, yNodeItr); + removeLink(zxEdgeItr, zNodeItr); + + // Graph some of the costs: + bool flipEdge1 = (g.getEdgeNode1Itr(yxEdgeItr) == xNodeItr), + flipEdge2 = (g.getEdgeNode1Itr(zxEdgeItr) == xNodeItr); + + const Matrix *yxCosts = flipEdge1 ? + new Matrix(g.getEdgeCosts(yxEdgeItr).transpose()) : + &g.getEdgeCosts(yxEdgeItr), + *zxCosts = flipEdge2 ? + new Matrix(g.getEdgeCosts(zxEdgeItr).transpose()) : + &g.getEdgeCosts(zxEdgeItr); + + unsigned xLen = xCosts.getLength(), + yLen = yxCosts->getRows(), + zLen = zxCosts->getRows(); + + // Compute delta: + Matrix delta(yLen, zLen); + + for (unsigned i = 0; i < yLen; ++i) { + for (unsigned j = 0; j < zLen; ++j) { + PBQPNum min = (*yxCosts)[i][0] + (*zxCosts)[j][0] + xCosts[0]; + for (unsigned k = 1; k < xLen; ++k) { + PBQPNum c = (*yxCosts)[i][k] + (*zxCosts)[j][k] + xCosts[k]; + if (c < min) { + min = c; + } + } + delta[i][j] = min; + } + } + + if (flipEdge1) + delete yxCosts; + + if (flipEdge2) + delete zxCosts; + + // Deal with the potentially induced yz edge. + GraphEdgeIterator yzEdgeItr = g.findEdge(yNodeItr, zNodeItr); + if (yzEdgeItr == g.edgesEnd()) { + yzEdgeItr = g.addEdge(yNodeItr, zNodeItr, delta, EdgeData(g)); + } + else { + // There was an edge, but we're going to screw with it. Delete the old + // link, update the costs. We'll re-link it later. + removeLinkR2(yzEdgeItr); + g.getEdgeCosts(yzEdgeItr) += + (yNodeItr == g.getEdgeNode1Itr(yzEdgeItr)) ? + delta : delta.transpose(); + } + + bool nullCostEdge = tryNormaliseEdgeMatrix(yzEdgeItr); + + // Nulled the edge, remove it entirely. + if (nullCostEdge) { + g.removeEdge(yzEdgeItr); + } + else { + // Edge remains - re-link it. + addLink(yzEdgeItr); + } + + addToBucket(yNodeItr); + addToBucket(zNodeItr); + } + + void computeTrivialSolutions() { + + for (NodeListIterator r0Itr = r0Bucket.begin(), r0End = r0Bucket.end(); + r0Itr != r0End; ++r0Itr) { + GraphNodeIterator nodeItr = *r0Itr; + + solution.incR0Reductions(); + setSolution(nodeItr, g.getNodeCosts(nodeItr).minIndex()); + } + + } + + void backpropagate() { + while (!stack.empty()) { + computeSolution(stack.back()); + stack.pop_back(); + } + } + + void computeSolution(const GraphNodeIterator &nodeItr) { + + NodeData &nodeData = g.getNodeData(nodeItr); + + Vector v(g.getNodeCosts(nodeItr)); + + // Solve based on existing links. + for (typename NodeData::AdjLinkIterator + solvedLinkItr = nodeData.solvedLinksBegin(), + solvedLinkEnd = nodeData.solvedLinksEnd(); + solvedLinkItr != solvedLinkEnd; ++solvedLinkItr) { + + GraphEdgeIterator solvedEdgeItr(*solvedLinkItr); + Matrix &edgeCosts = g.getEdgeCosts(solvedEdgeItr); + + if (nodeItr == g.getEdgeNode1Itr(solvedEdgeItr)) { + GraphNodeIterator adjNode(g.getEdgeNode2Itr(solvedEdgeItr)); + unsigned adjSolution = + solution.getSelection(g.getNodeID(adjNode)); + v += edgeCosts.getColAsVector(adjSolution); + } + else { + GraphNodeIterator adjNode(g.getEdgeNode1Itr(solvedEdgeItr)); + unsigned adjSolution = + solution.getSelection(g.getNodeID(adjNode)); + v += edgeCosts.getRowAsVector(adjSolution); + } + + } + + setSolution(nodeItr, v.minIndex()); + } + + void computeSolutionCost(const SimpleGraph &orig) { + PBQPNum cost = 0.0; + + for (SimpleGraph::ConstNodeIterator + nodeItr = orig.nodesBegin(), nodeEnd = orig.nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + + unsigned nodeId = orig.getNodeID(nodeItr); + + cost += orig.getNodeCosts(nodeItr)[solution.getSelection(nodeId)]; + } + + for (SimpleGraph::ConstEdgeIterator + edgeItr = orig.edgesBegin(), edgeEnd = orig.edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + + SimpleGraph::ConstNodeIterator n1 = orig.getEdgeNode1Itr(edgeItr), + n2 = orig.getEdgeNode2Itr(edgeItr); + unsigned sol1 = solution.getSelection(orig.getNodeID(n1)), + sol2 = solution.getSelection(orig.getNodeID(n2)); + + cost += orig.getEdgeCosts(edgeItr)[sol1][sol2]; + } + + solution.setSolutionCost(cost); + } + +}; + +template +class HeuristicSolver : public Solver { +public: + Solution solve(const SimpleGraph &g) const { + HeuristicSolverImpl solverImpl(g); + return solverImpl.getSolution(); + } +}; + +} + +#endif // LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H diff --git a/lib/CodeGen/PBQP/Heuristics/Briggs.h b/lib/CodeGen/PBQP/Heuristics/Briggs.h new file mode 100644 index 00000000000..fd37f5cbb32 --- /dev/null +++ b/lib/CodeGen/PBQP/Heuristics/Briggs.h @@ -0,0 +1,385 @@ +#ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H +#define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H + +#include "../HeuristicSolver.h" + +#include + +namespace PBQP { +namespace Heuristics { + +class Briggs { + public: + + class NodeData; + class EdgeData; + + private: + + typedef HeuristicSolverImpl Solver; + typedef HSITypes HSIT; + typedef HSIT::SolverGraph SolverGraph; + typedef HSIT::GraphNodeIterator GraphNodeIterator; + typedef HSIT::GraphEdgeIterator GraphEdgeIterator; + + class LinkDegreeComparator { + public: + LinkDegreeComparator() : g(0) {} + LinkDegreeComparator(SolverGraph *g) : g(g) {} + + bool operator()(const GraphNodeIterator &node1Itr, + const GraphNodeIterator &node2Itr) const { + assert((g != 0) && "Graph object not set, cannot access node data."); + unsigned n1Degree = g->getNodeData(node1Itr).getLinkDegree(), + n2Degree = g->getNodeData(node2Itr).getLinkDegree(); + if (n1Degree > n2Degree) { + return true; + } + else if (n1Degree < n2Degree) { + return false; + } + // else they're "equal" by degree, differentiate based on ID. + return g->getNodeID(node1Itr) < g->getNodeID(node2Itr); + } + + private: + SolverGraph *g; + }; + + class SpillPriorityComparator { + public: + SpillPriorityComparator() : g(0) {} + SpillPriorityComparator(SolverGraph *g) : g(g) {} + + bool operator()(const GraphNodeIterator &node1Itr, + const GraphNodeIterator &node2Itr) const { + assert((g != 0) && "Graph object not set, cannot access node data."); + PBQPNum cost1 = + g->getNodeCosts(node1Itr)[0] / + g->getNodeData(node1Itr).getLinkDegree(), + cost2 = + g->getNodeCosts(node2Itr)[0] / + g->getNodeData(node2Itr).getLinkDegree(); + + if (cost1 < cost2) { + return true; + } + else if (cost1 > cost2) { + return false; + } + // else they'er "equal" again, differentiate based on address again. + return g->getNodeID(node1Itr) < g->getNodeID(node2Itr); + } + + private: + SolverGraph *g; + }; + + typedef std::set + RNAllocableNodeList; + typedef RNAllocableNodeList::iterator RNAllocableNodeListIterator; + + typedef std::set + RNUnallocableNodeList; + typedef RNUnallocableNodeList::iterator RNUnallocableNodeListIterator; + + public: + + class NodeData { + private: + RNAllocableNodeListIterator rNAllocableNodeListItr; + RNUnallocableNodeListIterator rNUnallocableNodeListItr; + unsigned numRegOptions, numDenied, numSafe; + std::vector unsafeDegrees; + bool allocable; + + void addRemoveLink(SolverGraph &g, const GraphNodeIterator &nodeItr, + const GraphEdgeIterator &edgeItr, bool add) { + + //assume we're adding... + unsigned udTarget = 0, dir = 1; + + if (!add) { + udTarget = 1; + dir = -1; + } + + EdgeData &linkEdgeData = g.getEdgeData(edgeItr).getHeuristicData(); + + EdgeData::ConstUnsafeIterator edgeUnsafeBegin, edgeUnsafeEnd; + + if (nodeItr == g.getEdgeNode1Itr(edgeItr)) { + numDenied += (dir * linkEdgeData.getWorstDegree()); + edgeUnsafeBegin = linkEdgeData.unsafeBegin(); + edgeUnsafeEnd = linkEdgeData.unsafeEnd(); + } + else { + numDenied += (dir * linkEdgeData.getReverseWorstDegree()); + edgeUnsafeBegin = linkEdgeData.reverseUnsafeBegin(); + edgeUnsafeEnd = linkEdgeData.reverseUnsafeEnd(); + } + + assert((unsafeDegrees.size() == + static_cast( + std::distance(edgeUnsafeBegin, edgeUnsafeEnd))) + && "Unsafe array size mismatch."); + + std::vector::iterator unsafeDegreesItr = + unsafeDegrees.begin(); + + for (EdgeData::ConstUnsafeIterator edgeUnsafeItr = edgeUnsafeBegin; + edgeUnsafeItr != edgeUnsafeEnd; + ++edgeUnsafeItr, ++unsafeDegreesItr) { + + if ((*edgeUnsafeItr == 1) && (*unsafeDegreesItr == udTarget)) { + numSafe -= dir; + } + *unsafeDegreesItr += (dir * (*edgeUnsafeItr)); + } + + allocable = (numDenied < numRegOptions) || (numSafe > 0); + } + + public: + + void setup(SolverGraph &g, const GraphNodeIterator &nodeItr) { + + numRegOptions = g.getNodeCosts(nodeItr).getLength() - 1; + + numSafe = numRegOptions; // Optimistic, correct below. + numDenied = 0; // Also optimistic. + unsafeDegrees.resize(numRegOptions, 0); + + HSIT::NodeData &nodeData = g.getNodeData(nodeItr); + + for (HSIT::NodeData::AdjLinkIterator + adjLinkItr = nodeData.adjLinksBegin(), + adjLinkEnd = nodeData.adjLinksEnd(); + adjLinkItr != adjLinkEnd; ++adjLinkItr) { + + addRemoveLink(g, nodeItr, *adjLinkItr, true); + } + } + + bool isAllocable() const { return allocable; } + + void handleAddLink(SolverGraph &g, const GraphNodeIterator &nodeItr, + const GraphEdgeIterator &adjEdge) { + addRemoveLink(g, nodeItr, adjEdge, true); + } + + void handleRemoveLink(SolverGraph &g, const GraphNodeIterator &nodeItr, + const GraphEdgeIterator &adjEdge) { + addRemoveLink(g, nodeItr, adjEdge, false); + } + + void setRNAllocableNodeListItr( + const RNAllocableNodeListIterator &rNAllocableNodeListItr) { + + this->rNAllocableNodeListItr = rNAllocableNodeListItr; + } + + RNAllocableNodeListIterator getRNAllocableNodeListItr() const { + return rNAllocableNodeListItr; + } + + void setRNUnallocableNodeListItr( + const RNUnallocableNodeListIterator &rNUnallocableNodeListItr) { + + this->rNUnallocableNodeListItr = rNUnallocableNodeListItr; + } + + RNUnallocableNodeListIterator getRNUnallocableNodeListItr() const { + return rNUnallocableNodeListItr; + } + + + }; + + class EdgeData { + private: + + typedef std::vector UnsafeArray; + + unsigned worstDegree, + reverseWorstDegree; + UnsafeArray unsafe, reverseUnsafe; + + public: + + EdgeData() : worstDegree(0), reverseWorstDegree(0) {} + + typedef UnsafeArray::const_iterator ConstUnsafeIterator; + + void setup(SolverGraph &g, const GraphEdgeIterator &edgeItr) { + const Matrix &edgeCosts = g.getEdgeCosts(edgeItr); + unsigned numRegs = edgeCosts.getRows() - 1, + numReverseRegs = edgeCosts.getCols() - 1; + + unsafe.resize(numRegs, 0); + reverseUnsafe.resize(numReverseRegs, 0); + + std::vector rowInfCounts(numRegs, 0), + colInfCounts(numReverseRegs, 0); + + for (unsigned i = 0; i < numRegs; ++i) { + for (unsigned j = 0; j < numReverseRegs; ++j) { + if (edgeCosts[i + 1][j + 1] == + std::numeric_limits::infinity()) { + unsafe[i] = 1; + reverseUnsafe[j] = 1; + ++rowInfCounts[i]; + ++colInfCounts[j]; + + if (colInfCounts[j] > worstDegree) { + worstDegree = colInfCounts[j]; + } + + if (rowInfCounts[i] > reverseWorstDegree) { + reverseWorstDegree = rowInfCounts[i]; + } + } + } + } + } + + unsigned getWorstDegree() const { return worstDegree; } + unsigned getReverseWorstDegree() const { return reverseWorstDegree; } + ConstUnsafeIterator unsafeBegin() const { return unsafe.begin(); } + ConstUnsafeIterator unsafeEnd() const { return unsafe.end(); } + ConstUnsafeIterator reverseUnsafeBegin() const { + return reverseUnsafe.begin(); + } + ConstUnsafeIterator reverseUnsafeEnd() const { + return reverseUnsafe.end(); + } + }; + + void initialise(Solver &solver) { + this->s = &solver; + g = &s->getGraph(); + rNAllocableBucket = RNAllocableNodeList(LinkDegreeComparator(g)); + rNUnallocableBucket = + RNUnallocableNodeList(SpillPriorityComparator(g)); + + for (GraphEdgeIterator + edgeItr = g->edgesBegin(), edgeEnd = g->edgesEnd(); + edgeItr != edgeEnd; ++edgeItr) { + + g->getEdgeData(edgeItr).getHeuristicData().setup(*g, edgeItr); + } + + for (GraphNodeIterator + nodeItr = g->nodesBegin(), nodeEnd = g->nodesEnd(); + nodeItr != nodeEnd; ++nodeItr) { + + g->getNodeData(nodeItr).getHeuristicData().setup(*g, nodeItr); + } + } + + void addToRNBucket(const GraphNodeIterator &nodeItr) { + NodeData &nodeData = g->getNodeData(nodeItr).getHeuristicData(); + + if (nodeData.isAllocable()) { + nodeData.setRNAllocableNodeListItr( + rNAllocableBucket.insert(rNAllocableBucket.begin(), nodeItr)); + } + else { + nodeData.setRNUnallocableNodeListItr( + rNUnallocableBucket.insert(rNUnallocableBucket.begin(), nodeItr)); + } + } + + void removeFromRNBucket(const GraphNodeIterator &nodeItr) { + NodeData &nodeData = g->getNodeData(nodeItr).getHeuristicData(); + + if (nodeData.isAllocable()) { + rNAllocableBucket.erase(nodeData.getRNAllocableNodeListItr()); + } + else { + rNUnallocableBucket.erase(nodeData.getRNUnallocableNodeListItr()); + } + } + + void handleAddLink(const GraphEdgeIterator &edgeItr) { + // We assume that if we got here this edge is attached to at least + // one high degree node. + g->getEdgeData(edgeItr).getHeuristicData().setup(*g, edgeItr); + + GraphNodeIterator n1Itr = g->getEdgeNode1Itr(edgeItr), + n2Itr = g->getEdgeNode2Itr(edgeItr); + + HSIT::NodeData &n1Data = g->getNodeData(n1Itr), + &n2Data = g->getNodeData(n2Itr); + + if (n1Data.getLinkDegree() > 2) { + n1Data.getHeuristicData().handleAddLink(*g, n1Itr, edgeItr); + } + if (n2Data.getLinkDegree() > 2) { + n2Data.getHeuristicData().handleAddLink(*g, n2Itr, edgeItr); + } + } + + void handleRemoveLink(const GraphEdgeIterator &edgeItr, + const GraphNodeIterator &nodeItr) { + NodeData &nodeData = g->getNodeData(nodeItr).getHeuristicData(); + nodeData.handleRemoveLink(*g, nodeItr, edgeItr); + } + + void processRN() { + + /* + std::cerr << "processRN():\n" + << " rNAllocable = [ "; + for (RNAllocableNodeListIterator nItr = rNAllocableBucket.begin(), + nEnd = rNAllocableBucket.end(); + nItr != nEnd; ++nItr) { + std::cerr << g->getNodeID(*nItr) << " (" << g->getNodeData(*nItr).getLinkDegree() << ") "; + } + std::cerr << "]\n" + << " rNUnallocable = [ "; + for (RNUnallocableNodeListIterator nItr = rNUnallocableBucket.begin(), + nEnd = rNUnallocableBucket.end(); + nItr != nEnd; ++nItr) { + float bCost = g->getNodeCosts(*nItr)[0] / g->getNodeData(*nItr).getLinkDegree(); + std::cerr << g->getNodeID(*nItr) << " (" << bCost << ") "; + } + std::cerr << "]\n"; + */ + + if (!rNAllocableBucket.empty()) { + GraphNodeIterator selectedNodeItr = *rNAllocableBucket.begin(); + //std::cerr << "RN safely pushing " << g->getNodeID(selectedNodeItr) << "\n"; + rNAllocableBucket.erase(rNAllocableBucket.begin()); + s->pushStack(selectedNodeItr); + s->unlinkNode(selectedNodeItr); + } + else { + GraphNodeIterator selectedNodeItr = *rNUnallocableBucket.begin(); + //std::cerr << "RN optimistically pushing " << g->getNodeID(selectedNodeItr) << "\n"; + rNUnallocableBucket.erase(rNUnallocableBucket.begin()); + s->pushStack(selectedNodeItr); + s->unlinkNode(selectedNodeItr); + } + + } + + bool rNBucketEmpty() const { + return (rNAllocableBucket.empty() && rNUnallocableBucket.empty()); + } + +private: + + Solver *s; + SolverGraph *g; + RNAllocableNodeList rNAllocableBucket; + RNUnallocableNodeList rNUnallocableBucket; +}; + + + +} +} + + +#endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H diff --git a/lib/CodeGen/PBQP/PBQPMath.h b/lib/CodeGen/PBQP/PBQPMath.h new file mode 100644 index 00000000000..dc184fed144 --- /dev/null +++ b/lib/CodeGen/PBQP/PBQPMath.h @@ -0,0 +1,279 @@ +#ifndef LLVM_CODEGEN_PBQP_PBQPMATH_H +#define LLVM_CODEGEN_PBQP_PBQPMATH_H + +#include +#include +#include + +namespace PBQP { + +typedef double PBQPNum; + +/// \brief PBQP Vector class. +class Vector { + public: + + /// \brief Construct a PBQP vector of the given size. + explicit Vector(unsigned length) : + length(length), data(new PBQPNum[length]) { + } + + /// \brief Construct a PBQP vector with initializer. + Vector(unsigned length, PBQPNum initVal) : + length(length), data(new PBQPNum[length]) { + std::fill(data, data + length, initVal); + } + + /// \brief Copy construct a PBQP vector. + Vector(const Vector &v) : + length(v.length), data(new PBQPNum[length]) { + std::copy(v.data, v.data + length, data); + } + + /// \brief Destroy this vector, return its memory. + ~Vector() { delete[] data; } + + /// \brief Assignment operator. + Vector& operator=(const Vector &v) { + delete[] data; + length = v.length; + data = new PBQPNum[length]; + std::copy(v.data, v.data + length, data); + return *this; + } + + /// \brief Return the length of the vector + unsigned getLength() const throw () { + return length; + } + + /// \brief Element access. + PBQPNum& operator[](unsigned index) { + assert(index < length && "Vector element access out of bounds."); + return data[index]; + } + + /// \brief Const element access. + const PBQPNum& operator[](unsigned index) const { + assert(index < length && "Vector element access out of bounds."); + return data[index]; + } + + /// \brief Add another vector to this one. + Vector& operator+=(const Vector &v) { + assert(length == v.length && "Vector length mismatch."); + std::transform(data, data + length, v.data, data, std::plus()); + return *this; + } + + /// \brief Subtract another vector from this one. + Vector& operator-=(const Vector &v) { + assert(length == v.length && "Vector length mismatch."); + std::transform(data, data + length, v.data, data, std::minus()); + return *this; + } + + /// \brief Returns the index of the minimum value in this vector + unsigned minIndex() const { + return std::min_element(data, data + length) - data; + } + + private: + unsigned length; + PBQPNum *data; +}; + +/// \brief Output a textual representation of the given vector on the given +/// output stream. +template +OStream& operator<<(OStream &os, const Vector &v) { + assert((v.getLength() != 0) && "Zero-length vector badness."); + + os << "[ " << v[0]; + for (unsigned i = 1; i < v.getLength(); ++i) { + os << ", " << v[i]; + } + os << " ]"; + + return os; +} + + +/// \brief PBQP Matrix class +class Matrix { + public: + + /// \brief Construct a PBQP Matrix with the given dimensions. + Matrix(unsigned rows, unsigned cols) : + rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { + } + + /// \brief Construct a PBQP Matrix with the given dimensions and initial + /// value. + Matrix(unsigned rows, unsigned cols, PBQPNum initVal) : + rows(rows), cols(cols), data(new PBQPNum[rows * cols]) { + std::fill(data, data + (rows * cols), initVal); + } + + /// \brief Copy construct a PBQP matrix. + Matrix(const Matrix &m) : + rows(m.rows), cols(m.cols), data(new PBQPNum[rows * cols]) { + std::copy(m.data, m.data + (rows * cols), data); + } + + /// \brief Destroy this matrix, return its memory. + ~Matrix() { delete[] data; } + + /// \brief Assignment operator. + Matrix& operator=(const Matrix &m) { + delete[] data; + rows = m.rows; cols = m.cols; + data = new PBQPNum[rows * cols]; + std::copy(m.data, m.data + (rows * cols), data); + return *this; + } + + /// \brief Return the number of rows in this matrix. + unsigned getRows() const throw () { return rows; } + + /// \brief Return the number of cols in this matrix. + unsigned getCols() const throw () { return cols; } + + /// \brief Matrix element access. + PBQPNum* operator[](unsigned r) { + assert(r < rows && "Row out of bounds."); + return data + (r * cols); + } + + /// \brief Matrix element access. + const PBQPNum* operator[](unsigned r) const { + assert(r < rows && "Row out of bounds."); + return data + (r * cols); + } + + /// \brief Returns the given row as a vector. + Vector getRowAsVector(unsigned r) const { + Vector v(cols); + for (unsigned c = 0; c < cols; ++c) + v[c] = (*this)[r][c]; + return v; + } + + /// \brief Returns the given column as a vector. + Vector getColAsVector(unsigned c) const { + Vector v(rows); + for (unsigned r = 0; r < rows; ++r) + v[r] = (*this)[r][c]; + return v; + } + + /// \brief Reset the matrix to the given value. + Matrix& reset(PBQPNum val = 0) { + std::fill(data, data + (rows * cols), val); + return *this; + } + + /// \brief Set a single row of this matrix to the given value. + Matrix& setRow(unsigned r, PBQPNum val) { + assert(r < rows && "Row out of bounds."); + std::fill(data + (r * cols), data + ((r + 1) * cols), val); + return *this; + } + + /// \brief Set a single column of this matrix to the given value. + Matrix& setCol(unsigned c, PBQPNum val) { + assert(c < cols && "Column out of bounds."); + for (unsigned r = 0; r < rows; ++r) + (*this)[r][c] = val; + return *this; + } + + /// \brief Matrix transpose. + Matrix transpose() const { + Matrix m(cols, rows); + for (unsigned r = 0; r < rows; ++r) + for (unsigned c = 0; c < cols; ++c) + m[c][r] = (*this)[r][c]; + return m; + } + + /// \brief Returns the diagonal of the matrix as a vector. + /// + /// Matrix must be square. + Vector diagonalize() const { + assert(rows == cols && "Attempt to diagonalize non-square matrix."); + + Vector v(rows); + for (unsigned r = 0; r < rows; ++r) + v[r] = (*this)[r][r]; + return v; + } + + /// \brief Add the given matrix to this one. + Matrix& operator+=(const Matrix &m) { + assert(rows == m.rows && cols == m.cols && + "Matrix dimensions mismatch."); + std::transform(data, data + (rows * cols), m.data, data, + std::plus()); + return *this; + } + + /// \brief Returns the minimum of the given row + PBQPNum getRowMin(unsigned r) const { + assert(r < rows && "Row out of bounds"); + return *std::min_element(data + (r * cols), data + ((r + 1) * cols)); + } + + /// \brief Returns the minimum of the given column + PBQPNum getColMin(unsigned c) const { + PBQPNum minElem = (*this)[0][c]; + for (unsigned r = 1; r < rows; ++r) + if ((*this)[r][c] < minElem) minElem = (*this)[r][c]; + return minElem; + } + + /// \brief Subtracts the given scalar from the elements of the given row. + Matrix& subFromRow(unsigned r, PBQPNum val) { + assert(r < rows && "Row out of bounds"); + std::transform(data + (r * cols), data + ((r + 1) * cols), + data + (r * cols), + std::bind2nd(std::minus(), val)); + return *this; + } + + /// \brief Subtracts the given scalar from the elements of the given column. + Matrix& subFromCol(unsigned c, PBQPNum val) { + for (unsigned r = 0; r < rows; ++r) + (*this)[r][c] -= val; + return *this; + } + + /// \brief Returns true if this is a zero matrix. + bool isZero() const { + return find_if(data, data + (rows * cols), + std::bind2nd(std::not_equal_to(), 0)) == + data + (rows * cols); + } + + private: + unsigned rows, cols; + PBQPNum *data; +}; + +/// \brief Output a textual representation of the given matrix on the given +/// output stream. +template +OStream& operator<<(OStream &os, const Matrix &m) { + + assert((m.getRows() != 0) && "Zero-row matrix badness."); + + for (unsigned i = 0; i < m.getRows(); ++i) { + os << m.getRowAsVector(i); + } + + return os; +} + +} + +#endif // LLVM_CODEGEN_PBQP_PBQPMATH_HPP diff --git a/lib/CodeGen/PBQP/SimpleGraph.h b/lib/CodeGen/PBQP/SimpleGraph.h new file mode 100644 index 00000000000..595269c327e --- /dev/null +++ b/lib/CodeGen/PBQP/SimpleGraph.h @@ -0,0 +1,86 @@ +#ifndef LLVM_CODEGEN_PBQP_SIMPLEGRAPH_H +#define LLVM_CODEGEN_PBQP_SIMPLEGRAPH_H + +#include "GraphBase.h" + +namespace PBQP { + +class SimpleEdge; + +class SimpleNode : public NodeBase { +public: + SimpleNode(const Vector &costs) : + NodeBase(costs) {} +}; + +class SimpleEdge : public EdgeBase { +public: + SimpleEdge(const NodeIterator &node1Itr, const NodeIterator &node2Itr, + const Matrix &costs) : + EdgeBase(node1Itr, node2Itr, costs) {} +}; + +class SimpleGraph : public GraphBase { +private: + + typedef GraphBase PGraph; + + void copyFrom(const SimpleGraph &other) { + assert(other.areNodeIDsValid() && + "Cannot copy from another graph unless IDs have been assigned."); + + std::vector newNodeItrs(other.getNumNodes()); + + for (ConstNodeIterator nItr = other.nodesBegin(), nEnd = other.nodesEnd(); + nItr != nEnd; ++nItr) { + newNodeItrs[other.getNodeID(nItr)] = addNode(other.getNodeCosts(nItr)); + } + + for (ConstEdgeIterator eItr = other.edgesBegin(), eEnd = other.edgesEnd(); + eItr != eEnd; ++eItr) { + + unsigned node1ID = other.getNodeID(other.getEdgeNode1Itr(eItr)), + node2ID = other.getNodeID(other.getEdgeNode2Itr(eItr)); + + addEdge(newNodeItrs[node1ID], newNodeItrs[node2ID], + other.getEdgeCosts(eItr)); + } + } + + void copyFrom(SimpleGraph &other) { + if (!other.areNodeIDsValid()) { + other.assignNodeIDs(); + } + copyFrom(const_cast(other)); + } + +public: + + SimpleGraph() {} + + + SimpleGraph(const SimpleGraph &other) : PGraph() { + copyFrom(other); + } + + SimpleGraph& operator=(const SimpleGraph &other) { + clear(); + copyFrom(other); + return *this; + } + + NodeIterator addNode(const Vector &costs) { + return PGraph::addConstructedNode(SimpleNode(costs)); + } + + EdgeIterator addEdge(const NodeIterator &node1Itr, + const NodeIterator &node2Itr, + const Matrix &costs) { + return PGraph::addConstructedEdge(SimpleEdge(node1Itr, node2Itr, costs)); + } + +}; + +} + +#endif // LLVM_CODEGEN_PBQP_SIMPLEGRAPH_H diff --git a/lib/CodeGen/PBQP/Solution.h b/lib/CodeGen/PBQP/Solution.h new file mode 100644 index 00000000000..316c9de5bd1 --- /dev/null +++ b/lib/CodeGen/PBQP/Solution.h @@ -0,0 +1,74 @@ +#ifndef LLVM_CODEGEN_PBQP_SOLUTION_H +#define LLVM_CODEGEN_PBQP_SOLUTION_H + +#include "PBQPMath.h" + +namespace PBQP { + +class Solution { + + friend class SolverImplementation; + +private: + + std::vector selections; + PBQPNum solutionCost; + bool provedOptimal; + unsigned r0Reductions, r1Reductions, + r2Reductions, rNReductions; + +public: + + Solution() : + solutionCost(0.0), provedOptimal(false), + r0Reductions(0), r1Reductions(0), r2Reductions(0), rNReductions(0) {} + + Solution(unsigned length, bool assumeOptimal) : + selections(length), solutionCost(0.0), provedOptimal(assumeOptimal), + r0Reductions(0), r1Reductions(0), r2Reductions(0), rNReductions(0) {} + + void setProvedOptimal(bool provedOptimal) { + this->provedOptimal = provedOptimal; + } + + void setSelection(unsigned nodeID, unsigned selection) { + selections[nodeID] = selection; + } + + void setSolutionCost(PBQPNum solutionCost) { + this->solutionCost = solutionCost; + } + + void incR0Reductions() { ++r0Reductions; } + void incR1Reductions() { ++r1Reductions; } + void incR2Reductions() { ++r2Reductions; } + void incRNReductions() { ++rNReductions; } + + unsigned numNodes() const { return selections.size(); } + + unsigned getSelection(unsigned nodeID) const { + return selections[nodeID]; + } + + PBQPNum getCost() const { return solutionCost; } + + bool isProvedOptimal() const { return provedOptimal; } + + unsigned getR0Reductions() const { return r0Reductions; } + unsigned getR1Reductions() const { return r1Reductions; } + unsigned getR2Reductions() const { return r2Reductions; } + unsigned getRNReductions() const { return rNReductions; } + + bool operator==(const Solution &other) const { + return (selections == other.selections); + } + + bool operator!=(const Solution &other) const { + return !(*this == other); + } + +}; + +} + +#endif // LLVM_CODEGEN_PBQP_SOLUTION_H diff --git a/lib/CodeGen/PBQP/Solver.h b/lib/CodeGen/PBQP/Solver.h new file mode 100644 index 00000000000..5b6a2849579 --- /dev/null +++ b/lib/CodeGen/PBQP/Solver.h @@ -0,0 +1,21 @@ +#ifndef LLVM_CODEGEN_PBQP_SOLVER_H +#define LLVM_CODEGEN_PBQP_SOLVER_H + +#include "SimpleGraph.h" +#include "Solution.h" + +namespace PBQP { + +/// \brief Interface for solver classes. +class Solver { +public: + + virtual ~Solver() = 0; + virtual Solution solve(const SimpleGraph &orig) const = 0; +}; + +Solver::~Solver() {} + +} + +#endif // LLVM_CODEGEN_PBQP_SOLVER_H diff --git a/lib/CodeGen/RegAllocPBQP.cpp b/lib/CodeGen/RegAllocPBQP.cpp index 862ce00e1c8..63c7d3d2ddd 100644 --- a/lib/CodeGen/RegAllocPBQP.cpp +++ b/lib/CodeGen/RegAllocPBQP.cpp @@ -31,7 +31,9 @@ #define DEBUG_TYPE "regalloc" -#include "PBQP.h" +#include "PBQP/HeuristicSolver.h" +#include "PBQP/SimpleGraph.h" +#include "PBQP/Heuristics/Briggs.h" #include "VirtRegMap.h" #include "VirtRegRewriter.h" #include "llvm/CodeGen/LiveIntervalAnalysis.h" @@ -54,42 +56,41 @@ using namespace llvm; static RegisterRegAlloc -registerPBQPRepAlloc("pbqp", "PBQP register allocator", - createPBQPRegisterAllocator); +registerPBQPRepAlloc("pbqp", "PBQP register allocator.", + llvm::createPBQPRegisterAllocator); namespace { - //! - //! PBQP based allocators solve the register allocation problem by mapping - //! register allocation problems to Partitioned Boolean Quadratic - //! Programming problems. + /// + /// PBQP based allocators solve the register allocation problem by mapping + /// register allocation problems to Partitioned Boolean Quadratic + /// Programming problems. class VISIBILITY_HIDDEN PBQPRegAlloc : public MachineFunctionPass { public: static char ID; - - //! Construct a PBQP register allocator. + + /// Construct a PBQP register allocator. PBQPRegAlloc() : MachineFunctionPass((intptr_t)&ID) {} - //! Return the pass name. + /// Return the pass name. virtual const char* getPassName() const throw() { return "PBQP Register Allocator"; } - //! PBQP analysis usage. - virtual void getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); - AU.addRequired(); - AU.addRequiredTransitive(); - AU.addRequired(); - AU.addPreserved(); - AU.addRequired(); - AU.addPreserved(); - AU.addRequired(); - MachineFunctionPass::getAnalysisUsage(AU); + /// PBQP analysis usage. + virtual void getAnalysisUsage(AnalysisUsage &au) const { + au.addRequired(); + //au.addRequiredID(SplitCriticalEdgesID); + au.addRequired(); + au.addPreserved(); + au.addRequired(); + au.addPreserved(); + au.addRequired(); + MachineFunctionPass::getAnalysisUsage(au); } - //! Perform register allocation + /// Perform register allocation virtual bool runOnMachineFunction(MachineFunction &MF); private: @@ -99,7 +100,7 @@ namespace { typedef std::vector AllowedSetMap; typedef std::set RegSet; typedef std::pair RegPair; - typedef std::map CoalesceMap; + typedef std::map CoalesceMap; typedef std::set LiveIntervalSet; @@ -121,60 +122,60 @@ namespace { emptyVRegIntervals; - //! Builds a PBQP cost vector. + /// Builds a PBQP cost vector. template - PBQPVector* buildCostVector(unsigned vReg, - const RegContainer &allowed, - const CoalesceMap &cealesces, - PBQPNum spillCost) const; + PBQP::Vector buildCostVector(unsigned vReg, + const RegContainer &allowed, + const CoalesceMap &cealesces, + PBQP::PBQPNum spillCost) const; - //! \brief Builds a PBQP interference matrix. - //! - //! @return Either a pointer to a non-zero PBQP matrix representing the - //! allocation option costs, or a null pointer for a zero matrix. - //! - //! Expects allowed sets for two interfering LiveIntervals. These allowed - //! sets should contain only allocable registers from the LiveInterval's - //! register class, with any interfering pre-colored registers removed. + /// \brief Builds a PBQP interference matrix. + /// + /// @return Either a pointer to a non-zero PBQP matrix representing the + /// allocation option costs, or a null pointer for a zero matrix. + /// + /// Expects allowed sets for two interfering LiveIntervals. These allowed + /// sets should contain only allocable registers from the LiveInterval's + /// register class, with any interfering pre-colored registers removed. template - PBQPMatrix* buildInterferenceMatrix(const RegContainer &allowed1, - const RegContainer &allowed2) const; + PBQP::Matrix* buildInterferenceMatrix(const RegContainer &allowed1, + const RegContainer &allowed2) const; - //! - //! Expects allowed sets for two potentially coalescable LiveIntervals, - //! and an estimated benefit due to coalescing. The allowed sets should - //! contain only allocable registers from the LiveInterval's register - //! classes, with any interfering pre-colored registers removed. + /// + /// Expects allowed sets for two potentially coalescable LiveIntervals, + /// and an estimated benefit due to coalescing. The allowed sets should + /// contain only allocable registers from the LiveInterval's register + /// classes, with any interfering pre-colored registers removed. template - PBQPMatrix* buildCoalescingMatrix(const RegContainer &allowed1, - const RegContainer &allowed2, - PBQPNum cBenefit) const; + PBQP::Matrix* buildCoalescingMatrix(const RegContainer &allowed1, + const RegContainer &allowed2, + PBQP::PBQPNum cBenefit) const; - //! \brief Finds coalescing opportunities and returns them as a map. - //! - //! Any entries in the map are guaranteed coalescable, even if their - //! corresponding live intervals overlap. + /// \brief Finds coalescing opportunities and returns them as a map. + /// + /// Any entries in the map are guaranteed coalescable, even if their + /// corresponding live intervals overlap. CoalesceMap findCoalesces(); - //! \brief Finds the initial set of vreg intervals to allocate. + /// \brief Finds the initial set of vreg intervals to allocate. void findVRegIntervalsToAlloc(); - //! \brief Constructs a PBQP problem representation of the register - //! allocation problem for this function. - //! - //! @return a PBQP solver object for the register allocation problem. - pbqp* constructPBQPProblem(); + /// \brief Constructs a PBQP problem representation of the register + /// allocation problem for this function. + /// + /// @return a PBQP solver object for the register allocation problem. + PBQP::SimpleGraph constructPBQPProblem(); - //! \brief Adds a stack interval if the given live interval has been - //! spilled. Used to support stack slot coloring. + /// \brief Adds a stack interval if the given live interval has been + /// spilled. Used to support stack slot coloring. void addStackInterval(const LiveInterval *spilled,MachineRegisterInfo* mri); - //! \brief Given a solved PBQP problem maps this solution back to a register - //! assignment. - bool mapPBQPToRegAlloc(pbqp *problem); + /// \brief Given a solved PBQP problem maps this solution back to a register + /// assignment. + bool mapPBQPToRegAlloc(const PBQP::Solution &solution); - //! \brief Postprocessing before final spilling. Sets basic block "live in" - //! variables. + /// \brief Postprocessing before final spilling. Sets basic block "live in" + /// variables. void finalizeAlloc() const; }; @@ -184,17 +185,17 @@ namespace { template -PBQPVector* PBQPRegAlloc::buildCostVector(unsigned vReg, - const RegContainer &allowed, - const CoalesceMap &coalesces, - PBQPNum spillCost) const { +PBQP::Vector PBQPRegAlloc::buildCostVector(unsigned vReg, + const RegContainer &allowed, + const CoalesceMap &coalesces, + PBQP::PBQPNum spillCost) const { typedef typename RegContainer::const_iterator AllowedItr; // Allocate vector. Additional element (0th) used for spill option - PBQPVector *v = new PBQPVector(allowed.size() + 1); + PBQP::Vector v(allowed.size() + 1, 0); - (*v)[0] = spillCost; + v[0] = spillCost; // Iterate over the allowed registers inserting coalesce benefits if there // are any. @@ -212,14 +213,14 @@ PBQPVector* PBQPRegAlloc::buildCostVector(unsigned vReg, continue; // We have a coalesce - insert the benefit. - (*v)[ai + 1] = -cmItr->second; + v[ai + 1] = -cmItr->second; } return v; } template -PBQPMatrix* PBQPRegAlloc::buildInterferenceMatrix( +PBQP::Matrix* PBQPRegAlloc::buildInterferenceMatrix( const RegContainer &allowed1, const RegContainer &allowed2) const { typedef typename RegContainer::const_iterator RegContainerIterator; @@ -232,7 +233,8 @@ PBQPMatrix* PBQPRegAlloc::buildInterferenceMatrix( // that the spill option (element 0,0) has zero cost, since we can allocate // both intervals to memory safely (the cost for each individual allocation // to memory is accounted for by the cost vectors for each live interval). - PBQPMatrix *m = new PBQPMatrix(allowed1.size() + 1, allowed2.size() + 1); + PBQP::Matrix *m = + new PBQP::Matrix(allowed1.size() + 1, allowed2.size() + 1, 0); // Assume this is a zero matrix until proven otherwise. Zero matrices occur // between interfering live ranges with non-overlapping register sets (e.g. @@ -262,7 +264,7 @@ PBQPMatrix* PBQPRegAlloc::buildInterferenceMatrix( // If the row/column regs are identical or alias insert an infinity. if ((reg1 == reg2) || tri->areAliases(reg1, reg2)) { - (*m)[ri][ci] = std::numeric_limits::infinity(); + (*m)[ri][ci] = std::numeric_limits::infinity(); isZeroMatrix = false; } @@ -284,9 +286,9 @@ PBQPMatrix* PBQPRegAlloc::buildInterferenceMatrix( } template -PBQPMatrix* PBQPRegAlloc::buildCoalescingMatrix( +PBQP::Matrix* PBQPRegAlloc::buildCoalescingMatrix( const RegContainer &allowed1, const RegContainer &allowed2, - PBQPNum cBenefit) const { + PBQP::PBQPNum cBenefit) const { typedef typename RegContainer::const_iterator RegContainerIterator; @@ -295,7 +297,8 @@ PBQPMatrix* PBQPRegAlloc::buildCoalescingMatrix( // for the LiveIntervals which are (potentially) to be coalesced. The amount // -cBenefit will be placed in any element representing the same register // for both intervals. - PBQPMatrix *m = new PBQPMatrix(allowed1.size() + 1, allowed2.size() + 1); + PBQP::Matrix *m = + new PBQP::Matrix(allowed1.size() + 1, allowed2.size() + 1, 0); // Reset costs to zero. m->reset(0); @@ -497,10 +500,11 @@ void PBQPRegAlloc::findVRegIntervalsToAlloc() { } } -pbqp* PBQPRegAlloc::constructPBQPProblem() { +PBQP::SimpleGraph PBQPRegAlloc::constructPBQPProblem() { typedef std::vector LIVector; typedef std::vector RegVector; + typedef std::vector NodeVector; // This will store the physical intervals for easy reference. LIVector physIntervals; @@ -532,10 +536,11 @@ pbqp* PBQPRegAlloc::constructPBQPProblem() { } // Get the set of potential coalesces. - CoalesceMap coalesces(findCoalesces()); + CoalesceMap coalesces;//(findCoalesces()); // Construct a PBQP solver for this problem - pbqp *solver = alloc_pbqp(vregIntervalsToAlloc.size()); + PBQP::SimpleGraph problem; + NodeVector problemNodes(vregIntervalsToAlloc.size()); // Resize allowedSets container appropriately. allowedSets.resize(vregIntervalsToAlloc.size()); @@ -596,13 +601,13 @@ pbqp* PBQPRegAlloc::constructPBQPProblem() { // Set the spill cost to the interval weight, or epsilon if the // interval weight is zero - PBQPNum spillCost = (li->weight != 0.0) ? - li->weight : std::numeric_limits::min(); + PBQP::PBQPNum spillCost = (li->weight != 0.0) ? + li->weight : std::numeric_limits::min(); // Build a cost vector for this interval. - add_pbqp_nodecosts(solver, node, - buildCostVector(li->reg, allowedSets[node], coalesces, - spillCost)); + problemNodes[node] = + problem.addNode( + buildCostVector(li->reg, allowedSets[node], coalesces, spillCost)); } @@ -618,7 +623,7 @@ pbqp* PBQPRegAlloc::constructPBQPProblem() { CoalesceMap::const_iterator cmItr = coalesces.find(RegPair(li->reg, li2->reg)); - PBQPMatrix *m = 0; + PBQP::Matrix *m = 0; if (cmItr != coalesces.end()) { m = buildCoalescingMatrix(allowedSets[node1], allowedSets[node2], @@ -629,14 +634,29 @@ pbqp* PBQPRegAlloc::constructPBQPProblem() { } if (m != 0) { - add_pbqp_edgecosts(solver, node1, node2, m); + problem.addEdge(problemNodes[node1], + problemNodes[node2], + *m); + delete m; } } } + problem.assignNodeIDs(); + + assert(problem.getNumNodes() == allowedSets.size()); + for (unsigned i = 0; i < allowedSets.size(); ++i) { + assert(problem.getNodeItr(i) == problemNodes[i]); + } +/* + std::cerr << "Allocating for " << problem.getNumNodes() << " nodes, " + << problem.getNumEdges() << " edges.\n"; + + problem.printDot(std::cerr); +*/ // We're done, PBQP problem constructed - return it. - return solver; + return problem; } void PBQPRegAlloc::addStackInterval(const LiveInterval *spilled, @@ -659,7 +679,9 @@ void PBQPRegAlloc::addStackInterval(const LiveInterval *spilled, stackInterval.MergeRangesInAsValue(rhsInterval, vni); } -bool PBQPRegAlloc::mapPBQPToRegAlloc(pbqp *problem) { +bool PBQPRegAlloc::mapPBQPToRegAlloc(const PBQP::Solution &solution) { + + static unsigned round = 0; // Set to true if we have any spills bool anotherRoundNeeded = false; @@ -667,10 +689,56 @@ bool PBQPRegAlloc::mapPBQPToRegAlloc(pbqp *problem) { // Clear the existing allocation. vrm->clearAllVirt(); + CoalesceMap coalesces;//(findCoalesces()); + + for (unsigned i = 0; i < node2LI.size(); ++i) { + if (solution.getSelection(i) == 0) { + continue; + } + + unsigned iSel = solution.getSelection(i); + unsigned iAlloc = allowedSets[i][iSel - 1]; + + for (unsigned j = i + 1; j < node2LI.size(); ++j) { + + if (solution.getSelection(j) == 0) { + continue; + } + + unsigned jSel = solution.getSelection(j); + unsigned jAlloc = allowedSets[j][jSel - 1]; + + if ((iAlloc != jAlloc) && !tri->areAliases(iAlloc, jAlloc)) { + continue; + } + + if (node2LI[i]->overlaps(*node2LI[j])) { + if (coalesces.find(RegPair(node2LI[i]->reg, node2LI[j]->reg)) == coalesces.end()) { + DEBUG(errs() << "In round " << ++round << ":\n" + << "Bogusness in " << mf->getFunction()->getName() << "!\n" + << "Live interval " << i << " (reg" << node2LI[i]->reg << ") and\n" + << "Live interval " << j << " (reg" << node2LI[j]->reg << ")\n" + << " were allocated registers " << iAlloc << " (index " << iSel << ") and " + << jAlloc << "(index " << jSel + << ") respectively in a graph of " << solution.numNodes() << " nodes.\n" + << "li[i]->empty() = " << node2LI[i]->empty() << "\n" + << "li[j]->empty() = " << node2LI[j]->empty() << "\n" + << "li[i]->overlaps(li[j]) = " << node2LI[i]->overlaps(*node2LI[j]) << "\n" + << "coalesce = " << (coalesces.find(RegPair(node2LI[i]->reg, node2LI[j]->reg)) != coalesces.end()) << "\n"); + + DEBUG(errs() << "solution.getCost() = " << solution.getCost() << "\n"); + exit(1); + } + } + } + } + + // Iterate over the nodes mapping the PBQP solution to a register assignment. for (unsigned node = 0; node < node2LI.size(); ++node) { unsigned virtReg = node2LI[node]->reg, - allocSelection = get_pbqp_solution(problem, node); + allocSelection = solution.getSelection(node); + // If the PBQP solution is non-zero it's a physical register... if (allocSelection != 0) { @@ -731,11 +799,12 @@ void PBQPRegAlloc::finalizeAlloc() const { // First allocate registers for the empty intervals. for (LiveIntervalSet::const_iterator - itr = emptyVRegIntervals.begin(), end = emptyVRegIntervals.end(); + itr = emptyVRegIntervals.begin(), end = emptyVRegIntervals.end(); itr != end; ++itr) { LiveInterval *li = *itr; unsigned physReg = vrm->getRegAllocPref(li->reg); + if (physReg == 0) { const TargetRegisterClass *liRC = mri->getRegClass(li->reg); physReg = *liRC->allocation_order_begin(*mf); @@ -766,8 +835,8 @@ void PBQPRegAlloc::finalizeAlloc() const { continue; } - // Ignore unallocated vregs: if (reg == 0) { + // Filter out zero regs - they're for intervals that were spilled. continue; } @@ -806,8 +875,7 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { vrm = &getAnalysis(); - DEBUG(errs() << "PBQP Register Allocating for " - << mf->getFunction()->getName() << "\n"); + DEBUG(errs() << "PBQP2 Register Allocating for " << mf->getFunction()->getName() << "\n"); // Allocator main loop: // @@ -832,15 +900,19 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { unsigned round = 0; while (!pbqpAllocComplete) { - DOUT << " PBQP Regalloc round " << round << ":\n"; + DEBUG(errs() << " PBQP Regalloc round " << round << ":\n"); - pbqp *problem = constructPBQPProblem(); - - solve_pbqp(problem); - - pbqpAllocComplete = mapPBQPToRegAlloc(problem); - - free_pbqp(problem); + PBQP::SimpleGraph problem = constructPBQPProblem(); + PBQP::HeuristicSolver solver; + problem.assignNodeIDs(); + PBQP::Solution solution = solver.solve(problem); +/* + std::cerr << "Solution:\n"; + for (unsigned i = 0; i < solution.numNodes(); ++i) { + std::cerr << " " << i << " -> " << solution.getSelection(i) << "\n"; + } +*/ + pbqpAllocComplete = mapPBQPToRegAlloc(solution); ++round; } @@ -855,7 +927,7 @@ bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) { node2LI.clear(); allowedSets.clear(); - DOUT << "Post alloc VirtRegMap:\n" << *vrm << "\n"; + DEBUG(errs() << "Post alloc VirtRegMap:\n" << *vrm << "\n"); // Run rewriter std::auto_ptr rewriter(createVirtRegRewriter());