[llvm-commits] [llvm] r56959 - in /llvm/trunk: include/llvm/CodeGen/LinkAllCodegenComponents.h include/llvm/CodeGen/Passes.h lib/CodeGen/PBQP.cpp lib/CodeGen/PBQP.h lib/CodeGen/RegAllocPBQP.cpp
Owen Anderson
resistor at mac.com
Fri Oct 3 13:43:04 PDT 2008
Is there any data available about how this compares to the default
regalloc? When is it better/worse?
--Owen
On Oct 2, 2008, at 11:29 AM, Evan Cheng wrote:
> Author: evancheng
> Date: Thu Oct 2 13:29:27 2008
> New Revision: 56959
>
> URL: http://llvm.org/viewvc/llvm-project?rev=56959&view=rev
> Log:
> A Partitioned Boolean Quadratic Programming (PBQP) based register
> allocator.
>
> Contributed by Lang Hames.
>
> Added:
> llvm/trunk/lib/CodeGen/PBQP.cpp
> llvm/trunk/lib/CodeGen/PBQP.h
> llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp
> Modified:
> llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h
> llvm/trunk/include/llvm/CodeGen/Passes.h
>
> Modified: llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h?rev=56959&r1=56958&r2=56959&view=diff
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h
> (original)
> +++ llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h Thu
> Oct 2 13:29:27 2008
> @@ -35,6 +35,7 @@
> (void) llvm::createLocalRegisterAllocator();
> (void) llvm::createBigBlockRegisterAllocator();
> (void) llvm::createLinearScanRegisterAllocator();
> + (void) llvm::createPBQPRegisterAllocator();
>
> (void) llvm::createSimpleRegisterCoalescer();
>
>
> Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=56959&r1=56958&r2=56959&view=diff
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/Passes.h Thu Oct 2 13:29:27 2008
> @@ -110,6 +110,11 @@
> ///
> FunctionPass *createLinearScanRegisterAllocator();
>
> + /// PBQPRegisterAllocation Pass - This pass implements the
> Partitioned Boolean
> + /// Quadratic Prograaming (PBQP) based register allocator.
> + ///
> + FunctionPass *createPBQPRegisterAllocator();
> +
> /// SimpleRegisterCoalescing Pass - Coalesce all copies possible.
> Can run
> /// independently of the register allocator.
> ///
>
> Added: llvm/trunk/lib/CodeGen/PBQP.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/PBQP.cpp?rev=56959&view=auto
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- llvm/trunk/lib/CodeGen/PBQP.cpp (added)
> +++ llvm/trunk/lib/CodeGen/PBQP.cpp Thu Oct 2 13:29:27 2008
> @@ -0,0 +1,1395 @@
> +//===---------------- 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 Univesity of Sydney
> +// http://www.it.usyd.edu.au/~scholz
> +//
> =
> =
> =
> ----------------------------------------------------------------------=
> ==//
> +
> +
> +#include <limits>
> +#include <cassert>
> +
> +#include "PBQP.h"
> +
> +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<PBQPNum>::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;u<num_nodes;u++) {
> + this_->solution[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;u<this_->num_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;u<this_->num_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 <this_->num_nodes);
> + assert (v >= 0 && v <this_->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<ylen;i++) {
> + for(unsigned j=0;j<zlen;j++) {
> + PBQPNum min = (*c_yx)[i][0] + (*c_zx)[j][0] + (*cx)[0];
> + for(unsigned k=1;k<xlen;k++) {
> + PBQPNum c = (*c_yx)[i][k] + (*c_zx)[j][k] + (*cx)[k];
> + if ( c < min ) {
> + min = c;
> + }
> + }
> + (*delta)[i][j] = min;
> + }
> + }
> +
> + /* add delta matrix */
> + add_pbqp_edgecosts(this_,y,z,delta);
> +
> + /* delete node x */
> + remove_node(this_,x);
> +
> + /* simplify cost matrix c_yz */
> + simplify_edge(this_,y,z);
> +
> + /* reorder adj. nodes */
> + 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 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<PBQPNum>::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 */
>
> Added: llvm/trunk/lib/CodeGen/PBQP.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/PBQP.h?rev=56959&view=auto
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- llvm/trunk/lib/CodeGen/PBQP.h (added)
> +++ llvm/trunk/lib/CodeGen/PBQP.h Thu Oct 2 13:29:27 2008
> @@ -0,0 +1,284 @@
> +//===---------------- 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 Univesity 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 <cassert>
> +#include <algorithm>
> +#include <functional>
> +
> +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<PBQPNum>());
> + 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<PBQPNum>());
> + 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<PBQPNum>());
> + 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<PBQPNum>(), 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<PBQPNum>(), 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
>
> Added: llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp?rev=56959&view=auto
>
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp (added)
> +++ llvm/trunk/lib/CodeGen/RegAllocPBQP.cpp Thu Oct 2 13:29:27 2008
> @@ -0,0 +1,529 @@
> +//===------ RegAllocPBQP.cpp ---- PBQP Register Allocator -------*-
> C++ -*-===//
> +//
> +// The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open
> Source
> +// License. See LICENSE.TXT for details.
> +//
> +//
> =
> =
> =
> ----------------------------------------------------------------------=
> ==//
> +//
> +// This file contains a Partitioned Boolean Quadratic Programming
> (PBQP) based
> +// register allocator for LLVM. This allocator works by
> constructing a PBQP
> +// problem representing the register allocation problem under
> consideration,
> +// solving this using a PBQP solver, and mapping the solution back
> to a
> +// register assignment. If any variables are selected for spilling
> then spill
> +// code is inserted and the process repeated.
> +//
> +// The PBQP solver (pbqp.c) provided for this allocator uses a
> heuristic tuned
> +// for register allocation. For more information on PBQP for register
> +// allocation see the following papers:
> +//
> +// (1) Hames, L. and Scholz, B. 2006. Nearly optimal register
> allocation with
> +// PBQP. In Proceedings of the 7th Joint Modular Languages
> Conference
> +// (JMLC'06). LNCS, vol. 4228. Springer, New York, NY, USA.
> 346-361.
> +//
> +// (2) Scholz, B., Eckstein, E. 2002. Register allocation for
> irregular
> +// architectures. In Proceedings of the Joint Conference on
> Languages,
> +// Compilers and Tools for Embedded Systems (LCTES'02), ACM
> Press, New York,
> +// NY, USA, 139-148.
> +//
> +// Author: Lang Hames
> +// Email: lhames at gmail.com
> +//
> +//
> =
> =
> =
> ----------------------------------------------------------------------=
> ==//
> +
> +// TODO:
> +//
> +// * Use of std::set in constructPBQPProblem destroys allocation
> order preference.
> +// Switch to an order preserving container.
> +//
> +// * Coalescing support.
> +
> +#define DEBUG_TYPE "regalloc"
> +
> +#include "PBQP.h"
> +#include "VirtRegMap.h"
> +#include "llvm/CodeGen/MachineFunctionPass.h"
> +#include "llvm/CodeGen/RegAllocRegistry.h"
> +#include "llvm/CodeGen/LiveIntervalAnalysis.h"
> +#include "llvm/CodeGen/MachineRegisterInfo.h"
> +#include "llvm/CodeGen/MachineLoopInfo.h"
> +#include "llvm/Target/TargetMachine.h"
> +#include "llvm/Target/TargetInstrInfo.h"
> +#include "llvm/Support/Debug.h"
> +#include <memory>
> +#include <map>
> +#include <set>
> +#include <vector>
> +#include <limits>
> +
> +using namespace llvm;
> +
> +static RegisterRegAlloc
> +registerPBQPRepAlloc("pbqp", " PBQP register allocator",
> + createPBQPRegisterAllocator);
> +
> +
> +namespace {
> +
> + //!
> + //! 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.
> + PBQPRegAlloc() : MachineFunctionPass((intptr_t)&ID) {}
> +
> + //! Return the pass name.
> + virtual const char* getPassName() const throw() {
> + return "PBQP Register Allocator";
> + }
> +
> + //! PBQP analysis usage.
> + virtual void getAnalysisUsage(AnalysisUsage &au) const {
> + au.addRequired<LiveIntervals>();
> + au.addRequired<MachineLoopInfo>();
> + MachineFunctionPass::getAnalysisUsage(au);
> + }
> +
> + //! Perform register allocation
> + virtual bool runOnMachineFunction(MachineFunction &MF);
> +
> + private:
> + typedef std::map<const LiveInterval*, unsigned> LI2NodeMap;
> + typedef std::vector<const LiveInterval*> Node2LIMap;
> + typedef std::vector<unsigned> AllowedSet;
> + typedef std::vector<AllowedSet> AllowedSetMap;
> + typedef std::set<unsigned> IgnoreSet;
> +
> + MachineFunction *mf;
> + const TargetMachine *tm;
> + const TargetRegisterInfo *tri;
> + const TargetInstrInfo *tii;
> + const MachineLoopInfo *loopInfo;
> + MachineRegisterInfo *mri;
> +
> + LiveIntervals *li;
> + VirtRegMap *vrm;
> +
> + LI2NodeMap li2Node;
> + Node2LIMap node2LI;
> + AllowedSetMap allowedSets;
> + IgnoreSet ignoreSet;
> +
> + //! Builds a PBQP cost vector.
> + template <typename Container>
> + PBQPVector* buildCostVector(const Container &allowed,
> + PBQPNum spillCost) const;
> +
> + //! \brief Builds a PBQP interfernce 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 <typename Container>
> + PBQPMatrix* buildInterferenceMatrix(const Container &allowed1,
> + const Container &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.
> + template <typename Container>
> + PBQPMatrix* buildCoalescingMatrix(const Container &allowed1,
> + const Container &allowed2,
> + PBQPNum cBenefit) const;
> +
> + //! \brief Helper functior for constructInitialPBQPProblem().
> + //!
> + //! This function iterates over the Function we are about to
> allocate for
> + //! and computes spill costs.
> + void calcSpillCosts();
> +
> + //! \brief Scans the MachineFunction being allocated to find
> coalescing
> + // opportunities.
> + void findCoalescingOpportunities();
> +
> + //! \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 Given a solved PBQP problem maps this solution back
> to a register
> + //! assignment.
> + bool mapPBQPToRegAlloc(pbqp *problem);
> +
> + };
> +
> + char PBQPRegAlloc::ID = 0;
> +}
> +
> +
> +template <typename Container>
> +PBQPVector* PBQPRegAlloc::buildCostVector(const Container &allowed,
> + PBQPNum spillCost) const {
> +
> + // Allocate vector. Additional element (0th) used for spill option
> + PBQPVector *v = new PBQPVector(allowed.size() + 1);
> +
> + (*v)[0] = spillCost;
> +
> + return v;
> +}
> +
> +template <typename Container>
> +PBQPMatrix* PBQPRegAlloc::buildInterferenceMatrix(
> + const Container &allowed1, const Container &allowed2) const {
> +
> + typedef typename Container::const_iterator ContainerIterator;
> +
> + // Construct a PBQP matrix representing the cost of allocation
> options. The
> + // rows and columns correspond to the allocation options for the
> two live
> + // intervals. Elements will be infinite where corresponding
> registers alias,
> + // since we cannot allocate aliasing registers to interfering
> live intervals.
> + // All other elements (non-aliasing combinations) will have zero
> cost. Note
> + // 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);
> +
> + // Assume this is a zero matrix until proven otherwise. Zero
> matrices occur
> + // between interfering live ranges with non-overlapping register
> sets (e.g.
> + // non-overlapping reg classes, or disjoint sets of allowed regs
> within the
> + // same class). The term "overlapping" is used advisedly: sets
> which do not
> + // intersect, but contain registers which alias, will have non-
> zero matrices.
> + // We optimize zero matrices away to improve solver speed.
> + bool isZeroMatrix = true;
> +
> +
> + // Row index. Starts at 1, since the 0th row is for the spill
> option, which
> + // is always zero.
> + unsigned ri = 1;
> +
> + // Iterate over allowed sets, insert infinities where required.
> + for (ContainerIterator a1Itr = allowed1.begin(), a1End =
> allowed1.end();
> + a1Itr != a1End; ++a1Itr) {
> +
> + // Column index, starts at 1 as for row index.
> + unsigned ci = 1;
> + unsigned reg1 = *a1Itr;
> +
> + for (ContainerIterator a2Itr = allowed2.begin(), a2End =
> allowed2.end();
> + a2Itr != a2End; ++a2Itr) {
> +
> + unsigned reg2 = *a2Itr;
> +
> + // 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<PBQPNum>::infinity();
> + isZeroMatrix = false;
> + }
> +
> + ++ci;
> + }
> +
> + ++ri;
> + }
> +
> + // If this turns out to be a zero matrix...
> + if (isZeroMatrix) {
> + // free it and return null.
> + delete m;
> + return 0;
> + }
> +
> + // ...otherwise return the cost matrix.
> + return m;
> +}
> +
> +void PBQPRegAlloc::calcSpillCosts() {
> +
> + // Calculate the spill cost for each live interval by iterating
> over the
> + // function counting loads and stores, with loop depth taken into
> account.
> + for (MachineFunction::const_iterator bbItr = mf->begin(), bbEnd =
> mf->end();
> + bbItr != bbEnd; ++bbItr) {
> +
> + const MachineBasicBlock *mbb = &*bbItr;
> + float loopDepth = loopInfo->getLoopDepth(mbb);
> +
> + for (MachineBasicBlock::const_iterator
> + iItr = mbb->begin(), iEnd = mbb->end(); iItr != iEnd; +
> +iItr) {
> +
> + const MachineInstr *instr = &*iItr;
> +
> + for (unsigned opNo = 0; opNo < instr->getNumOperands(); +
> +opNo) {
> +
> + const MachineOperand &mo = instr->getOperand(opNo);
> +
> + // We're not interested in non-registers...
> + if (!mo.isRegister())
> + continue;
> +
> + unsigned moReg = mo.getReg();
> +
> + // ...Or invalid registers...
> + if (moReg == 0)
> + continue;
> +
> + // ...Or physical registers...
> + if (TargetRegisterInfo::isPhysicalRegister(moReg))
> + continue;
> +
> + assert ((mo.isUse() || mo.isDef()) &&
> + "Not a use, not a def, what is it?");
> +
> + //... Just the virtual registers. We treat loads and stores as
> equal.
> + li->getInterval(moReg).weight += powf(10.0f, loopDepth);
> + }
> +
> + }
> +
> + }
> +
> +}
> +
> +pbqp* PBQPRegAlloc::constructPBQPProblem() {
> +
> + typedef std::vector<const LiveInterval*> LIVector;
> + typedef std::set<unsigned> RegSet;
> +
> + // These will store the physical & virtual intervals, respectively.
> + LIVector physIntervals, virtIntervals;
> +
> + // Start by clearing the old node <-> live interval mappings &
> allowed sets
> + li2Node.clear();
> + node2LI.clear();
> + allowedSets.clear();
> +
> + // Iterate over intervals classifying them as physical or
> virtual, and
> + // constructing live interval <-> node number mappings.
> + for (LiveIntervals::iterator itr = li->begin(), end = li->end();
> + itr != end; ++itr) {
> +
> + if (itr->second->getNumValNums() != 0) {
> + DOUT << "Live range has " << itr->second->getNumValNums() <<
> ": " << itr->second << "\n";
> + }
> +
> + if (TargetRegisterInfo::isPhysicalRegister(itr->first)) {
> + physIntervals.push_back(itr->second);
> + mri->setPhysRegUsed(itr->second->reg);
> + }
> + else {
> +
> + // If we've allocated this virtual register interval a stack
> slot on a
> + // previous round then it's not an allocation candidate
> + if (ignoreSet.find(itr->first) != ignoreSet.end())
> + continue;
> +
> + li2Node[itr->second] = node2LI.size();
> + node2LI.push_back(itr->second);
> + virtIntervals.push_back(itr->second);
> + }
> + }
> +
> + // Early out if there's no regs to allocate for.
> + if (virtIntervals.empty())
> + return 0;
> +
> + // Construct a PBQP solver for this problem
> + pbqp *solver = alloc_pbqp(virtIntervals.size());
> +
> + // Resize allowedSets container appropriately.
> + allowedSets.resize(virtIntervals.size());
> +
> + // Iterate over virtual register intervals to compute allowed
> sets...
> + for (unsigned node = 0; node < node2LI.size(); ++node) {
> +
> + // Grab pointers to the interval and its register class.
> + const LiveInterval *li = node2LI[node];
> + const TargetRegisterClass *liRC = mri->getRegClass(li->reg);
> +
> + // Start by assuming all allocable registers in the class are
> allowed...
> + RegSet liAllowed(liRC->allocation_order_begin(*mf),
> + liRC->allocation_order_end(*mf));
> +
> + // If this range is non-empty then eliminate the physical
> registers which
> + // overlap with this range, along with all their aliases.
> + if (!li->empty()) {
> + for (LIVector::iterator pItr = physIntervals.begin(),
> + pEnd = physIntervals.end(); pItr != pEnd; ++pItr) {
> +
> + if (li->overlaps(**pItr)) {
> +
> + unsigned pReg = (*pItr)->reg;
> +
> + // Remove the overlapping reg...
> + liAllowed.erase(pReg);
> +
> + const unsigned *aliasItr = tri->getAliasSet(pReg);
> +
> + if (aliasItr != 0) {
> + // ...and its aliases.
> + for (; *aliasItr != 0; ++aliasItr) {
> + liAllowed.erase(*aliasItr);
> + }
> +
> + }
> +
> + }
> +
> + }
> +
> + }
> +
> + // Copy the allowed set into a member vector for use when
> constructing cost
> + // vectors & matrices, and mapping PBQP solutions back to
> assignments.
> + allowedSets[node] = AllowedSet(liAllowed.begin(),
> liAllowed.end());
> +
> + // 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<PBQPNum>::min();
> +
> + // Build a cost vector for this interval.
> + add_pbqp_nodecosts(solver, node,
> + buildCostVector(allowedSets[node],
> spillCost));
> +
> + }
> +
> + // Now add the cost matrices...
> + for (unsigned node1 = 0; node1 < node2LI.size(); ++node1) {
> +
> + const LiveInterval *li = node2LI[node1];
> +
> + if (li->empty())
> + continue;
> +
> + // Test for live range overlaps and insert interference matrices.
> + for (unsigned node2 = node1 + 1; node2 < node2LI.size(); +
> +node2) {
> + const LiveInterval *li2 = node2LI[node2];
> +
> + if (li2->empty())
> + continue;
> +
> + if (li->overlaps(*li2)) {
> + PBQPMatrix *m =
> + buildInterferenceMatrix(allowedSets[node1],
> allowedSets[node2]);
> +
> + if (m != 0) {
> + add_pbqp_edgecosts(solver, node1, node2, m);
> + delete m;
> + }
> + }
> + }
> + }
> +
> + // We're done, PBQP problem constructed - return it.
> + return solver;
> +}
> +
> +bool PBQPRegAlloc::mapPBQPToRegAlloc(pbqp *problem) {
> +
> + // Set to true if we have any spills
> + bool anotherRoundNeeded = false;
> +
> + // Clear the existing allocation.
> + vrm->clearAllVirt();
> +
> + // Iterate over the nodes mapping the PBQP solution to a register
> assignment.
> + for (unsigned node = 0; node < node2LI.size(); ++node) {
> + unsigned symReg = node2LI[node]->reg,
> + allocSelection = get_pbqp_solution(problem, node);
> +
> + // If the PBQP solution is non-zero it's a physical register...
> + if (allocSelection != 0) {
> + // Get the physical reg, subtracting 1 to account for the
> spill option.
> + unsigned physReg = allowedSets[node][allocSelection - 1];
> +
> + // Add to the virt reg map and update the used phys regs.
> + vrm->assignVirt2Phys(symReg, physReg);
> + mri->setPhysRegUsed(physReg);
> + }
> + // ...Otherwise it's a spill.
> + else {
> +
> + // Make sure we ignore this virtual reg on the next round
> + // of allocation
> + ignoreSet.insert(node2LI[node]->reg);
> +
> + float SSWeight;
> +
> + // Insert spill ranges for this live range
> + SmallVector<LiveInterval*, 8> spillIs;
> + std::vector<LiveInterval*> newSpills =
> + li->addIntervalsForSpills(*node2LI[node], spillIs,
> loopInfo, *vrm,
> + SSWeight);
> +
> + // We need another round if spill intervals were added.
> + anotherRoundNeeded |= !newSpills.empty();
> + }
> + }
> +
> + return !anotherRoundNeeded;
> +}
> +
> +bool PBQPRegAlloc::runOnMachineFunction(MachineFunction &MF) {
> +
> + mf = &MF;
> + tm = &mf->getTarget();
> + tri = tm->getRegisterInfo();
> + mri = &mf->getRegInfo();
> +
> + li = &getAnalysis<LiveIntervals>();
> + loopInfo = &getAnalysis<MachineLoopInfo>();
> +
> + std::auto_ptr<VirtRegMap> vrmAutoPtr(new VirtRegMap(*mf));
> + vrm = vrmAutoPtr.get();
> +
> + // Allocator main loop:
> + //
> + // * Map current regalloc problem to a PBQP problem
> + // * Solve the PBQP problem
> + // * Map the solution back to a register allocation
> + // * Spill if necessary
> + //
> + // This process is continued till no more spills are generated.
> +
> + bool regallocComplete = false;
> +
> + // Calculate spill costs for intervals
> + calcSpillCosts();
> +
> + while (!regallocComplete) {
> + pbqp *problem = constructPBQPProblem();
> +
> + // Fast out if there's no problem to solve.
> + if (problem == 0)
> + return true;
> +
> + solve_pbqp(problem);
> +
> + regallocComplete = mapPBQPToRegAlloc(problem);
> +
> + free_pbqp(problem);
> + }
> +
> + ignoreSet.clear();
> +
> + std::auto_ptr<Spiller> spiller(createSpiller());
> +
> + spiller->runOnMachineFunction(*mf, *vrm);
> +
> + return true;
> +}
> +
> +FunctionPass* llvm::createPBQPRegisterAllocator() {
> + return new PBQPRegAlloc();
> +}
> +
> +
> +#undef DEBUG_TYPE
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
-------------- next part --------------
A non-text attachment was scrubbed...
Name: smime.p7s
Type: application/pkcs7-signature
Size: 2624 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20081003/405e75f6/attachment.bin>
More information about the llvm-commits
mailing list