Mesa (master): tgsi: handle SOA dependencies for MOV/SWZ

Brian Paul brianp at kemper.freedesktop.org
Thu Aug 20 16:52:55 UTC 2009


Module: Mesa
Branch: master
Commit: 013bd4da1a4c112334c0b658f2506446df3666a6
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=013bd4da1a4c112334c0b658f2506446df3666a6

Author: Brian Paul <brianp at vmware.com>
Date:   Thu Aug 20 10:28:22 2009 -0600

tgsi: handle SOA dependencies for MOV/SWZ

SOA dependencies can happen when a register is used both as a source and
destination and the source is swizzled.  For example:

MOV T, T.yxwz; would expand into:

  MOV t0, t1;
  MOV t1, t0;
  MOV t2, t3;
  MOV t3, t2;

The second instruction will produce the wrong result since we wrote to t0
in the first instruction.  We need to use an intermediate temporary to fix
this.

This will take more work to fix for all TGSI instructions.  This seems to
happen with MOV instructions more than anything else so fix that case now
and warn on others.

Fixes piglit glsl-vs-loop test (when not using SSE). See bug 23317.

---

 src/gallium/auxiliary/tgsi/tgsi_exec.c |   50 +++++++++++++++++++++++---------
 src/gallium/auxiliary/tgsi/tgsi_exec.h |    8 +++++
 2 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index 951ecfd..711e86d 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -62,6 +62,9 @@
 
 #define FAST_MATH 1
 
+/** for tgsi_full_instruction::Flags */
+#define SOA_DEPENDENCY_FLAG 0x1
+
 #define TILE_TOP_LEFT     0
 #define TILE_TOP_RIGHT    1
 #define TILE_BOTTOM_LEFT  2
@@ -182,7 +185,7 @@ print_temp(const struct tgsi_exec_machine *mach, uint index)
  *   MOV t3, t2;
  * The second instruction will have the wrong value for t0 if executed as-is.
  */
-static boolean
+boolean
 tgsi_check_soa_dependencies(const struct tgsi_full_instruction *inst)
 {
    uint i, chan;
@@ -328,19 +331,24 @@ tgsi_exec_machine_bind_shader(
                                    * sizeof(struct tgsi_full_instruction));
             maxInstructions += 10;
          }
-         memcpy(instructions + numInstructions,
-                &parse.FullToken.FullInstruction,
-                sizeof(instructions[0]));
 
-#if 0
          if (tgsi_check_soa_dependencies(&parse.FullToken.FullInstruction)) {
-            debug_printf("SOA dependency in instruction:\n");
-            tgsi_dump_instruction(&parse.FullToken.FullInstruction,
-                                  numInstructions);
+            uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode;
+            parse.FullToken.FullInstruction.Flags = SOA_DEPENDENCY_FLAG;
+            /* XXX we only handle SOA dependencies properly for MOV/SWZ
+             * at this time!
+             */
+            if (opcode != TGSI_OPCODE_MOV && opcode != TGSI_OPCODE_SWZ) {
+               debug_printf("Warning: SOA dependency in instruction"
+                            " is not handled:\n");
+               tgsi_dump_instruction(&parse.FullToken.FullInstruction,
+                                     numInstructions);
+            }
          }
-#else
-         (void) tgsi_check_soa_dependencies;
-#endif
+
+         memcpy(instructions + numInstructions,
+                &parse.FullToken.FullInstruction,
+                sizeof(instructions[0]));
 
          numInstructions++;
          break;
@@ -2024,9 +2032,23 @@ exec_instruction(
 
    case TGSI_OPCODE_MOV:
    case TGSI_OPCODE_SWZ:
-      FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) {
-         FETCH( &r[0], 0, chan_index );
-         STORE( &r[0], 0, chan_index );
+      if (inst->Flags & SOA_DEPENDENCY_FLAG) {
+         /* Do all fetches into temp regs, then do all stores to avoid
+          * intermediate/accidental clobbering.  This could be done all the
+          * time for MOV but for other instructions we'll need more temps...
+          */
+         FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) {
+            FETCH( &r[chan_index], 0, chan_index );
+         }
+         FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) {
+            STORE( &r[chan_index], 0, chan_index );
+         }
+      }
+      else {
+         FOR_EACH_ENABLED_CHANNEL( *inst, chan_index ) {
+            FETCH( &r[0], 0, chan_index );
+            STORE( &r[0], 0, chan_index );
+         }
       }
       break;
 
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.h b/src/gallium/auxiliary/tgsi/tgsi_exec.h
index 8a9100f..fd9ef6f 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.h
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.h
@@ -272,6 +272,14 @@ tgsi_exec_machine_run(
    struct tgsi_exec_machine *mach );
 
 
+void
+tgsi_exec_machine_free_data(struct tgsi_exec_machine *mach);
+
+
+boolean
+tgsi_check_soa_dependencies(const struct tgsi_full_instruction *inst);
+
+
 static INLINE void
 tgsi_set_kill_mask(struct tgsi_exec_machine *mach, unsigned mask)
 {




More information about the mesa-commit mailing list