gallivm: fetch immediates to correct type (v2)
[mesa.git] / src / glsl / lower_instructions.cpp
index a5f61f213d056d8098083bdd2a479c292861b1e7..d79eb0a7ffb0d69f41d5fcef8e9d1674514dcb45 100644 (file)
@@ -32,6 +32,7 @@
  * Currently supported transformations:
  * - SUB_TO_ADD_NEG
  * - DIV_TO_MUL_RCP
+ * - INT_DIV_TO_MUL_RCP
  * - EXP_TO_EXP2
  * - POW_TO_EXP2
  * - LOG_TO_LOG2
@@ -47,8 +48,8 @@
  * want to recognize add(op0, neg(op1)) or the other way around to
  * produce a subtract anyway.
  *
- * DIV_TO_MUL_RCP:
- * ---------------
+ * DIV_TO_MUL_RCP and INT_DIV_TO_MUL_RCP:
+ * --------------------------------------
  * Breaks an ir_unop_div expression down to op0 * (rcp(op1)).
  *
  * Many GPUs don't have a divide instruction (945 and 965 included),
  * reciprocal.  By breaking the operation down, constant reciprocals
  * can get constant folded.
  *
+ * DIV_TO_MUL_RCP only lowers floating point division; INT_DIV_TO_MUL_RCP
+ * handles the integer case, converting to and from floating point so that
+ * RCP is possible.
+ *
  * EXP_TO_EXP2 and LOG_TO_LOG2:
  * ----------------------------
  * Many GPUs don't have a base e log or exponent instruction, but they
@@ -95,6 +100,7 @@ private:
 
    void sub_to_add_neg(ir_expression *);
    void div_to_mul_rcp(ir_expression *);
+   void int_div_to_mul_rcp(ir_expression *);
    void mod_to_fract(ir_expression *);
    void exp_to_exp2(ir_expression *);
    void pow_to_exp2(ir_expression *);
@@ -127,51 +133,67 @@ lower_instructions_visitor::sub_to_add_neg(ir_expression *ir)
 void
 lower_instructions_visitor::div_to_mul_rcp(ir_expression *ir)
 {
-   if (!ir->operands[1]->type->is_integer()) {
-      /* 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;
+   assert(ir->operands[1]->type->is_float());
+
+   /* 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]);
+
+   /* op0 / op1 -> op0 * (1.0 / op1) */
+   ir->operation = ir_binop_mul;
+   ir->operands[1] = expr;
+
+   this->progress = true;
+}
 
-      vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
-                                        ir->operands[1]->type->vector_elements,
-                                        ir->operands[1]->type->matrix_columns);
+void
+lower_instructions_visitor::int_div_to_mul_rcp(ir_expression *ir)
+{
+   assert(ir->operands[1]->type->is_integer());
+
+   /* 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;
 
-      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);
+   vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+                                     ir->operands[1]->type->vector_elements,
+                                     ir->operands[1]->type->matrix_columns);
 
-      op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL);
+   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);
 
-      vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
-                                        ir->operands[0]->type->vector_elements,
-                                        ir->operands[0]->type->matrix_columns);
+   op1 = new(ir) ir_expression(ir_unop_rcp, op1->type, op1, NULL);
 
-      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);
+   vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+                                     ir->operands[0]->type->vector_elements,
+                                     ir->operands[0]->type->matrix_columns);
 
-      op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1);
+   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);
 
+   vec_type = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+                                     ir->type->vector_elements,
+                                     ir->type->matrix_columns);
+
+   op0 = new(ir) ir_expression(ir_binop_mul, vec_type, op0, op1);
+
+   if (ir->operands[1]->type->base_type == GLSL_TYPE_INT) {
       ir->operation = ir_unop_f2i;
       ir->operands[0] = op0;
-      ir->operands[1] = NULL;
+   } else {
+      ir->operation = ir_unop_i2u;
+      ir->operands[0] = new(ir) ir_expression(ir_unop_f2i, op0);
    }
+   ir->operands[1] = NULL;
 
    this->progress = true;
 }
@@ -256,7 +278,9 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
       break;
 
    case ir_binop_div:
-      if (lowering(DIV_TO_MUL_RCP))
+      if (ir->operands[1]->type->is_integer() && lowering(INT_DIV_TO_MUL_RCP))
+        int_div_to_mul_rcp(ir);
+      else if (ir->operands[1]->type->is_float() && lowering(DIV_TO_MUL_RCP))
         div_to_mul_rcp(ir);
       break;
 
@@ -271,7 +295,7 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
       break;
 
    case ir_binop_mod:
-      if (lowering(MOD_TO_FRACT))
+      if (lowering(MOD_TO_FRACT) && ir->type->is_float())
         mod_to_fract(ir);
       break;