glsl2: Make ir_algebraic reassociate add/mul operands for constant folding.

It's rather easy to produce two constant multiplies separated by other
multiplies while writing a BRDF shader, and non-obvious enough in the
resulting codegen that I didn't catch it in my demo code until just
recently.  Cuts 3 965 instructions from my demo (<1%), and 20 from
glsl-fs-raytrace (1.3%).
This commit is contained in:
Eric Anholt
2010-07-26 23:56:19 -07:00
parent 5854d4583c
commit 0ff3b2b344
+107 -1
View File
@@ -58,7 +58,14 @@ public:
virtual ir_visitor_status visit_leave(ir_texture *);
ir_rvalue *handle_expression(ir_rvalue *in_ir);
bool reassociate_constant(ir_expression *ir1,
int const_index,
ir_constant *constant,
ir_expression *ir2);
void reassociate_operands(ir_expression *ir1,
int op1,
ir_expression *ir2,
int op2);
bool progress;
};
@@ -138,6 +145,84 @@ is_vec_one(ir_constant *ir)
return true;
}
static void
update_type(ir_expression *ir)
{
if (ir->operands[0]->type->is_vector())
ir->type = ir->operands[0]->type;
else
ir->type = ir->operands[1]->type;
}
void
ir_algebraic_visitor::reassociate_operands(ir_expression *ir1,
int op1,
ir_expression *ir2,
int op2)
{
ir_rvalue *temp = ir2->operands[op2];
ir2->operands[op2] = ir1->operands[op1];
ir1->operands[op1] = temp;
/* Update the type of ir2. The type of ir1 won't have changed --
* base types matched, and at least one of the operands of the 2
* binops is still a vector if any of them were.
*/
update_type(ir2);
this->progress = true;
}
/**
* Reassociates a constant down a tree of adds or multiplies.
*
* Consider (2 * (a * (b * 0.5))). We want to send up with a * b.
*/
bool
ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
ir_constant *constant,
ir_expression *ir2)
{
if (!ir2 || ir1->operation != ir2->operation)
return false;
/* Don't want to even think about matrices. */
if (ir1->operands[0]->type->is_matrix() ||
ir1->operands[0]->type->is_matrix() ||
ir2->operands[1]->type->is_matrix() ||
ir2->operands[1]->type->is_matrix())
return false;
ir_constant *ir2_const[2];
ir2_const[0] = ir2->operands[0]->constant_expression_value();
ir2_const[1] = ir2->operands[1]->constant_expression_value();
if (ir2_const[0] && ir2_const[1])
return false;
if (ir2_const[0]) {
reassociate_operands(ir1, const_index, ir2, 1);
return true;
} else if (ir2_const[1]) {
reassociate_operands(ir1, const_index, ir2, 0);
return true;
}
if (reassociate_constant(ir1, const_index, constant,
ir2->operands[0]->as_expression())) {
update_type(ir2);
return true;
}
if (reassociate_constant(ir1, const_index, constant,
ir2->operands[1]->as_expression())) {
update_type(ir2);
return true;
}
return false;
}
ir_rvalue *
ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir)
{
@@ -201,6 +286,16 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir)
this->progress = true;
return ir->operands[0];
}
/* Reassociate addition of constants so that we can do constant
* folding.
*/
if (op_const[0] && !op_const[1])
reassociate_constant(ir, 0, op_const[0],
ir->operands[1]->as_expression());
if (op_const[1] && !op_const[0])
reassociate_constant(ir, 1, op_const[1],
ir->operands[0]->as_expression());
break;
case ir_binop_sub:
@@ -231,6 +326,17 @@ ir_algebraic_visitor::handle_expression(ir_rvalue *in_ir)
this->progress = true;
return ir_constant::zero(ir, ir->type);
}
/* Reassociate multiplication of constants so that we can do
* constant folding.
*/
if (op_const[0] && !op_const[1])
reassociate_constant(ir, 0, op_const[0],
ir->operands[1]->as_expression());
if (op_const[1] && !op_const[0])
reassociate_constant(ir, 1, op_const[1],
ir->operands[0]->as_expression());
break;
case ir_binop_div: