[Mesa-dev] [PATCH 14/15] glsl: Add frexp_to_arith lowering pass.

Matt Turner mattst88 at gmail.com
Thu Aug 22 16:08:34 PDT 2013


---
 src/glsl/ir_optimization.h      |   1 +
 src/glsl/lower_instructions.cpp | 106 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/src/glsl/ir_optimization.h b/src/glsl/ir_optimization.h
index 074686c..51c73bb 100644
--- a/src/glsl/ir_optimization.h
+++ b/src/glsl/ir_optimization.h
@@ -39,6 +39,7 @@
 #define LRP_TO_ARITH       0x80
 #define BITFIELD_INSERT_TO_BFM_BFI 0x100
 #define LDEXP_TO_ARITH     0x200
+#define FREXP_TO_ARITH     0x400
 
 /**
  * \see class lower_packing_builtins_visitor
diff --git a/src/glsl/lower_instructions.cpp b/src/glsl/lower_instructions.cpp
index 8b0a8e1..495c232 100644
--- a/src/glsl/lower_instructions.cpp
+++ b/src/glsl/lower_instructions.cpp
@@ -87,6 +87,10 @@
  * -------------
  * Converts ir_binop_ldexp to arithmetic and bit operations.
  *
+ * FREXP_TO_ARITH:
+ * -------------
+ * Converts ir_binop_frexp to arithmetic and bit operations.
+ *
  * LRP_TO_ARITH:
  * -------------
  * Converts ir_triop_lrp to (op0 * (1.0f - op2)) + (op1 * op2).
@@ -131,6 +135,7 @@ private:
    void lrp_to_arith(ir_expression *);
    void bitfield_insert_to_bfm_bfi(ir_expression *);
    void ldexp_to_arith(ir_expression *);
+   void frexp_to_arith(ir_expression *);
 };
 
 /**
@@ -455,6 +460,102 @@ lower_instructions_visitor::ldexp_to_arith(ir_expression *ir)
    this->progress = true;
 }
 
+void
+lower_instructions_visitor::frexp_to_arith(ir_expression *ir)
+{
+   /* Translates
+    *    ir_binop_frexp x_input exp
+    * into:
+    *
+    *    x = x_input;
+    *    exp = 0;
+    *
+    *    if (abs(x) != 0.0) {
+    *       bits = bitcast_f2u(x);
+    *
+    *       exp += (bitcast_f2u(abs(x)) >> exp_shift) + exp_bias;
+    *       bits &= sign_mantissa_mask;
+    *       bits |= exponent_mask;
+    *       x = bitcast_u2f(bits);
+    *    }
+    *    return x;
+    *
+    * which we can't actually implement as such, since the GLSL IR doesn't
+    * have vectorized if-statements. We actually implement it without branches
+    * using conditional-select:
+    *
+    *    x = x_input;
+    *
+    *    is_not_zero = abs(x) != 0.0f;
+    *
+    *    exp = u2i(bitcast_f2u(abs(x)) >> exp_shift);
+    *    exp += cond_sel(is_not_zero, exp_bias, 0);
+    *
+    *    bits = bitcast_f2u(x);
+    *    bits &= sign_mantissa_mask;
+    *    bits |= cond_sel(is_not_zero, exponent_mask, 0u);
+    *    x = bitcast_u2f(bits);
+    *    return x;
+    */
+
+   const unsigned vec_elem = ir->type->vector_elements;
+
+   /* Types */
+   const glsl_type *uvec = glsl_type::get_instance(GLSL_TYPE_UINT, vec_elem, 1);
+   const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1);
+   const glsl_type *ivec = glsl_type::get_instance(GLSL_TYPE_INT, vec_elem, 1);
+
+   /* Constants */
+   ir_constant *zeroi = ir_constant::zero(ir, ivec);
+   ir_constant *zerou = ir_constant::zero(ir, uvec);
+   ir_constant *zerof = ir_constant::zero(ir, ir->type);
+
+   ir_constant *exp_bias = new(ir) ir_constant(-126, vec_elem);
+   ir_constant *exp_shift = new(ir) ir_constant(23u, vec_elem);
+
+   ir_constant *sign_mantissa_mask = new(ir) ir_constant(0x807fffffu, vec_elem);
+   ir_constant *exponent_mask = new(ir) ir_constant(0x3f000000u, vec_elem);
+
+   /* Temporary variables */
+   ir_variable *x = new(ir) ir_variable(ir->type, "x", ir_var_temporary);
+
+   ir_variable *bits = new(ir) ir_variable(uvec, "bits", ir_var_temporary);
+
+   ir_variable *is_not_zero = new(ir) ir_variable(bvec, "is_not_zero",
+                                                  ir_var_temporary);
+
+   /* Variable passed as <exp> parameter */
+   ir_variable *exponent = ir->operands[1]->variable_referenced();
+
+
+   ir_instruction &i = *base_ir;
+
+   /* Initialize x = x_input; exponent = 0; */
+   i.insert_before(x);
+   i.insert_before(assign(x, ir->operands[0]));
+   i.insert_before(is_not_zero);
+   i.insert_before(assign(is_not_zero, nequal(abs(x), zerof)));
+
+   /* Calculate exponent */
+   /* Use bitcast to unsigned to get shr, not asr. */
+   i.insert_before(assign(exponent, add(u2i(rshift(bitcast_f2u(abs(x)),
+                                                   exp_shift)),
+                                        cond_sel(is_not_zero, exp_bias,
+                                                              zeroi))));
+
+   /* Calculate mantissa */
+   i.insert_before(bits);
+   i.insert_before(assign(bits, bit_and(bitcast_f2u(x), sign_mantissa_mask)));
+   i.insert_before(assign(bits, bit_or(bits, cond_sel(is_not_zero,
+                                                      exponent_mask, zerou))));
+
+   ir->operation = ir_unop_bitcast_u2f;
+   ir->operands[0] = new(ir) ir_dereference_variable(bits);
+   ir->operands[1] = NULL;
+
+   this->progress = true;
+}
+
 ir_visitor_status
 lower_instructions_visitor::visit_leave(ir_expression *ir)
 {
@@ -506,6 +607,11 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
          ldexp_to_arith(ir);
       break;
 
+   case ir_binop_frexp:
+      if (lowering(FREXP_TO_ARITH))
+         frexp_to_arith(ir);
+      break;
+
    default:
       return visit_continue;
    }
-- 
1.8.3.2



More information about the mesa-dev mailing list