i965: Ask the register allocator to round-robin through registers.
authorEric Anholt <eric@anholt.net>
Sat, 1 Dec 2012 00:34:09 +0000 (16:34 -0800)
committerEric Anholt <eric@anholt.net>
Thu, 4 Apr 2013 19:51:06 +0000 (12:51 -0700)
The way we were allocating registers before, packing into low register
numbers for Ironlake, resulted in an overly-constrained dependency graph
for instruction scheduling.  Improves GLBenchmark 2.1 performance by
4.5% +/- 0.7% (n=26).  No difference on my old GLSL demo (n=20).  No
difference on nexuiz (n=15).

v2: Fix off-by-one bug that made the change only work for 16-wide on i965.
Reviewed-by: Matt Turner <mattst88@gmail.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp
src/mesa/program/register_allocate.c
src/mesa/program/register_allocate.h

index 4ee7bbc66593b3c97dd8cdd7887384d6c4f6a576..b9b030317ae5cc06b9502e8a79ceefcb2d034ff6 100644 (file)
@@ -108,6 +108,8 @@ brw_alloc_reg_set(struct brw_context *brw, int reg_width)
 
    uint8_t *ra_reg_to_grf = ralloc_array(brw, uint8_t, ra_reg_count);
    struct ra_regs *regs = ra_alloc_reg_set(brw, ra_reg_count);
+   if (intel->gen >= 6)
+      ra_set_allocate_round_robin(regs);
    int *classes = ralloc_array(brw, int, class_count);
    int aligned_pairs_class = -1;
 
index a9064c38ca2792b1b59c2a8ceb0bd8e034f8c53d..2c826fc6604b9f52ef62f7a37f25d9c37ee20afa 100644 (file)
@@ -70,6 +70,7 @@
  * this during ra_set_finalize().
  */
 
+#include <stdbool.h>
 #include <ralloc.h>
 
 #include "main/imports.h"
@@ -93,6 +94,8 @@ struct ra_regs {
 
    struct ra_class **classes;
    unsigned int class_count;
+
+   bool round_robin;
 };
 
 struct ra_class {
@@ -185,6 +188,22 @@ ra_alloc_reg_set(void *mem_ctx, unsigned int count)
    return regs;
 }
 
+/**
+ * The register allocator by default prefers to allocate low register numbers,
+ * since it was written for hardware (gen4/5 Intel) that is limited in its
+ * multithreadedness by the number of registers used in a given shader.
+ *
+ * However, for hardware without that restriction, densely packed register
+ * allocation can put serious constraints on instruction scheduling.  This
+ * function tells the allocator to rotate around the registers if possible as
+ * it allocates the nodes.
+ */
+void
+ra_set_allocate_round_robin(struct ra_regs *regs)
+{
+   regs->round_robin = true;
+}
+
 static void
 ra_add_conflict_list(struct ra_regs *regs, unsigned int r1, unsigned int r2)
 {
@@ -436,16 +455,19 @@ GLboolean
 ra_select(struct ra_graph *g)
 {
    int i;
+   int start_search_reg = 0;
 
    while (g->stack_count != 0) {
-      unsigned int r;
+      unsigned int ri;
+      unsigned int r = -1;
       int n = g->stack[g->stack_count - 1];
       struct ra_class *c = g->regs->classes[g->nodes[n].class];
 
       /* Find the lowest-numbered reg which is not used by a member
        * of the graph adjacent to us.
        */
-      for (r = 0; r < g->regs->count; r++) {
+      for (ri = 0; ri < g->regs->count; ri++) {
+         r = (start_search_reg + ri) % g->regs->count;
         if (!c->regs[r])
            continue;
 
@@ -461,12 +483,15 @@ ra_select(struct ra_graph *g)
         if (i == g->nodes[n].adjacency_count)
            break;
       }
-      if (r == g->regs->count)
+      if (ri == g->regs->count)
         return GL_FALSE;
 
       g->nodes[n].reg = r;
       g->nodes[n].in_stack = GL_FALSE;
       g->stack_count--;
+
+      if (g->regs->round_robin)
+         start_search_reg = r + 1;
    }
 
    return GL_TRUE;
index 2a9d61191039125629d3c1608e0e876c352a29c8..fa119e320f7aae3e7b29091e8f86ec6ccd671954 100644 (file)
@@ -37,6 +37,7 @@ struct ra_regs;
  * two real registers from which they are composed.
  */
 struct ra_regs *ra_alloc_reg_set(void *mem_ctx, unsigned int count);
+void ra_set_allocate_round_robin(struct ra_regs *regs);
 unsigned int ra_alloc_reg_class(struct ra_regs *regs);
 void ra_add_reg_conflict(struct ra_regs *regs,
                         unsigned int r1, unsigned int r2);