diff options
-rw-r--r-- | src/mesa/program/ir_to_mesa.cpp | 73 |
1 files changed, 64 insertions, 9 deletions
diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index c5b67ad706a..d5b3693661c 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -304,6 +304,22 @@ public: 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); @@ -913,6 +929,46 @@ ir_to_mesa_visitor::emit_swz(ir_expression *ir) } 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) { unsigned int operand; @@ -1086,17 +1142,17 @@ 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. @@ -1111,7 +1167,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) 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: @@ -1124,7 +1180,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) 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 @@ -1147,12 +1203,12 @@ ir_to_mesa_visitor::visit(ir_expression *ir) 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: { @@ -1217,8 +1273,7 @@ ir_to_mesa_visitor::visit(ir_expression *ir) 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: |