summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancisco Jerez <[email protected]>2016-04-25 15:39:29 -0700
committerFrancisco Jerez <[email protected]>2016-05-27 23:29:06 -0700
commitc88b52745c754619d3e7af73abb71adfcc63cc7a (patch)
treedad94d4c2948f0580ae5157891b46f4627ea4862
parent8476233ae22c77ca26d8109f0f0d6c74457969f8 (diff)
i965/fs: Fix cmod propagation not to propagate non-identity cmod into CMP(N).
The conditional mod of these instructions determines the semantics of the comparison itself (rather than being evaluated based on the result of the instruction as is usually the case for most other instructions that allow conditional mods), so it's in general not legal to propagate a conditional mod into a CMP instruction. This prevents cmod propagation from (mis)optimizing: cmp.z.f0 tmp, ... mov.z.f0 null, tmp into: cmp.z.f0 tmp, ... which gives the negation of the flag result of the original sequence. I could reproduce this easily with SIMD32 but I don't see any reason why the problem would be SIMD32-specific, it was most likely working by luck. Cc: [email protected] Reviewed-by: Jason Ekstrand <[email protected]>
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_cmod_propagation.cpp12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs_cmod_propagation.cpp b/src/mesa/drivers/dri/i965/brw_fs_cmod_propagation.cpp
index 98d4ff6007f..af1e3ebbaa2 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_cmod_propagation.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_cmod_propagation.cpp
@@ -129,6 +129,18 @@ opt_cmod_propagation_local(const brw_device_info *devinfo, bblock_t *block)
break;
}
+ /* The conditional mod of the CMP/CMPN instructions behaves
+ * specially because the flag output is not calculated from the
+ * result of the instruction, but the other way around, which
+ * means that even if the condmod to propagate and the condmod
+ * from the CMP instruction are the same they will in general give
+ * different results because they are evaluated based on different
+ * inputs.
+ */
+ if (scan_inst->opcode == BRW_OPCODE_CMP ||
+ scan_inst->opcode == BRW_OPCODE_CMPN)
+ break;
+
/* Otherwise, try propagating the conditional. */
enum brw_conditional_mod cond =
inst->src[0].negate ? brw_swap_cmod(inst->conditional_mod)