void emit_swz(ir_expression *ir);
+ void emit_equality_comparison(ir_expression *ir, enum prog_opcode op,
+ dst_reg dst,
+ const src_reg &src0, const src_reg &src1);
+
+ inline void emit_sne(ir_expression *ir, dst_reg dst,
+ const src_reg &src0, const src_reg &src1)
+ {
+ emit_equality_comparison(ir, OPCODE_SLT, dst, src0, src1);
+ }
+
+ inline void emit_seq(ir_expression *ir, dst_reg dst,
+ const src_reg &src0, const src_reg &src1)
+ {
+ emit_equality_comparison(ir, OPCODE_SGE, dst, src0, src1);
+ }
+
bool process_move_condition(ir_rvalue *ir);
void copy_propagate(void);
this->result = result_src;
}
+void
+ir_to_mesa_visitor::emit_equality_comparison(ir_expression *ir,
+ enum prog_opcode op,
+ dst_reg dst,
+ const src_reg &src0,
+ const src_reg &src1)
+{
+ src_reg difference;
+ src_reg abs_difference = get_temp(glsl_type::vec4_type);
+ const src_reg zero = src_reg_for_float(0.0);
+
+ /* x == y is equivalent to -abs(x-y) >= 0. Since all of the code that
+ * consumes the generated IR is pretty dumb, take special care when one
+ * of the operands is zero.
+ *
+ * Similarly, x != y is equivalent to -abs(x-y) < 0.
+ */
+ if (src0.file == zero.file &&
+ src0.index == zero.index &&
+ src0.swizzle == zero.swizzle) {
+ difference = src1;
+ } else if (src1.file == zero.file &&
+ src1.index == zero.index &&
+ src1.swizzle == zero.swizzle) {
+ difference = src0;
+ } else {
+ difference = get_temp(glsl_type::vec4_type);
+
+ src_reg tmp_src = src0;
+ tmp_src.negate = ~tmp_src.negate;
+
+ emit(ir, OPCODE_ADD, dst_reg(difference), tmp_src, src1);
+ }
+
+ emit(ir, OPCODE_ABS, dst_reg(abs_difference), difference);
+
+ abs_difference.negate = ~abs_difference.negate;
+ emit(ir, op, dst, abs_difference, zero);
+}
+
void
ir_to_mesa_visitor::visit(ir_expression *ir)
{
emit(ir, OPCODE_SGE, result_dst, op[0], op[1]);
break;
case ir_binop_equal:
- emit(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+ emit_seq(ir, result_dst, op[0], op[1]);
break;
case ir_binop_nequal:
- emit(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ emit_sne(ir, result_dst, op[0], op[1]);
break;
case ir_binop_all_equal:
/* "==" operator producing a scalar boolean. */
if (ir->operands[0]->type->is_vector() ||
ir->operands[1]->type->is_vector()) {
src_reg temp = get_temp(glsl_type::vec4_type);
- emit(ir, OPCODE_SNE, dst_reg(temp), op[0], op[1]);
+ emit_sne(ir, dst_reg(temp), op[0], op[1]);
/* After the dot-product, the value will be an integer on the
* range [0,4]. Zero becomes 1.0, and positive values become zero.
sge_src.negate = ~sge_src.negate;
emit(ir, OPCODE_SGE, result_dst, sge_src, src_reg_for_float(0.0));
} else {
- emit(ir, OPCODE_SEQ, result_dst, op[0], op[1]);
+ emit_seq(ir, result_dst, op[0], op[1]);
}
break;
case ir_binop_any_nequal:
ir->operands[1]->as_constant()->is_zero()) {
temp = op[0];
} else {
- emit(ir, OPCODE_SNE, dst_reg(temp), op[0], op[1]);
+ emit_sne(ir, dst_reg(temp), op[0], op[1]);
}
/* After the dot-product, the value will be an integer on the
emit(ir, OPCODE_SLT, result_dst, slt_src, src_reg_for_float(0.0));
}
} else {
- emit(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ emit_sne(ir, result_dst, op[0], op[1]);
}
break;
case ir_binop_logic_xor:
- emit(ir, OPCODE_SNE, result_dst, op[0], op[1]);
+ emit_sne(ir, result_dst, op[0], op[1]);
break;
case ir_binop_logic_or: {
break;
case ir_unop_f2b:
case ir_unop_i2b:
- emit(ir, OPCODE_SNE, result_dst,
- op[0], src_reg_for_float(0.0));
+ emit_sne(ir, result_dst, op[0], src_reg_for_float(0.0));
break;
case ir_unop_bitcast_f2i: // Ignore these 4, they can't happen here anyway
case ir_unop_bitcast_f2u: