summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJosé Fonseca <[email protected]>2010-10-09 12:11:20 +0100
committerJosé Fonseca <[email protected]>2010-10-09 12:12:59 +0100
commit81a09c8a975ec1e727a7863823e39549c5096746 (patch)
treed617e8a8f5b1cc60b5f2e145adc6ad1f3abf14f3 /src
parent52427f0ba703f933b70d669ae565c7aeb733236d (diff)
gallivm: Less code duplication in log computation.
Diffstat (limited to 'src')
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_arit.c113
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_arit.h10
2 files changed, 88 insertions, 35 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.c b/src/gallium/auxiliary/gallivm/lp_bld_arit.c
index 6ab13506e15..2c049d02934 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_arit.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.c
@@ -2262,6 +2262,71 @@ lp_build_exp2(struct lp_build_context *bld,
/**
+ * Extract the exponent of a IEEE-754 floating point value.
+ *
+ * Optionally apply an integer bias.
+ *
+ * Result is an integer value with
+ *
+ * ifloor(log2(x)) + bias
+ */
+LLVMValueRef
+lp_build_extract_exponent(struct lp_build_context *bld,
+ LLVMValueRef x,
+ int bias)
+{
+ const struct lp_type type = bld->type;
+ unsigned mantissa = lp_mantissa(type);
+ LLVMValueRef res;
+
+ assert(type.floating);
+
+ assert(lp_check_value(bld->type, x));
+
+ x = LLVMBuildBitCast(bld->builder, x, bld->int_vec_type, "");
+
+ res = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
+ res = LLVMBuildAnd(bld->builder, res, lp_build_const_int_vec(type, 255), "");
+ res = LLVMBuildSub(bld->builder, res, lp_build_const_int_vec(type, 127 - bias), "");
+
+ return res;
+}
+
+
+/**
+ * Extract the mantissa of the a floating.
+ *
+ * Result is a floating point value with
+ *
+ * x / floor(log2(x))
+ */
+LLVMValueRef
+lp_build_extract_mantissa(struct lp_build_context *bld,
+ LLVMValueRef x)
+{
+ const struct lp_type type = bld->type;
+ unsigned mantissa = lp_mantissa(type);
+ LLVMValueRef mantmask = lp_build_const_int_vec(type, (1ULL << mantissa) - 1);
+ LLVMValueRef one = LLVMConstBitCast(bld->one, bld->int_vec_type);
+ LLVMValueRef res;
+
+ assert(lp_check_value(bld->type, x));
+
+ assert(type.floating);
+
+ x = LLVMBuildBitCast(bld->builder, x, bld->int_vec_type, "");
+
+ /* res = x / 2**ipart */
+ res = LLVMBuildAnd(bld->builder, x, mantmask, "");
+ res = LLVMBuildOr(bld->builder, res, one, "");
+ res = LLVMBuildBitCast(bld->builder, res, bld->vec_type, "");
+
+ return res;
+}
+
+
+
+/**
* Minimax polynomial fit of log2(x)/(x - 1), for x in range [1, 2[
* These coefficients can be generate with
* http://www.boost.org/doc/libs/1_36_0/libs/math/doc/sf_and_dist/html/math_toolkit/toolkit/internals2/minimax.html
@@ -2385,7 +2450,10 @@ lp_build_log2(struct lp_build_context *bld,
/**
* Faster (and less accurate) log2.
*
- * log2(x) = floor(log2(x)) + frac(x)
+ * log2(x) = floor(log2(x)) - 1 + x / 2**floor(log2(x))
+ *
+ * Piece-wise linear approximation, with exact results when x is a
+ * power of two.
*
* See http://www.flipcode.com/archives/Fast_log_Function.shtml
*/
@@ -2393,35 +2461,21 @@ LLVMValueRef
lp_build_fast_log2(struct lp_build_context *bld,
LLVMValueRef x)
{
- const struct lp_type type = bld->type;
- LLVMTypeRef vec_type = bld->vec_type;
- LLVMTypeRef int_vec_type = bld->int_vec_type;
-
- unsigned mantissa = lp_mantissa(type);
- LLVMValueRef mantmask = lp_build_const_int_vec(type, (1ULL << mantissa) - 1);
- LLVMValueRef one = LLVMConstBitCast(bld->one, int_vec_type);
-
LLVMValueRef ipart;
LLVMValueRef fpart;
assert(lp_check_value(bld->type, x));
- assert(type.floating);
-
- x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
+ assert(bld->type.floating);
/* ipart = floor(log2(x)) - 1 */
- ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
- ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
- ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 128), "");
- ipart = LLVMBuildSIToFP(bld->builder, ipart, vec_type, "");
+ ipart = lp_build_extract_exponent(bld, x, -1);
+ ipart = LLVMBuildSIToFP(bld->builder, ipart, bld->vec_type, "");
- /* fpart = 1.0 + frac(x) */
- fpart = LLVMBuildAnd(bld->builder, x, mantmask, "");
- fpart = LLVMBuildOr(bld->builder, fpart, one, "");
- fpart = LLVMBuildBitCast(bld->builder, fpart, vec_type, "");
+ /* fpart = x / 2**ipart */
+ fpart = lp_build_extract_mantissa(bld, x);
- /* floor(log2(x)) + frac(x) */
+ /* ipart + fpart */
return LLVMBuildFAdd(bld->builder, ipart, fpart, "");
}
@@ -2435,27 +2489,18 @@ LLVMValueRef
lp_build_ilog2(struct lp_build_context *bld,
LLVMValueRef x)
{
- const struct lp_type type = bld->type;
- LLVMTypeRef int_vec_type = bld->int_vec_type;
-
- unsigned mantissa = lp_mantissa(type);
- LLVMValueRef sqrt2 = lp_build_const_vec(type, 1.4142135623730951);
-
+ LLVMValueRef sqrt2 = lp_build_const_vec(bld->type, M_SQRT2);
LLVMValueRef ipart;
- assert(lp_check_value(bld->type, x));
+ assert(bld->type.floating);
- assert(type.floating);
+ assert(lp_check_value(bld->type, x));
/* x * 2^(0.5) i.e., add 0.5 to the log2(x) */
x = LLVMBuildFMul(bld->builder, x, sqrt2, "");
- x = LLVMBuildBitCast(bld->builder, x, int_vec_type, "");
-
/* ipart = floor(log2(x) + 0.5) */
- ipart = LLVMBuildLShr(bld->builder, x, lp_build_const_int_vec(type, mantissa), "");
- ipart = LLVMBuildAnd(bld->builder, ipart, lp_build_const_int_vec(type, 255), "");
- ipart = LLVMBuildSub(bld->builder, ipart, lp_build_const_int_vec(type, 127), "");
+ ipart = lp_build_extract_exponent(bld, x, 0);
return ipart;
}
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_arit.h b/src/gallium/auxiliary/gallivm/lp_bld_arit.h
index 8424384f8f7..c78b61decf0 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_arit.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_arit.h
@@ -215,6 +215,15 @@ lp_build_exp2(struct lp_build_context *bld,
LLVMValueRef a);
LLVMValueRef
+lp_build_extract_exponent(struct lp_build_context *bld,
+ LLVMValueRef x,
+ int bias);
+
+LLVMValueRef
+lp_build_extract_mantissa(struct lp_build_context *bld,
+ LLVMValueRef x);
+
+LLVMValueRef
lp_build_log2(struct lp_build_context *bld,
LLVMValueRef a);
@@ -226,7 +235,6 @@ LLVMValueRef
lp_build_ilog2(struct lp_build_context *bld,
LLVMValueRef x);
-
void
lp_build_exp2_approx(struct lp_build_context *bld,
LLVMValueRef x,