i965/fs: Fix propagation of copies with strided source.
authorFrancisco Jerez <currojerez@riseup.net>
Mon, 25 Apr 2016 22:40:05 +0000 (15:40 -0700)
committerSamuel Iglesias Gonsálvez <siglesias@igalia.com>
Mon, 16 May 2016 07:55:32 +0000 (09:55 +0200)
This has likely been broken since we started propagating copies not
matching the offset of the instruction exactly
(1728e74957a62b1b4b9fbb62a7de2c12b77c8a75).  The copy source stride
needs to be taken into account to find out the offset at the origin
that corresponds to the offset at the destination of the copy which is
being read by the instruction.  This has led to program miscompilation
on both my SIMD32 branch and Igalia's FP64 branch.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/dri/i965/brw_fs_copy_propagation.cpp

index 3c702d8b36ec8a29e63d8bf6401a9ba71df7c6f0..83791bfcfff62b190ea3b65894a044df83596c73 100644 (file)
@@ -460,16 +460,26 @@ fs_visitor::try_copy_propagate(fs_inst *inst, int arg, acp_entry *entry)
           * parts of vgrfs so we have to do some reg_offset magic.
           */
 
-         /* Compute the offset of inst->src[arg] relative to inst->dst */
-         assert(entry->dst.subreg_offset == 0);
-         int rel_offset = inst->src[arg].reg_offset - entry->dst.reg_offset;
-         int rel_suboffset = inst->src[arg].subreg_offset;
-
-         /* Compute the final register offset (in bytes) */
-         int offset = entry->src.reg_offset * 32 + entry->src.subreg_offset;
-         offset += rel_offset * 32 + rel_suboffset;
-         inst->src[arg].reg_offset = offset / 32;
-         inst->src[arg].subreg_offset = offset % 32;
+         /* Compute the offset of inst->src[arg] relative to entry->dst */
+         const unsigned rel_offset = (inst->src[arg].reg_offset
+                                      - entry->dst.reg_offset) * REG_SIZE +
+                                     inst->src[arg].subreg_offset;
+
+         /* Compute the first component of the copy that the instruction is
+          * reading, and the base byte offset within that component.
+          */
+         assert(entry->dst.subreg_offset == 0 && entry->dst.stride == 1);
+         const unsigned component = rel_offset / type_sz(entry->dst.type);
+         const unsigned suboffset = rel_offset % type_sz(entry->dst.type);
+
+         /* Calculate the byte offset at the origin of the copy of the given
+          * component and suboffset.
+          */
+         const unsigned offset = suboffset +
+            component * entry->src.stride * type_sz(entry->src.type) +
+            entry->src.reg_offset * REG_SIZE + entry->src.subreg_offset;
+         inst->src[arg].reg_offset = offset / REG_SIZE;
+         inst->src[arg].subreg_offset = offset % REG_SIZE;
       }
       break;