aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src/glsl/lower_instructions.cpp
diff options
context:
space:
mode:
authormarha <marha@users.sourceforge.net>2013-09-18 08:03:04 +0200
committermarha <marha@users.sourceforge.net>2013-09-18 08:03:04 +0200
commit7f669a708bd35bdf8e842f762ec68f9ad0ec0486 (patch)
tree332fc6d6e6f70503d717249e4e387bf3eea29637 /mesalib/src/glsl/lower_instructions.cpp
parenta7d3f63ee5e292379ed6d6eba0c65512205a4786 (diff)
downloadvcxsrv-7f669a708bd35bdf8e842f762ec68f9ad0ec0486.tar.gz
vcxsrv-7f669a708bd35bdf8e842f762ec68f9ad0ec0486.tar.bz2
vcxsrv-7f669a708bd35bdf8e842f762ec68f9ad0ec0486.zip
libX11 mesa pixman xserver git update 18 Sep 2013
xserver commit 8010d3a48bd0b224dcb0883e39c2351ad364d846 libX11 commit 5dcb40f28d59587597d2ff6e6ac64c71cfe6ff7b pixman commit 58a79dfe6d1fd62c2b66c69fdb64f6b8ecf61da5 mesa commit a3b51a22f71819236baa6bbda9d0d050914b149d
Diffstat (limited to 'mesalib/src/glsl/lower_instructions.cpp')
-rw-r--r--mesalib/src/glsl/lower_instructions.cpp128
1 files changed, 128 insertions, 0 deletions
diff --git a/mesalib/src/glsl/lower_instructions.cpp b/mesalib/src/glsl/lower_instructions.cpp
index d32ec80d6..cb5304895 100644
--- a/mesalib/src/glsl/lower_instructions.cpp
+++ b/mesalib/src/glsl/lower_instructions.cpp
@@ -37,6 +37,7 @@
* - POW_TO_EXP2
* - LOG_TO_LOG2
* - MOD_TO_FRACT
+ * - LDEXP_TO_ARITH
* - LRP_TO_ARITH
* - BITFIELD_INSERT_TO_BFM_BFI
*
@@ -82,6 +83,10 @@
* if we have to break it down like this anyway, it gives an
* opportunity to do things like constant fold the (1.0 / op1) easily.
*
+ * LDEXP_TO_ARITH:
+ * -------------
+ * Converts ir_binop_ldexp to arithmetic and bit operations.
+ *
* LRP_TO_ARITH:
* -------------
* Converts ir_triop_lrp to (op0 * (1.0f - op2)) + (op1 * op2).
@@ -125,6 +130,7 @@ private:
void log_to_log2(ir_expression *);
void lrp_to_arith(ir_expression *);
void bitfield_insert_to_bfm_bfi(ir_expression *);
+ void ldexp_to_arith(ir_expression *);
};
/**
@@ -332,6 +338,123 @@ lower_instructions_visitor::bitfield_insert_to_bfm_bfi(ir_expression *ir)
this->progress = true;
}
+void
+lower_instructions_visitor::ldexp_to_arith(ir_expression *ir)
+{
+ /* Translates
+ * ir_binop_ldexp x exp
+ * into
+ *
+ * extracted_biased_exp = rshift(bitcast_f2i(abs(x)), exp_shift);
+ * resulting_biased_exp = extracted_biased_exp + exp;
+ *
+ * if (resulting_biased_exp < 1) {
+ * return copysign(0.0, x);
+ * }
+ *
+ * return bitcast_u2f((bitcast_f2u(x) & sign_mantissa_mask) |
+ * lshift(i2u(resulting_biased_exp), exp_shift));
+ *
+ * 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:
+ *
+ * extracted_biased_exp = rshift(bitcast_f2i(abs(x)), exp_shift);
+ * resulting_biased_exp = extracted_biased_exp + exp;
+ *
+ * is_not_zero_or_underflow = gequal(resulting_biased_exp, 1);
+ * x = csel(is_not_zero_or_underflow, x, copysign(0.0f, x));
+ * resulting_biased_exp = csel(is_not_zero_or_underflow,
+ * resulting_biased_exp, 0);
+ *
+ * return bitcast_u2f((bitcast_f2u(x) & sign_mantissa_mask) |
+ * lshift(i2u(resulting_biased_exp), exp_shift));
+ */
+
+ const unsigned vec_elem = ir->type->vector_elements;
+
+ /* Types */
+ const glsl_type *ivec = glsl_type::get_instance(GLSL_TYPE_INT, vec_elem, 1);
+ const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1);
+
+ /* Constants */
+ ir_constant *zeroi = ir_constant::zero(ir, ivec);
+ ir_constant *zerof = ir_constant::zero(ir, ir->type);
+
+ ir_constant *sign_mantissa_mask = new(ir) ir_constant(0x807fffffu, vec_elem);
+ ir_constant *sign_mask = new(ir) ir_constant(0x80000000u, vec_elem);
+
+ ir_constant *exp_shift = new(ir) ir_constant(23u, vec_elem);
+
+ /* Temporary variables */
+ ir_variable *x = new(ir) ir_variable(ir->type, "x", ir_var_temporary);
+ ir_variable *exp = new(ir) ir_variable(ivec, "exp", ir_var_temporary);
+
+ ir_variable *zero_sign_x = new(ir) ir_variable(ir->type, "zero_sign_x",
+ ir_var_temporary);
+
+ ir_variable *extracted_biased_exp =
+ new(ir) ir_variable(ivec, "extracted_biased_exp", ir_var_temporary);
+ ir_variable *resulting_biased_exp =
+ new(ir) ir_variable(ivec, "resulting_biased_exp", ir_var_temporary);
+
+ ir_variable *is_not_zero_or_underflow =
+ new(ir) ir_variable(bvec, "is_not_zero_or_underflow", ir_var_temporary);
+
+ ir_instruction &i = *base_ir;
+
+ /* Copy <x> and <exp> arguments. */
+ i.insert_before(x);
+ i.insert_before(assign(x, ir->operands[0]));
+ i.insert_before(exp);
+ i.insert_before(assign(exp, ir->operands[1]));
+
+ /* Extract the biased exponent from <x>. */
+ i.insert_before(extracted_biased_exp);
+ i.insert_before(assign(extracted_biased_exp,
+ rshift(bitcast_f2i(abs(x)), exp_shift)));
+
+ i.insert_before(resulting_biased_exp);
+ i.insert_before(assign(resulting_biased_exp,
+ add(extracted_biased_exp, exp)));
+
+ /* Test if result is ±0.0, subnormal, or underflow by checking if the
+ * resulting biased exponent would be less than 0x1. If so, the result is
+ * 0.0 with the sign of x. (Actually, invert the conditions so that
+ * immediate values are the second arguments, which is better for i965)
+ */
+ i.insert_before(zero_sign_x);
+ i.insert_before(assign(zero_sign_x,
+ bitcast_u2f(bit_or(bit_and(bitcast_f2u(x), sign_mask),
+ bitcast_f2u(zerof)))));
+
+ i.insert_before(is_not_zero_or_underflow);
+ i.insert_before(assign(is_not_zero_or_underflow,
+ gequal(resulting_biased_exp,
+ new(ir) ir_constant(0x1, vec_elem))));
+ i.insert_before(assign(x, csel(is_not_zero_or_underflow,
+ x, zero_sign_x)));
+ i.insert_before(assign(resulting_biased_exp,
+ csel(is_not_zero_or_underflow,
+ resulting_biased_exp, zeroi)));
+
+ /* We could test for overflows by checking if the resulting biased exponent
+ * would be greater than 0xFE. Turns out we don't need to because the GLSL
+ * spec says:
+ *
+ * "If this product is too large to be represented in the
+ * floating-point type, the result is undefined."
+ */
+
+ ir_constant *exp_shift_clone = exp_shift->clone(ir, NULL);
+ ir->operation = ir_unop_bitcast_u2f;
+ ir->operands[0] = bit_or(bit_and(bitcast_f2u(x), sign_mantissa_mask),
+ lshift(i2u(resulting_biased_exp), exp_shift_clone));
+ ir->operands[1] = NULL;
+
+ this->progress = true;
+}
+
ir_visitor_status
lower_instructions_visitor::visit_leave(ir_expression *ir)
{
@@ -378,6 +501,11 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
bitfield_insert_to_bfm_bfi(ir);
break;
+ case ir_binop_ldexp:
+ if (lowering(LDEXP_TO_ARITH))
+ ldexp_to_arith(ir);
+ break;
+
default:
return visit_continue;
}