summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <[email protected]>2010-07-07 12:25:22 -0700
committerEric Anholt <[email protected]>2010-07-07 14:06:26 -0700
commit9cbd8a1d5a85f39f12e9edbd2defbb9e9d0468ef (patch)
tree1c9415e53702b6213eed6f490b20073f16b05dd9 /src
parent43b5b03d67ce890e867c81d4a5cfc4871d711d43 (diff)
glsl2: Fix ir_div_to_mul_rcp for integer division.
rcp of an integer value did not produce the result you're looking for. Instead, do the a * rcp(b) as float and truncate after. This mostly fixes glsl-fs-loop-nested.
Diffstat (limited to 'src')
-rw-r--r--src/glsl/ir_div_to_mul_rcp.cpp56
1 files changed, 47 insertions, 9 deletions
diff --git a/src/glsl/ir_div_to_mul_rcp.cpp b/src/glsl/ir_div_to_mul_rcp.cpp
index ce84add2213..640d5d64f98 100644
--- a/src/glsl/ir_div_to_mul_rcp.cpp
+++ b/src/glsl/ir_div_to_mul_rcp.cpp
@@ -33,6 +33,7 @@
*/
#include "ir.h"
+#include "glsl_types.h"
class ir_div_to_mul_rcp_visitor : public ir_hierarchical_visitor {
public:
@@ -61,16 +62,53 @@ ir_div_to_mul_rcp_visitor::visit_leave(ir_expression *ir)
if (ir->operation != ir_binop_div)
return visit_continue;
- /* New expression for the 1.0 / op1 */
- ir_rvalue *expr;
- expr = new(ir) ir_expression(ir_unop_rcp,
- ir->operands[1]->type,
- ir->operands[1],
- NULL);
+ if (ir->operands[1]->type->base_type != GLSL_TYPE_INT &&
+ ir->operands[1]->type->base_type != GLSL_TYPE_UINT) {
+ /* New expression for the 1.0 / op1 */
+ ir_rvalue *expr;
+ expr = new(ir) ir_expression(ir_unop_rcp,
+ ir->operands[1]->type,
+ ir->operands[1],
+ NULL);
+
+ /* op0 / op1 -> op0 * (1.0 / op1) */
+ ir->operation = ir_binop_mul;
+ ir->operands[1] = expr;
+ } else {
+ /* Be careful with integer division -- we need to do it as a
+ * float and re-truncate, since rcp(n > 1) of an integer would
+ * just be 0.
+ */
+ ir_rvalue *op0, *op1;
+ const struct glsl_type *vec_type;
+
+ vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ ir->operands[1]->type->vector_elements,
+ ir->operands[1]->type->matrix_columns);
+
+ if (ir->operands[1]->type->base_type == GLSL_TYPE_INT)
+ op1 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[1], NULL);
+ else
+ op1 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[1], NULL);
+
+ op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL);
+
+ vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ ir->operands[0]->type->vector_elements,
+ ir->operands[0]->type->matrix_columns);
+
+ if (ir->operands[0]->type->base_type == GLSL_TYPE_INT)
+ op0 = new(ir) ir_expression(ir_unop_i2f, vec_type, ir->operands[0], NULL);
+ else
+ op0 = new(ir) ir_expression(ir_unop_u2f, vec_type, ir->operands[0], NULL);
+
+ op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1);
+
+ ir->operation = ir_unop_f2i;
+ ir->operands[0] = op0;
+ ir->operands[1] = NULL;
+ }
- /* op0 / op1 -> op0 * (1.0 / op1) */
- ir->operation = ir_binop_mul;
- ir->operands[1] = expr;
this->made_progress = true;
return visit_continue;