namespace brw {
+static bool
+writemasks_incompatible(const vec4_instruction *earlier,
+ const vec4_instruction *later)
+{
+ return (earlier->dst.writemask != WRITEMASK_X &&
+ earlier->dst.writemask != WRITEMASK_XYZW) ||
+ (earlier->dst.writemask == WRITEMASK_XYZW &&
+ later->src[0].swizzle != BRW_SWIZZLE_XYZW) ||
+ (later->dst.writemask & ~earlier->dst.writemask) != 0;
+}
+
static bool
opt_cmod_propagation_local(bblock_t *block)
{
if (scan_inst->opcode != BRW_OPCODE_ADD)
goto not_match;
+ if (writemasks_incompatible(scan_inst, inst))
+ goto not_match;
+
/* A CMP is basically a subtraction. The result of the
* subtraction must be the same as the result of the addition.
* This means that one of the operands must be negated. So (a +
scan_inst->dst, scan_inst->size_written)) {
if ((scan_inst->predicate && scan_inst->opcode != BRW_OPCODE_SEL) ||
scan_inst->dst.offset != inst->src[0].offset ||
- (scan_inst->dst.writemask != WRITEMASK_X &&
- scan_inst->dst.writemask != WRITEMASK_XYZW) ||
- (scan_inst->dst.writemask == WRITEMASK_XYZW &&
- inst->src[0].swizzle != BRW_SWIZZLE_XYZW) ||
- (inst->dst.writemask & ~scan_inst->dst.writemask) != 0 ||
+ writemasks_incompatible(scan_inst, inst) ||
scan_inst->exec_size != inst->exec_size ||
scan_inst->group != inst->group) {
break;
EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
EXPECT_EQ(BRW_CONDITIONAL_NZ, instruction(block0, 1)->conditional_mod);
}
+
+TEST_F(cmod_propagation_test, add_cmp_same_dst_writemask)
+{
+ const vec4_builder bld = vec4_builder(v).at_end();
+ dst_reg dest = dst_reg(v, glsl_type::vec4_type);
+ src_reg src0 = src_reg(v, glsl_type::vec4_type);
+ src_reg src1 = src_reg(v, glsl_type::vec4_type);
+ dst_reg dest_null = bld.null_reg_f();
+
+ bld.ADD(dest, src0, src1);
+ vec4_instruction *inst = bld.CMP(dest_null, src0, src1, BRW_CONDITIONAL_GE);
+ inst->src[1].negate = true;
+
+ /* = Before =
+ *
+ * 0: add dest.xyzw src0 src1
+ * 1: cmp.ge.f0 null.xyzw src0 -src1
+ *
+ * = After =
+ * 0: add.ge.f0 dest.xyzw src0 src1
+ */
+
+ v->calculate_cfg();
+ bblock_t *block0 = v->cfg->blocks[0];
+
+ EXPECT_EQ(0, block0->start_ip);
+ EXPECT_EQ(1, block0->end_ip);
+
+ EXPECT_TRUE(cmod_propagation(v));
+
+ ASSERT_EQ(0, block0->start_ip);
+ ASSERT_EQ(0, block0->end_ip);
+ EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
+ EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 0)->conditional_mod);
+}
+
+TEST_F(cmod_propagation_test, add_cmp_different_dst_writemask)
+{
+ const vec4_builder bld = vec4_builder(v).at_end();
+ dst_reg dest = dst_reg(v, glsl_type::float_type);
+ src_reg src0 = src_reg(v, glsl_type::vec4_type);
+ src_reg src1 = src_reg(v, glsl_type::vec4_type);
+ dst_reg dest_null = bld.null_reg_f();
+
+ bld.ADD(dest, src0, src1);
+ vec4_instruction *inst = bld.CMP(dest_null, src0, src1, BRW_CONDITIONAL_GE);
+ inst->src[1].negate = true;
+
+ /* = Before =
+ *
+ * 0: add dest.x src0 src1
+ * 1: cmp.ge.f0 null.xyzw src0 -src1
+ *
+ * = After =
+ * (no changes)
+ */
+
+ v->calculate_cfg();
+ bblock_t *block0 = v->cfg->blocks[0];
+
+ EXPECT_EQ(0, block0->start_ip);
+ EXPECT_EQ(1, block0->end_ip);
+
+ EXPECT_FALSE(cmod_propagation(v));
+
+ ASSERT_EQ(0, block0->start_ip);
+ ASSERT_EQ(1, block0->end_ip);
+ EXPECT_EQ(BRW_OPCODE_ADD, instruction(block0, 0)->opcode);
+ EXPECT_EQ(BRW_CONDITIONAL_NONE, instruction(block0, 0)->conditional_mod);
+ EXPECT_EQ(BRW_OPCODE_CMP, instruction(block0, 1)->opcode);
+ EXPECT_EQ(BRW_CONDITIONAL_GE, instruction(block0, 1)->conditional_mod);
+}