[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