From 11260cc54f277cadd2abfd22ec313f3f0f504487 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 16 May 2016 01:23:44 -0700 Subject: 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 --- src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp | 19 ++++++++++++++++--- 1 file 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); -- cgit v1.2.3