i965: Unalias all GLSL source regs from the destination regs used.
authorEric Anholt <eric@anholt.net>
Tue, 9 Mar 2010 19:56:14 +0000 (11:56 -0800)
committerEric Anholt <eric@anholt.net>
Tue, 9 Mar 2010 22:42:17 +0000 (14:42 -0800)
We were doing it ad-hoc before, as instructions with potential
aliasing problems were identified.  But thanks to swizzling basically
anything can have aliasing, so just do it generally at source reg
setup time.  This is somewhat inefficient, because sometimes an
operation doesn't need unaliasing protection if the swizzling is safe,
but the unaliasing before didn't cover those cases either.

Fixes piglit glsl-fs-loop.

src/mesa/drivers/dri/i965/brw_wm_glsl.c

index 562608e2ecdfb6d8833f36a1415109c48e47e968..13306accda763ba3e18eb9057bea4c495e0c1b1b 100644 (file)
@@ -614,112 +614,6 @@ static void invoke_subroutine( struct brw_wm_compile *c,
     }
 }
 
-/* Workaround for using brw_wm_emit.c's emit functions, which expect
- * destination regs to be uniquely written.  Moves arguments out to
- * temporaries as necessary for instructions which use their destination as
- * a temporary.
- */
-static void
-unalias3(struct brw_wm_compile *c,
-        void (*func)(struct brw_compile *c,
-                     const struct brw_reg *dst,
-                     GLuint mask,
-                     const struct brw_reg *arg0,
-                     const struct brw_reg *arg1,
-                     const struct brw_reg *arg2),
-        const struct brw_reg *dst,
-        GLuint mask,
-        const struct brw_reg *arg0,
-        const struct brw_reg *arg1,
-        const struct brw_reg *arg2)
-{
-    struct brw_compile *p = &c->func;
-    struct brw_reg tmp_arg0[4], tmp_arg1[4], tmp_arg2[4];
-    int i, j;
-    int mark = mark_tmps(c);
-
-    for (j = 0; j < 4; j++) {
-       tmp_arg0[j] = arg0[j];
-       tmp_arg1[j] = arg1[j];
-       tmp_arg2[j] = arg2[j];
-    }
-
-    for (i = 0; i < 4; i++) {
-       if (mask & (1<<i)) {
-           for (j = 0; j < 4; j++) {
-               if (arg0[j].file == dst[i].file &&
-                   dst[i].nr == arg0[j].nr) {
-                   tmp_arg0[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg0[j], arg0[j]);
-               }
-               if (arg1[j].file == dst[i].file &&
-                   dst[i].nr == arg1[j].nr) {
-                   tmp_arg1[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg1[j], arg1[j]);
-               }
-               if (arg2[j].file == dst[i].file &&
-                   dst[i].nr == arg2[j].nr) {
-                   tmp_arg2[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg2[j], arg2[j]);
-               }
-           }
-       }
-    }
-
-    func(p, dst, mask, tmp_arg0, tmp_arg1, tmp_arg2);
-
-    release_tmps(c, mark);
-}
-
-/* Workaround for using brw_wm_emit.c's emit functions, which expect
- * destination regs to be uniquely written.  Moves arguments out to
- * temporaries as necessary for instructions which use their destination as
- * a temporary.
- */
-static void
-unalias2(struct brw_wm_compile *c,
-        void (*func)(struct brw_compile *c,
-                     const struct brw_reg *dst,
-                     GLuint mask,
-                     const struct brw_reg *arg0,
-                     const struct brw_reg *arg1),
-        const struct brw_reg *dst,
-        GLuint mask,
-        const struct brw_reg *arg0,
-        const struct brw_reg *arg1)
-{
-    struct brw_compile *p = &c->func;
-    struct brw_reg tmp_arg0[4], tmp_arg1[4];
-    int i, j;
-    int mark = mark_tmps(c);
-
-    for (j = 0; j < 4; j++) {
-       tmp_arg0[j] = arg0[j];
-       tmp_arg1[j] = arg1[j];
-    }
-
-    for (i = 0; i < 4; i++) {
-       if (mask & (1<<i)) {
-           for (j = 0; j < 4; j++) {
-               if (arg0[j].file == dst[i].file &&
-                   dst[i].nr == arg0[j].nr) {
-                   tmp_arg0[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg0[j], arg0[j]);
-               }
-               if (arg1[j].file == dst[i].file &&
-                   dst[i].nr == arg1[j].nr) {
-                   tmp_arg1[j] = alloc_tmp(c);
-                   brw_MOV(p, tmp_arg1[j], arg1[j]);
-               }
-           }
-       }
-    }
-
-    func(p, dst, mask, tmp_arg0, tmp_arg1);
-
-    release_tmps(c, mark);
-}
-
 static void emit_arl(struct brw_wm_compile *c,
                      const struct prog_instruction *inst)
 {
@@ -1813,14 +1707,29 @@ static void
 get_argument_regs(struct brw_wm_compile *c,
                  const struct prog_instruction *inst,
                  int index,
+                 struct brw_reg *dst,
                  struct brw_reg *regs,
                  int mask)
 {
-    int i;
+    struct brw_compile *p = &c->func;
+    int i, j;
 
     for (i = 0; i < 4; i++) {
-       if (mask & (1 << i))
+       if (mask & (1 << i)) {
            regs[i] = get_src_reg(c, inst, index, i);
+
+           /* Unalias destination registers from our sources. */
+           if (regs[i].file == BRW_GENERAL_REGISTER_FILE) {
+              for (j = 0; j < 4; j++) {
+                  if (memcmp(&regs[i], &dst[j], sizeof(regs[0])) == 0) {
+                      struct brw_reg tmp = alloc_tmp(c);
+                      brw_MOV(p, tmp, regs[i]);
+                      regs[i] = tmp;
+                      break;
+                  }
+              }
+           }
+       }
     }
 }
 
@@ -1845,6 +1754,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
        int dst_flags;
        struct brw_reg args[3][4], dst[4];
        int j;
+       int mark = mark_tmps( c );
 
         c->cur_inst = i;
 
@@ -1866,7 +1776,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
           }
        }
        for (j = 0; j < brw_wm_nr_args(inst->Opcode); j++)
-           get_argument_regs(c, inst, j, args[j], WRITEMASK_XYZW);
+           get_argument_regs(c, inst, j, dst, args[j], WRITEMASK_XYZW);
 
        dst_flags = inst->DstReg.WriteMask;
        if (inst->SaturateMode == SATURATE_ZERO_ONE)
@@ -1920,8 +1830,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                emit_alu1(p, brw_RNDD, dst, dst_flags, args[0]);
                break;
            case OPCODE_LRP:
-               unalias3(c, emit_lrp,
-                        dst, dst_flags, args[0], args[1], args[2]);
+               emit_lrp(p, dst, dst_flags, args[0], args[1], args[2]);
                break;
            case OPCODE_TRUNC:
                emit_alu1(p, brw_RNDZ, dst, dst_flags, args[0]);
@@ -1961,10 +1870,10 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                emit_math1(c, BRW_MATH_FUNCTION_LOG, dst, dst_flags, args[0]);
                break;
            case OPCODE_MIN:    
-               unalias2(c, emit_min, dst, dst_flags, args[0], args[1]);
+               emit_min(p, dst, dst_flags, args[0], args[1]);
                break;
            case OPCODE_MAX:    
-               unalias2(c, emit_max, dst, dst_flags, args[0], args[1]);
+               emit_max(p, dst, dst_flags, args[0], args[1]);
                break;
            case OPCODE_DDX:
            case OPCODE_DDY:
@@ -2119,6 +2028,9 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
                        inst->Opcode);
        }
 
+       /* Release temporaries containing any unaliased source regs. */
+       release_tmps( c, mark );
+
        if (inst->CondUpdate)
            brw_set_predicate_control(p, BRW_PREDICATE_NORMAL);
        else