[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