glsl_to_tgsi: emit a MAD(b, -a, b) for !a && b

This is a port of commit ff2cfb8989 to glsl_to_tgsi.
This commit is contained in:
Bryan Cain
2011-08-20 14:43:25 -05:00
parent c721d7b7bc
commit 5379a70d3f
@@ -392,6 +392,8 @@ public:
GLboolean try_emit_mad(ir_expression *ir,
int mul_operand);
bool try_emit_mad_for_and_not(ir_expression *ir,
int mul_operand);
GLboolean try_emit_sat(ir_expression *ir);
void emit_swz(ir_expression *ir);
@@ -1210,6 +1212,46 @@ glsl_to_tgsi_visitor::try_emit_mad(ir_expression *ir, int mul_operand)
return true;
}
/**
* Emit MAD(a, -b, a) instead of AND(a, NOT(b))
*
* The logic values are 1.0 for true and 0.0 for false. Logical-and is
* implemented using multiplication, and logical-or is implemented using
* addition. Logical-not can be implemented as (true - x), or (1.0 - x).
* As result, the logical expression (a & !b) can be rewritten as:
*
* - a * !b
* - a * (1 - b)
* - (a * 1) - (a * b)
* - a + -(a * b)
* - a + (a * -b)
*
* This final expression can be implemented as a single MAD(a, -b, a)
* instruction.
*/
bool
glsl_to_tgsi_visitor::try_emit_mad_for_and_not(ir_expression *ir, int try_operand)
{
const int other_operand = 1 - try_operand;
st_src_reg a, b;
ir_expression *expr = ir->operands[try_operand]->as_expression();
if (!expr || expr->operation != ir_unop_logic_not)
return false;
ir->operands[other_operand]->accept(this);
a = this->result;
expr->operands[0]->accept(this);
b = this->result;
b.negate = ~b.negate;
this->result = get_temp(ir->type);
emit(ir, TGSI_OPCODE_MAD, st_dst_reg(this->result), a, b, a);
return true;
}
GLboolean
glsl_to_tgsi_visitor::try_emit_sat(ir_expression *ir)
{
@@ -1291,6 +1333,16 @@ glsl_to_tgsi_visitor::visit(ir_expression *ir)
if (try_emit_mad(ir, 0))
return;
}
/* Quick peephole: Emit OPCODE_MAD(-a, -b, a) instead of AND(a, NOT(b))
*/
if (ir->operation == ir_binop_logic_and) {
if (try_emit_mad_for_and_not(ir, 1))
return;
if (try_emit_mad_for_and_not(ir, 0))
return;
}
if (try_emit_sat(ir))
return;