summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorFrancisco Jerez <[email protected]>2016-05-16 01:23:44 -0700
committerFrancisco Jerez <[email protected]>2016-05-23 14:05:21 -0700
commit11260cc54f277cadd2abfd22ec313f3f0f504487 (patch)
treed4b0f33110221652f9a5934475dac955cdd7c1ca /src
parentbb67c467a48f89177cf5a1c9904a627704ea7844 (diff)
i965/fs: Set exec_all on spills not matching the channel layout of the instruction.
This prevents the application of an incorrect channel mask by the scratch write instruction for spilled variables that don't have an exact one-to-one correspondence between channels of the variable and 32-bit components of the scratch write instruction. Reviewed-by: Jason Ekstrand <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp19
1 files changed, 16 insertions, 3 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp b/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp
index bc847bfdb2b..4b921137ca0 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp
@@ -977,14 +977,27 @@ fs_visitor::spill_reg(int spill_reg)
const unsigned width =
dispatch_width == 16 && inst->regs_written % 2 == 0 ? 16 : 8;
+ /* Spills should only write data initialized by the instruction for
+ * whichever channels are enabled in the excution mask. If that's
+ * not possible we'll have to emit a matching unspill before the
+ * instruction and set force_writemask_all on the spill.
+ */
+ const bool per_channel =
+ inst->dst.is_contiguous() && type_sz(inst->dst.type) == 4 &&
+ inst->exec_size == width;
+
/* Builder used to emit the scratch messages. */
- const fs_builder ubld = ibld.group(width, 0);
+ const fs_builder ubld = ibld.exec_all(!per_channel).group(width, 0);
/* If our write is going to affect just part of the
* inst->regs_written(), then we need to unspill the destination
- * since we write back out all of the regs_written().
+ * since we write back out all of the regs_written(). If the
+ * original instruction had force_writemask_all set and is not a
+ * partial write, there should be no need for the unspill since the
+ * instruction will be overwriting the whole destination in any case.
*/
- if (inst->is_partial_write())
+ if (inst->is_partial_write() ||
+ (!inst->force_writemask_all && !per_channel))
emit_unspill(ubld, spill_src, subset_spill_offset,
inst->regs_written);