[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

Lang Hames lhames at gmail.com
Sat Oct 4 01:11:47 PDT 2008


I just checked MultiSource on my Ubuntu AMD64 box using

make DISABLE_LLI=1 DISABLE_JIT=1 DISABLE_CBE=1 ENABLE_LLC=1 ENABLE_LLCBETA=1

where LLCBETA uses -regalloc=pbqp

both LLC & LLCBETA fail oggenc, kc, tramp3d-v4. LLCBETA also fails
ldecod. I am currently looking into this, however the long weekend
here in Australia may hamper efforts for a day or two. ;)

I am aware of a SingleSource failure on the TLS unit test too. This
seems to me to be a problem exposed by the PBQP allocator's lack of
coalescing support, but I'm not familiar enough with tls to be sure.
Certainly the same bug appeared when the simple, local or bigblock
allocators were used (again on my Ubuntu AMD64 box).

The PBQP allocator is not ready for production yet - it has not been
optimised, and the lack of coalescing support leads to poor execution
times for compiled programs. It is, however (imho), very easy to
understand, and I'm hoping (with your feedback) to see big
improvements soon.

Cheers,
Lang.



On Sat, Oct 4, 2008 at 7:35 AM, Evan Cheng <evan.cheng at apple.com> wrote:
> I don't think it's quite meant for production yet. I saw some failures when
> running on MultiSource. Lang?
>
> Evan
>
> On Oct 3, 2008, at 1:43 PM, Owen Anderson wrote:
>
>> 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
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
>



More information about the llvm-commits mailing list