diff options
author | Bryan Cain <[email protected]> | 2011-08-20 14:43:25 -0500 |
---|---|---|
committer | Bryan Cain <[email protected]> | 2011-08-20 14:43:25 -0500 |
commit | 5379a70d3fabd9cf92a615647f81289d33ae9468 (patch) | |
tree | 58e92526988532ceeb8acc3b1acc41b58dd2c7dc | |
parent | c721d7b7bc70503d2ebb6c742be96371b68bd152 (diff) |
glsl_to_tgsi: emit a MAD(b, -a, b) for !a && b
This is a port of commit ff2cfb8989cd to glsl_to_tgsi.
-rw-r--r-- | src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index 2885630c7db..a1f56d3d78a 100644 --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -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; |