On Aug-07, Leopold Toetsch wrote:
> Sean O'Rourke <[EMAIL PROTECTED]> wrote:
> > [EMAIL PROTECTED] (Leopold Toetsch) writes:
> >> The interference_graph size is n_symbols * n_symbols *
> >> sizeof(a_pointer). This might already be too much.
> >>
> >> 2) There is a note in the source code that the interference graph could
> >> be done without the N x N graph array. Any hints welcome (Angel Faus!).
>
> > It looks like the way things are used in the code, you can use an
> > adjacency list instead of the current adjacency matrix for the graph.
>
> Yeah. Or a bitmap.
An adjacency list would definitely be much smaller, but I'd be
concerned that it would slow down searches too much. I think the
bitmap might be worth a try just to see how much the size matters.
Since this is an n^2 issue, splitting out the four different register
types could help -- except that I'd guess that most code with
excessive register usage probably uses one type of register much more
than the rest.
Anyway, I've attached a patch that uses bitmaps instead of SymReg*'s,
which should give a factor of 32 size reduction. I've only tested it
by doing a 'make test' and verifying that the several dozen test
failures are the same before and after (I don't think things are
actually that broken; I think the make system is), but for all I know
it's not even calling the code. That's what you get when I only have a
two hour hacking window and I've never looked at the code before.
> Or still better, create the interference graph per basic block.
> Should be much smaller then.
Huh? Is register allocation done wholly within basic blocks? I thought
the point of the graph was to compute interference across basic
blocks. I guess I should go and actually read the code.
Index: imcc/reg_alloc.c
===================================================================
RCS file: /cvs/public/parrot/imcc/reg_alloc.c,v
retrieving revision 1.14
diff -u -r1.14 reg_alloc.c
--- imcc/reg_alloc.c 23 Apr 2004 14:09:33 -0000 1.14
+++ imcc/reg_alloc.c 7 Aug 2004 07:11:08 -0000
@@ -41,7 +41,7 @@
static void compute_du_chain(IMC_Unit * unit);
static void compute_one_du_chain(SymReg * r, IMC_Unit * unit);
static int interferes(IMC_Unit *, SymReg * r0, SymReg * r1);
-static int map_colors(int x, SymReg ** graph, int colors[], int typ);
+static int map_colors(IMC_Unit *, int x, int * graph, int colors[], int typ);
#ifdef DO_SIMPLIFY
static int simplify (IMC_Unit *);
#endif
@@ -58,12 +58,46 @@
/* XXX FIXME: Globals: */
static IMCStack nodeStack;
-static SymReg** interference_graph;
-/*
-static SymReg** reglist;
-*/
+static int* interference_graph;
static int n_symbols;
+static int* ig_get_word(int i, int j, int N, int* graph, int* bit_ofs)
+{
+ int bit = i * N + j;
+ *bit_ofs = bit % sizeof(*graph);
+ return &graph[bit / sizeof(*graph)];
+}
+
+static void ig_set(int i, int j, int N, int* graph)
+{
+ int bit_ofs;
+ int* word = ig_get_word(i, j, N, graph, &bit_ofs);
+ *word |= (1 << bit_ofs);
+}
+
+static void ig_clear(int i, int j, int N, int* graph)
+{
+ int bit_ofs;
+ int* word = ig_get_word(i, j, N, graph, &bit_ofs);
+ *word &= ~(1 << bit_ofs);
+}
+
+static int ig_test(int i, int j, int N, int* graph)
+{
+ int bit_ofs;
+ int* word = ig_get_word(i, j, N, graph, &bit_ofs);
+ return *word & (1 << bit_ofs);
+}
+
+static int* ig_allocate(int N)
+{
+ // size is N*N bits, but we want don't want to allocate a partial
+ // word, so round up to the nearest multiple of sizeof(int).
+ int need_bits = N * N;
+ int num_words = (need_bits + sizeof(int) - 1) / sizeof(int);
+ return (int*) calloc(num_words, sizeof(int));
+}
+
/* imc_reg_alloc is the main loop of the allocation algorithm. It operates
* on a single compilation unit at a time.
*/
@@ -446,6 +480,12 @@
/* creates the interference graph between the variables.
*
+ * data structure is a 2-d array 'interference_graph' where row/column
+ * indices represent the same index in the list of all symbols
+ * (unit->reglist) in the current compilation unit. The value in the
+ * 2-d array interference_graph[i][j] is the symbol unit->reglist[j]
+ * itself.
+ *
* two variables interfere when they are alive at the
* same time
*/
@@ -461,7 +501,7 @@
/* Construct a graph N x N where N = number of symbolics.
* This piece can be rewritten without the N x N array
*/
- interference_graph = calloc(n_symbols * n_symbols, sizeof(SymReg*));
+ interference_graph = ig_allocate(n_symbols);
if (interference_graph == NULL)
fatal(1, "build_interference_graph","Out of mem\n");
unit->interference_graph = interference_graph;
@@ -475,8 +515,8 @@
if (!unit->reglist[y]->first_ins)
continue;
if (interferes(unit, unit->reglist[x], unit->reglist[y])) {
- interference_graph[x*n_symbols+y] = unit->reglist[y];
- interference_graph[y*n_symbols+x] = unit->reglist[x];
+ ig_set(x, y, n_symbols, interference_graph);
+ ig_set(y, x, n_symbols, interference_graph);
}
}
}
@@ -801,8 +841,7 @@
allocate_wanted_regs(IMC_Unit * unit)
{
int i, y, interf;
- SymReg *r, *s;
- SymReg ** graph = interference_graph;
+ SymReg *r;
for (i = 0; i < n_symbols; i++) {
r = unit->reglist[i];
@@ -810,9 +849,13 @@
continue;
interf = 0;
for (y = 0; y < n_symbols; y++) {
- if ((s = graph[i*n_symbols+y])
- && s->color == r->want_regno
- && s->set == r->set) {
+ SymReg *s;
+ if (! ig_test(i, y, n_symbols, interference_graph))
+ continue;
+ s = unit->reglist[y];
+ if ( s
+ && s->color == r->want_regno
+ && s->set == r->set) {
interf = 1;
}
}
@@ -835,7 +878,7 @@
int x = 0;
int color, colors[MAX_COLOR];
int free_colors, t;
- SymReg ** graph = interference_graph;
+ int *graph = interference_graph;
SymReg ** reglist = unit->reglist;
while ((imcstack_depth(nodeStack) > 0) ) {
@@ -845,7 +888,7 @@
int typ = "INSP"[t];
memset(colors, 0, sizeof(colors));
if (reglist[x]->set == typ && reglist[x]->color == -1) {
- free_colors = map_colors(x, graph, colors, typ);
+ free_colors = map_colors(unit, x, graph, colors, typ);
if (free_colors > 0) {
for (color = 0; color < MAX_COLOR; color++) {
int c = (color + 16) % 32;
@@ -886,7 +929,7 @@
* map_colors: calculates what colors can be assigned to the x-th symbol.
*/
static int
-map_colors(int x, SymReg ** graph, int colors[], int typ)
+map_colors(IMC_Unit* unit, int x, int *graph, int colors[], int typ)
{
int y = 0;
SymReg * r;
@@ -901,7 +944,10 @@
colors[30] = 1; /* for immediate allocation */
#endif
for (y = 0; y < n_symbols; y++) {
- if ((r = graph[x*n_symbols+y])
+ if (! ig_test(x, y, n_symbols, graph))
+ continue;
+ r = unit->reglist[y];
+ if ( r
&& r->color != -1
&& r->set == typ) {
colors[r->color] = 1;
@@ -985,13 +1031,15 @@
SymReg ** reglist = unit->reglist;
if (old != new) {
/* n_symbols is already increased */
- SymReg ** new_graph = calloc(n_symbols * n_symbols, sizeof(SymReg*));
+ int *new_graph = ig_allocate(n_symbols);
/* old symbols count of previous graph */
int o = n_symbols - 1;
for (x = 0; x < o; x++) {
for (y = x + 1; y < o; y++) {
- new_graph[x*n_symbols+y] = interference_graph[x*o+y];
- new_graph[y*n_symbols+x] = interference_graph[y*o+x];
+ if (ig_test(x, y, o, interference_graph)) {
+ ig_set(x, y, n_symbols, new_graph);
+ ig_set(y, x, n_symbols, new_graph);
+ }
}
}
free(interference_graph);
@@ -1002,12 +1050,12 @@
if (reglist[x] == old || reglist[x] == new ||
reglist[y] == old || reglist[y] == new) {
if (interferes(unit, reglist[x], reglist[y])) {
- interference_graph[x*n_symbols+y] = reglist[y];
- interference_graph[y*n_symbols+x] = reglist[x];
+ ig_set(x, y, n_symbols, interference_graph);
+ ig_set(y, x, n_symbols, interference_graph);
}
else {
- interference_graph[x*n_symbols+y] = NULL;
- interference_graph[y*n_symbols+x] = NULL;
+ ig_clear(x, y, n_symbols, interference_graph);
+ ig_clear(y, x, n_symbols, interference_graph);
}
}
}
@@ -1151,27 +1199,6 @@
}
-#if 0
-static int
-neighbours(int node)
-{
- int y, cnt;
- SymReg *r;
-
- cnt = 0;
- for (y = 0; y < n_symbols; y++) {
-
- if ( (r = interference_graph[node*n_symbols + y] ) &&
- (!r->simplified) ) {
- cnt++;
- }
- }
-
- return cnt;
-}
-#endif
-
-
/*
* Local variables:
* c-indentation-style: bsd
Index: imcc/unit.h
===================================================================
RCS file: /cvs/public/parrot/imcc/unit.h,v
retrieving revision 1.6
diff -u -r1.6 unit.h
--- imcc/unit.h 22 Apr 2004 08:55:01 -0000 1.6
+++ imcc/unit.h 7 Aug 2004 07:11:08 -0000
@@ -31,7 +31,7 @@
/* register allocation */
int n_spilled;
SymReg * p31;
- SymReg** interference_graph;
+ int* interference_graph;
SymReg** reglist;
int n_symbols;
struct _IMC_Unit * prev;