OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [conflict.c] - Diff between revs 154 and 816

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 154 Rev 816
/* Register conflict graph computation routines.
/* Register conflict graph computation routines.
   Copyright (C) 2000, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
   Copyright (C) 2000, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
   Contributed by CodeSourcery, LLC
   Contributed by CodeSourcery, LLC
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
/* References:
/* References:
 
 
   Building an Optimizing Compiler
   Building an Optimizing Compiler
   Robert Morgan
   Robert Morgan
   Butterworth-Heinemann, 1998 */
   Butterworth-Heinemann, 1998 */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "coretypes.h"
#include "coretypes.h"
#include "tm.h"
#include "tm.h"
#include "obstack.h"
#include "obstack.h"
#include "hashtab.h"
#include "hashtab.h"
#include "rtl.h"
#include "rtl.h"
#include "hard-reg-set.h"
#include "hard-reg-set.h"
#include "basic-block.h"
#include "basic-block.h"
 
 
/* A register conflict graph is an undirected graph containing nodes
/* A register conflict graph is an undirected graph containing nodes
   for some or all of the regs used in a function.  Arcs represent
   for some or all of the regs used in a function.  Arcs represent
   conflicts, i.e. two nodes are connected by an arc if there is a
   conflicts, i.e. two nodes are connected by an arc if there is a
   point in the function at which the regs corresponding to the two
   point in the function at which the regs corresponding to the two
   nodes are both live.
   nodes are both live.
 
 
   The conflict graph is represented by the data structures described
   The conflict graph is represented by the data structures described
   in Morgan section 11.3.1.  Nodes are not stored explicitly; only
   in Morgan section 11.3.1.  Nodes are not stored explicitly; only
   arcs are.  An arc stores the numbers of the regs it connects.
   arcs are.  An arc stores the numbers of the regs it connects.
 
 
   Arcs can be located by two methods:
   Arcs can be located by two methods:
 
 
     - The two reg numbers for each arc are hashed into a single
     - The two reg numbers for each arc are hashed into a single
       value, and the arc is placed in a hash table according to this
       value, and the arc is placed in a hash table according to this
       value.  This permits quick determination of whether a specific
       value.  This permits quick determination of whether a specific
       conflict is present in the graph.
       conflict is present in the graph.
 
 
     - Additionally, the arc data structures are threaded by a set of
     - Additionally, the arc data structures are threaded by a set of
       linked lists by single reg number.  Since each arc references
       linked lists by single reg number.  Since each arc references
       two regs, there are two next pointers, one for the
       two regs, there are two next pointers, one for the
       smaller-numbered reg and one for the larger-numbered reg.  This
       smaller-numbered reg and one for the larger-numbered reg.  This
       permits the quick enumeration of conflicts for a single
       permits the quick enumeration of conflicts for a single
       register.
       register.
 
 
   Arcs are allocated from an obstack.  */
   Arcs are allocated from an obstack.  */
 
 
/* An arc in a conflict graph.  */
/* An arc in a conflict graph.  */
 
 
struct conflict_graph_arc_def
struct conflict_graph_arc_def
{
{
  /* The next element of the list of conflicts involving the
  /* The next element of the list of conflicts involving the
     smaller-numbered reg, as an index in the table of arcs of this
     smaller-numbered reg, as an index in the table of arcs of this
     graph.   Contains NULL if this is the tail.  */
     graph.   Contains NULL if this is the tail.  */
  struct conflict_graph_arc_def *smaller_next;
  struct conflict_graph_arc_def *smaller_next;
 
 
  /* The next element of the list of conflicts involving the
  /* The next element of the list of conflicts involving the
     larger-numbered reg, as an index in the table of arcs of this
     larger-numbered reg, as an index in the table of arcs of this
     graph.  Contains NULL if this is the tail.  */
     graph.  Contains NULL if this is the tail.  */
  struct conflict_graph_arc_def *larger_next;
  struct conflict_graph_arc_def *larger_next;
 
 
  /* The smaller-numbered reg involved in this conflict.  */
  /* The smaller-numbered reg involved in this conflict.  */
  int smaller;
  int smaller;
 
 
  /* The larger-numbered reg involved in this conflict.  */
  /* The larger-numbered reg involved in this conflict.  */
  int larger;
  int larger;
};
};
 
 
typedef struct conflict_graph_arc_def *conflict_graph_arc;
typedef struct conflict_graph_arc_def *conflict_graph_arc;
typedef const struct conflict_graph_arc_def *const_conflict_graph_arc;
typedef const struct conflict_graph_arc_def *const_conflict_graph_arc;
 
 
 
 
/* A conflict graph.  */
/* A conflict graph.  */
 
 
struct conflict_graph_def
struct conflict_graph_def
{
{
  /* A hash table of arcs.  Used to search for a specific conflict.  */
  /* A hash table of arcs.  Used to search for a specific conflict.  */
  htab_t arc_hash_table;
  htab_t arc_hash_table;
 
 
  /* The number of regs this conflict graph handles.  */
  /* The number of regs this conflict graph handles.  */
  int num_regs;
  int num_regs;
 
 
  /* For each reg, the arc at the head of a list that threads through
  /* For each reg, the arc at the head of a list that threads through
     all the arcs involving that reg.  An entry is NULL if no
     all the arcs involving that reg.  An entry is NULL if no
     conflicts exist involving that reg.  */
     conflicts exist involving that reg.  */
  conflict_graph_arc *neighbor_heads;
  conflict_graph_arc *neighbor_heads;
 
 
  /* Arcs are allocated from here.  */
  /* Arcs are allocated from here.  */
  struct obstack arc_obstack;
  struct obstack arc_obstack;
};
};
 
 
/* The initial capacity (number of conflict arcs) for newly-created
/* The initial capacity (number of conflict arcs) for newly-created
   conflict graphs.  */
   conflict graphs.  */
#define INITIAL_ARC_CAPACITY 64
#define INITIAL_ARC_CAPACITY 64
 
 
 
 
/* Computes the hash value of the conflict graph arc connecting regs
/* Computes the hash value of the conflict graph arc connecting regs
   R1 and R2.  R1 is assumed to be smaller or equal to R2.  */
   R1 and R2.  R1 is assumed to be smaller or equal to R2.  */
#define CONFLICT_HASH_FN(R1, R2) ((R2) * ((R2) - 1) / 2 + (R1))
#define CONFLICT_HASH_FN(R1, R2) ((R2) * ((R2) - 1) / 2 + (R1))
 
 
static hashval_t arc_hash (const void *);
static hashval_t arc_hash (const void *);
static int arc_eq (const void *, const void *);
static int arc_eq (const void *, const void *);
static int print_conflict (int, int, void *);
static int print_conflict (int, int, void *);


/* Callback function to compute the hash value of an arc.  Uses
/* Callback function to compute the hash value of an arc.  Uses
   current_graph to locate the graph to which the arc belongs.  */
   current_graph to locate the graph to which the arc belongs.  */
 
 
static hashval_t
static hashval_t
arc_hash (const void *arcp)
arc_hash (const void *arcp)
{
{
  const_conflict_graph_arc arc = (const_conflict_graph_arc) arcp;
  const_conflict_graph_arc arc = (const_conflict_graph_arc) arcp;
 
 
  return CONFLICT_HASH_FN (arc->smaller, arc->larger);
  return CONFLICT_HASH_FN (arc->smaller, arc->larger);
}
}
 
 
/* Callback function to determine the equality of two arcs in the hash
/* Callback function to determine the equality of two arcs in the hash
   table.  */
   table.  */
 
 
static int
static int
arc_eq (const void *arcp1, const void *arcp2)
arc_eq (const void *arcp1, const void *arcp2)
{
{
  const_conflict_graph_arc arc1 = (const_conflict_graph_arc) arcp1;
  const_conflict_graph_arc arc1 = (const_conflict_graph_arc) arcp1;
  const_conflict_graph_arc arc2 = (const_conflict_graph_arc) arcp2;
  const_conflict_graph_arc arc2 = (const_conflict_graph_arc) arcp2;
 
 
  return arc1->smaller == arc2->smaller && arc1->larger == arc2->larger;
  return arc1->smaller == arc2->smaller && arc1->larger == arc2->larger;
}
}
 
 
/* Creates an empty conflict graph to hold conflicts among NUM_REGS
/* Creates an empty conflict graph to hold conflicts among NUM_REGS
   registers.  */
   registers.  */
 
 
conflict_graph
conflict_graph
conflict_graph_new (int num_regs)
conflict_graph_new (int num_regs)
{
{
  conflict_graph graph = XNEW (struct conflict_graph_def);
  conflict_graph graph = XNEW (struct conflict_graph_def);
  graph->num_regs = num_regs;
  graph->num_regs = num_regs;
 
 
  /* Set up the hash table.  No delete action is specified; memory
  /* Set up the hash table.  No delete action is specified; memory
     management of arcs is through the obstack.  */
     management of arcs is through the obstack.  */
  graph->arc_hash_table
  graph->arc_hash_table
    = htab_create (INITIAL_ARC_CAPACITY, &arc_hash, &arc_eq, NULL);
    = htab_create (INITIAL_ARC_CAPACITY, &arc_hash, &arc_eq, NULL);
 
 
  /* Create an obstack for allocating arcs.  */
  /* Create an obstack for allocating arcs.  */
  obstack_init (&graph->arc_obstack);
  obstack_init (&graph->arc_obstack);
 
 
  /* Create and zero the lookup table by register number.  */
  /* Create and zero the lookup table by register number.  */
  graph->neighbor_heads = XCNEWVEC (conflict_graph_arc, num_regs);
  graph->neighbor_heads = XCNEWVEC (conflict_graph_arc, num_regs);
 
 
  return graph;
  return graph;
}
}
 
 
/* Deletes a conflict graph.  */
/* Deletes a conflict graph.  */
 
 
void
void
conflict_graph_delete (conflict_graph graph)
conflict_graph_delete (conflict_graph graph)
{
{
  obstack_free (&graph->arc_obstack, NULL);
  obstack_free (&graph->arc_obstack, NULL);
  htab_delete (graph->arc_hash_table);
  htab_delete (graph->arc_hash_table);
  free (graph->neighbor_heads);
  free (graph->neighbor_heads);
  free (graph);
  free (graph);
}
}
 
 
/* Adds a conflict to GRAPH between regs REG1 and REG2, which must be
/* Adds a conflict to GRAPH between regs REG1 and REG2, which must be
   distinct.  Returns nonzero, unless the conflict is already present
   distinct.  Returns nonzero, unless the conflict is already present
   in GRAPH, in which case it does nothing and returns zero.  */
   in GRAPH, in which case it does nothing and returns zero.  */
 
 
int
int
conflict_graph_add (conflict_graph graph, int reg1, int reg2)
conflict_graph_add (conflict_graph graph, int reg1, int reg2)
{
{
  int smaller = MIN (reg1, reg2);
  int smaller = MIN (reg1, reg2);
  int larger = MAX (reg1, reg2);
  int larger = MAX (reg1, reg2);
  struct conflict_graph_arc_def dummy;
  struct conflict_graph_arc_def dummy;
  conflict_graph_arc arc;
  conflict_graph_arc arc;
  void **slot;
  void **slot;
 
 
  /* A reg cannot conflict with itself.  */
  /* A reg cannot conflict with itself.  */
  gcc_assert (reg1 != reg2);
  gcc_assert (reg1 != reg2);
 
 
  dummy.smaller = smaller;
  dummy.smaller = smaller;
  dummy.larger = larger;
  dummy.larger = larger;
  slot = htab_find_slot (graph->arc_hash_table, (void *) &dummy, INSERT);
  slot = htab_find_slot (graph->arc_hash_table, (void *) &dummy, INSERT);
 
 
  /* If the conflict is already there, do nothing.  */
  /* If the conflict is already there, do nothing.  */
  if (*slot != NULL)
  if (*slot != NULL)
    return 0;
    return 0;
 
 
  /* Allocate an arc.  */
  /* Allocate an arc.  */
  arc
  arc
    = obstack_alloc (&graph->arc_obstack,
    = obstack_alloc (&graph->arc_obstack,
                     sizeof (struct conflict_graph_arc_def));
                     sizeof (struct conflict_graph_arc_def));
 
 
  /* Record the reg numbers.  */
  /* Record the reg numbers.  */
  arc->smaller = smaller;
  arc->smaller = smaller;
  arc->larger = larger;
  arc->larger = larger;
 
 
  /* Link the conflict into two lists, one for each reg.  */
  /* Link the conflict into two lists, one for each reg.  */
  arc->smaller_next = graph->neighbor_heads[smaller];
  arc->smaller_next = graph->neighbor_heads[smaller];
  graph->neighbor_heads[smaller] = arc;
  graph->neighbor_heads[smaller] = arc;
  arc->larger_next = graph->neighbor_heads[larger];
  arc->larger_next = graph->neighbor_heads[larger];
  graph->neighbor_heads[larger] = arc;
  graph->neighbor_heads[larger] = arc;
 
 
  /* Put it in the hash table.  */
  /* Put it in the hash table.  */
  *slot = (void *) arc;
  *slot = (void *) arc;
 
 
  return 1;
  return 1;
}
}
 
 
/* Returns nonzero if a conflict exists in GRAPH between regs REG1
/* Returns nonzero if a conflict exists in GRAPH between regs REG1
   and REG2.  */
   and REG2.  */
 
 
int
int
conflict_graph_conflict_p (conflict_graph graph, int reg1, int reg2)
conflict_graph_conflict_p (conflict_graph graph, int reg1, int reg2)
{
{
  /* Build an arc to search for.  */
  /* Build an arc to search for.  */
  struct conflict_graph_arc_def arc;
  struct conflict_graph_arc_def arc;
  arc.smaller = MIN (reg1, reg2);
  arc.smaller = MIN (reg1, reg2);
  arc.larger = MAX (reg1, reg2);
  arc.larger = MAX (reg1, reg2);
 
 
  return htab_find (graph->arc_hash_table, (void *) &arc) != NULL;
  return htab_find (graph->arc_hash_table, (void *) &arc) != NULL;
}
}
 
 
/* Calls ENUM_FN for each conflict in GRAPH involving REG.  EXTRA is
/* Calls ENUM_FN for each conflict in GRAPH involving REG.  EXTRA is
   passed back to ENUM_FN.  */
   passed back to ENUM_FN.  */
 
 
void
void
conflict_graph_enum (conflict_graph graph, int reg,
conflict_graph_enum (conflict_graph graph, int reg,
                     conflict_graph_enum_fn enum_fn, void *extra)
                     conflict_graph_enum_fn enum_fn, void *extra)
{
{
  conflict_graph_arc arc = graph->neighbor_heads[reg];
  conflict_graph_arc arc = graph->neighbor_heads[reg];
  while (arc != NULL)
  while (arc != NULL)
    {
    {
      /* Invoke the callback.  */
      /* Invoke the callback.  */
      if ((*enum_fn) (arc->smaller, arc->larger, extra))
      if ((*enum_fn) (arc->smaller, arc->larger, extra))
        /* Stop if requested.  */
        /* Stop if requested.  */
        break;
        break;
 
 
      /* Which next pointer to follow depends on whether REG is the
      /* Which next pointer to follow depends on whether REG is the
         smaller or larger reg in this conflict.  */
         smaller or larger reg in this conflict.  */
      if (reg < arc->larger)
      if (reg < arc->larger)
        arc = arc->smaller_next;
        arc = arc->smaller_next;
      else
      else
        arc = arc->larger_next;
        arc = arc->larger_next;
    }
    }
}
}
 
 
/* For each conflict between a register x and SRC in GRAPH, adds a
/* For each conflict between a register x and SRC in GRAPH, adds a
   conflict to GRAPH between x and TARGET.  */
   conflict to GRAPH between x and TARGET.  */
 
 
void
void
conflict_graph_merge_regs (conflict_graph graph, int target, int src)
conflict_graph_merge_regs (conflict_graph graph, int target, int src)
{
{
  conflict_graph_arc arc = graph->neighbor_heads[src];
  conflict_graph_arc arc = graph->neighbor_heads[src];
 
 
  if (target == src)
  if (target == src)
    return;
    return;
 
 
  while (arc != NULL)
  while (arc != NULL)
    {
    {
      int other = arc->smaller;
      int other = arc->smaller;
 
 
      if (other == src)
      if (other == src)
        other = arc->larger;
        other = arc->larger;
 
 
      conflict_graph_add (graph, target, other);
      conflict_graph_add (graph, target, other);
 
 
      /* Which next pointer to follow depends on whether REG is the
      /* Which next pointer to follow depends on whether REG is the
         smaller or larger reg in this conflict.  */
         smaller or larger reg in this conflict.  */
      if (src < arc->larger)
      if (src < arc->larger)
        arc = arc->smaller_next;
        arc = arc->smaller_next;
      else
      else
        arc = arc->larger_next;
        arc = arc->larger_next;
    }
    }
}
}
 
 
/* Holds context information while a conflict graph is being traversed
/* Holds context information while a conflict graph is being traversed
   for printing.  */
   for printing.  */
 
 
struct print_context
struct print_context
{
{
  /* The file pointer to which we're printing.  */
  /* The file pointer to which we're printing.  */
  FILE *fp;
  FILE *fp;
 
 
  /* The reg whose conflicts we're printing.  */
  /* The reg whose conflicts we're printing.  */
  int reg;
  int reg;
 
 
  /* Whether a conflict has already been printed for this reg.  */
  /* Whether a conflict has already been printed for this reg.  */
  int started;
  int started;
};
};
 
 
/* Callback function when enumerating conflicts during printing.  */
/* Callback function when enumerating conflicts during printing.  */
 
 
static int
static int
print_conflict (int reg1, int reg2, void *contextp)
print_conflict (int reg1, int reg2, void *contextp)
{
{
  struct print_context *context = (struct print_context *) contextp;
  struct print_context *context = (struct print_context *) contextp;
  int reg;
  int reg;
 
 
  /* If this is the first conflict printed for this reg, start a new
  /* If this is the first conflict printed for this reg, start a new
     line.  */
     line.  */
  if (! context->started)
  if (! context->started)
    {
    {
      fprintf (context->fp, " %d:", context->reg);
      fprintf (context->fp, " %d:", context->reg);
      context->started = 1;
      context->started = 1;
    }
    }
 
 
  /* Figure out the reg whose conflicts we're printing.  The other reg
  /* Figure out the reg whose conflicts we're printing.  The other reg
     is the interesting one.  */
     is the interesting one.  */
  if (reg1 == context->reg)
  if (reg1 == context->reg)
    reg = reg2;
    reg = reg2;
  else
  else
    {
    {
      gcc_assert (reg2 == context->reg);
      gcc_assert (reg2 == context->reg);
      reg = reg1;
      reg = reg1;
    }
    }
 
 
  /* Print the conflict.  */
  /* Print the conflict.  */
  fprintf (context->fp, " %d", reg);
  fprintf (context->fp, " %d", reg);
 
 
  /* Continue enumerating.  */
  /* Continue enumerating.  */
  return 0;
  return 0;
}
}
 
 
/* Prints the conflicts in GRAPH to FP.  */
/* Prints the conflicts in GRAPH to FP.  */
 
 
void
void
conflict_graph_print (conflict_graph graph, FILE *fp)
conflict_graph_print (conflict_graph graph, FILE *fp)
{
{
  int reg;
  int reg;
  struct print_context context;
  struct print_context context;
 
 
  context.fp = fp;
  context.fp = fp;
  fprintf (fp, "Conflicts:\n");
  fprintf (fp, "Conflicts:\n");
 
 
  /* Loop over registers supported in this graph.  */
  /* Loop over registers supported in this graph.  */
  for (reg = 0; reg < graph->num_regs; ++reg)
  for (reg = 0; reg < graph->num_regs; ++reg)
    {
    {
      context.reg = reg;
      context.reg = reg;
      context.started = 0;
      context.started = 0;
 
 
      /* Scan the conflicts for reg, printing as we go.  A label for
      /* Scan the conflicts for reg, printing as we go.  A label for
         this line will be printed the first time a conflict is
         this line will be printed the first time a conflict is
         printed for the reg; we won't start a new line if this reg
         printed for the reg; we won't start a new line if this reg
         has no conflicts.  */
         has no conflicts.  */
      conflict_graph_enum (graph, reg, &print_conflict, &context);
      conflict_graph_enum (graph, reg, &print_conflict, &context);
 
 
      /* If this reg does have conflicts, end the line.  */
      /* If this reg does have conflicts, end the line.  */
      if (context.started)
      if (context.started)
        fputc ('\n', fp);
        fputc ('\n', fp);
    }
    }
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.