diff options
-rw-r--r-- | src/glsl/ir_algebraic.cpp | 46 |
1 files changed, 34 insertions, 12 deletions
diff --git a/src/glsl/ir_algebraic.cpp b/src/glsl/ir_algebraic.cpp index 0092eea036b..b731ba05be9 100644 --- a/src/glsl/ir_algebraic.cpp +++ b/src/glsl/ir_algebraic.cpp @@ -60,8 +60,11 @@ public: int op1, ir_expression *ir2, int op2); + ir_rvalue *swizzle_if_required(ir_expression *expr, + ir_rvalue *operand); void *mem_ctx; + bool progress; }; @@ -219,11 +222,27 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index, return false; } +/* When eliminating an expression and just returning one of its operands, + * we may need to swizzle that operand out to a vector if the expression was + * vector type. + */ +ir_rvalue * +ir_algebraic_visitor::swizzle_if_required(ir_expression *expr, + ir_rvalue *operand) +{ + if (expr->type->is_vector() && operand->type->is_scalar()) { + return new(mem_ctx) ir_swizzle(operand, 0, 0, 0, 0, + expr->type->vector_elements); + } else + return operand; +} + ir_rvalue * ir_algebraic_visitor::handle_expression(ir_expression *ir) { ir_constant *op_const[2] = {NULL, NULL}; ir_expression *op_expr[2] = {NULL, NULL}; + ir_expression *temp; unsigned int i; for (i = 0; i < ir->get_num_operands(); i++) { @@ -272,11 +291,11 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_add: if (is_vec_zero(op_const[0])) { this->progress = true; - return ir->operands[1]; + return swizzle_if_required(ir, ir->operands[1]); } if (is_vec_zero(op_const[1])) { this->progress = true; - return ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } /* Reassociate addition of constants so that we can do constant @@ -293,25 +312,26 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_sub: if (is_vec_zero(op_const[0])) { this->progress = true; - return new(mem_ctx) ir_expression(ir_unop_neg, - ir->type, + temp = new(mem_ctx) ir_expression(ir_unop_neg, + ir->operands[1]->type, ir->operands[1], NULL); + return swizzle_if_required(ir, temp); } if (is_vec_zero(op_const[1])) { this->progress = true; - return ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } break; case ir_binop_mul: if (is_vec_one(op_const[0])) { this->progress = true; - return ir->operands[1]; + return swizzle_if_required(ir, ir->operands[1]); } if (is_vec_one(op_const[1])) { this->progress = true; - return ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) { @@ -334,14 +354,15 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) case ir_binop_div: if (is_vec_one(op_const[0]) && ir->type->base_type == GLSL_TYPE_FLOAT) { this->progress = true; - return new(mem_ctx) ir_expression(ir_unop_rcp, - ir->type, + temp = new(mem_ctx) ir_expression(ir_unop_rcp, + ir->operands[1]->type, ir->operands[1], NULL); + return swizzle_if_required(ir, temp); } if (is_vec_one(op_const[1])) { this->progress = true; - return ir->operands[0]; + return swizzle_if_required(ir, ir->operands[0]); } break; @@ -359,10 +380,11 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir) /* As far as we know, all backends are OK with rsq. */ if (op_expr[0] && op_expr[0]->operation == ir_unop_sqrt) { this->progress = true; - return new(mem_ctx) ir_expression(ir_unop_rsq, - ir->type, + temp = new(mem_ctx) ir_expression(ir_unop_rsq, + op_expr[0]->operands[0]->type, op_expr[0]->operands[0], NULL); + return swizzle_if_required(ir, temp); } break; |