summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancisco Jerez <[email protected]>2016-06-01 16:27:52 -0700
committerFrancisco Jerez <[email protected]>2016-06-03 18:38:51 -0700
commita2135c6fd95d3e48f222a702c2b814e3cf37eb7d (patch)
tree3352d000842415d0cf4829745306fcd9ee8e693b
parent7a3a0d921235712fa8d22f85552cc382a793ce95 (diff)
i965/vec4: 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 originally noticed this while working on SIMD32 in the scalar back-end, but the same scenario is likely to be possible in vec4 programs so this commit ports the bugfix with the same name from the scalar back-end to the vec4 cmod propagation pass. Cc: [email protected] Reviewed-by: Jason Ekstrand <[email protected]>
-rw-r--r--src/mesa/drivers/dri/i965/brw_vec4_cmod_propagation.cpp12
1 files changed, 12 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_vec4_cmod_propagation.cpp b/src/mesa/drivers/dri/i965/brw_vec4_cmod_propagation.cpp
index 0c8224f5f83..c376bebbe8e 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_cmod_propagation.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_cmod_propagation.cpp
@@ -115,6 +115,18 @@ opt_cmod_propagation_local(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)