summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosé Fonseca <jfonseca@vmware.com>2009-09-29 16:59:13 +0100
committerJosé Fonseca <jfonseca@vmware.com>2009-09-29 17:28:15 +0100
commit741c40a232637c933c9273bbdef905397e54bc94 (patch)
treefeb309a915af06cb8001a990b1826e4183dc0a60 /src
parent124f5875eae0b914d5c679fec6b25633907ad843 (diff)
llvmpipe: Implement non SSE4.1 versions of floor and round.
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_arit.c177
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_arit.h13
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_sample_soa.c4
3 files changed, 159 insertions, 35 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.c b/src/gallium/drivers/llvmpipe/lp_bld_arit.c
index e8c5fa3c2a..f878706ad1 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_arit.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.c
@@ -675,6 +675,8 @@ lp_build_round_sse41(struct lp_build_context *bld,
assert(type.floating);
assert(type.width*type.length == 128);
+ assert(lp_check_value(type, a));
+ assert(util_cpu_caps.has_sse4_1);
switch(type.width) {
case 32:
@@ -694,19 +696,45 @@ lp_build_round_sse41(struct lp_build_context *bld,
LLVMValueRef
+lp_build_trunc(struct lp_build_context *bld,
+ LLVMValueRef a)
+{
+ const struct lp_type type = bld->type;
+
+ assert(type.floating);
+ assert(lp_check_value(type, a));
+
+ if(util_cpu_caps.has_sse4_1)
+ return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_TRUNCATE);
+ else {
+ LLVMTypeRef vec_type = lp_build_vec_type(type);
+ LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
+ LLVMValueRef res;
+ res = LLVMBuildFPToSI(bld->builder, a, int_vec_type, "");
+ res = LLVMBuildSIToFP(bld->builder, res, vec_type, "");
+ return res;
+ }
+}
+
+
+LLVMValueRef
lp_build_round(struct lp_build_context *bld,
LLVMValueRef a)
{
const struct lp_type type = bld->type;
assert(type.floating);
+ assert(lp_check_value(type, a));
if(util_cpu_caps.has_sse4_1)
return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
-
- /* FIXME */
- assert(0);
- return bld->undef;
+ else {
+ LLVMTypeRef vec_type = lp_build_vec_type(type);
+ LLVMValueRef res;
+ res = lp_build_iround(bld, a);
+ res = LLVMBuildSIToFP(bld->builder, res, vec_type, "");
+ return res;
+ }
}
@@ -720,10 +748,13 @@ lp_build_floor(struct lp_build_context *bld,
if(util_cpu_caps.has_sse4_1)
return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_FLOOR);
-
- /* FIXME */
- assert(0);
- return bld->undef;
+ else {
+ LLVMTypeRef vec_type = lp_build_vec_type(type);
+ LLVMValueRef res;
+ res = lp_build_ifloor(bld, a);
+ res = LLVMBuildSIToFP(bld->builder, res, vec_type, "");
+ return res;
+ }
}
@@ -734,47 +765,74 @@ lp_build_ceil(struct lp_build_context *bld,
const struct lp_type type = bld->type;
assert(type.floating);
+ assert(lp_check_value(type, a));
if(util_cpu_caps.has_sse4_1)
return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_CEIL);
-
- /* FIXME */
- assert(0);
- return bld->undef;
+ else {
+ LLVMTypeRef vec_type = lp_build_vec_type(type);
+ LLVMValueRef res;
+ res = lp_build_iceil(bld, a);
+ res = LLVMBuildSIToFP(bld->builder, res, vec_type, "");
+ return res;
+ }
}
+/**
+ * Convert to integer, through whichever rounding method that's fastest,
+ * typically truncating to zero.
+ */
LLVMValueRef
-lp_build_trunc(struct lp_build_context *bld,
- LLVMValueRef a)
+lp_build_itrunc(struct lp_build_context *bld,
+ LLVMValueRef a)
{
const struct lp_type type = bld->type;
+ LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
assert(type.floating);
+ assert(lp_check_value(type, a));
- if(util_cpu_caps.has_sse4_1)
- return lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_TRUNCATE);
-
- /* FIXME */
- assert(0);
- return bld->undef;
+ return LLVMBuildFPToSI(bld->builder, a, int_vec_type, "");
}
-/**
- * Convert to integer, through whichever rounding method that's fastest,
- * typically truncating to zero.
- */
LLVMValueRef
-lp_build_int(struct lp_build_context *bld,
- LLVMValueRef a)
+lp_build_iround(struct lp_build_context *bld,
+ LLVMValueRef a)
{
const struct lp_type type = bld->type;
LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
+ LLVMValueRef res;
assert(type.floating);
+ assert(lp_check_value(type, a));
- return LLVMBuildFPToSI(bld->builder, a, int_vec_type, "");
+ if(util_cpu_caps.has_sse4_1) {
+ res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_NEAREST);
+ }
+ else {
+ LLVMTypeRef vec_type = lp_build_vec_type(type);
+ LLVMValueRef mask = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1));
+ LLVMValueRef sign;
+ LLVMValueRef half;
+
+ /* get sign bit */
+ sign = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
+ sign = LLVMBuildAnd(bld->builder, sign, mask, "");
+
+ /* sign * 0.5 */
+ half = lp_build_const_scalar(type, 0.5);
+ half = LLVMBuildBitCast(bld->builder, half, int_vec_type, "");
+ half = LLVMBuildOr(bld->builder, sign, half, "");
+ half = LLVMBuildBitCast(bld->builder, half, vec_type, "");
+
+ res = LLVMBuildAdd(bld->builder, a, half, "");
+ }
+
+ res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, "");
+
+ return res;
}
@@ -782,9 +840,68 @@ LLVMValueRef
lp_build_ifloor(struct lp_build_context *bld,
LLVMValueRef a)
{
- a = lp_build_floor(bld, a);
- a = lp_build_int(bld, a);
- return a;
+ const struct lp_type type = bld->type;
+ LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
+ LLVMValueRef res;
+
+ assert(type.floating);
+ assert(lp_check_value(type, a));
+
+ if(util_cpu_caps.has_sse4_1) {
+ res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_FLOOR);
+ }
+ else {
+ /* Take the sign bit and add it to 1 constant */
+ LLVMTypeRef vec_type = lp_build_vec_type(type);
+ unsigned mantissa = lp_mantissa(type);
+ LLVMValueRef mask = lp_build_int_const_scalar(type, (unsigned long long)1 << (type.width - 1));
+ LLVMValueRef sign;
+ LLVMValueRef offset;
+
+ /* sign = a < 0 ? ~0 : 0 */
+ sign = LLVMBuildBitCast(bld->builder, a, int_vec_type, "");
+ sign = LLVMBuildAnd(bld->builder, sign, mask, "");
+ sign = LLVMBuildAShr(bld->builder, sign, lp_build_int_const_scalar(type, type.width - 1), "");
+
+ /* offset = -0.99999(9)f */
+ offset = lp_build_const_scalar(type, -(double)(((unsigned long long)1 << mantissa) - 1)/((unsigned long long)1 << mantissa));
+ offset = LLVMConstBitCast(offset, int_vec_type);
+
+ /* offset = a < 0 ? -0.99999(9)f : 0.0f */
+ offset = LLVMBuildAnd(bld->builder, offset, sign, "");
+ offset = LLVMBuildBitCast(bld->builder, offset, vec_type, "");
+
+ res = LLVMBuildAdd(bld->builder, a, offset, "");
+ }
+
+ res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, "");
+
+ return res;
+}
+
+
+LLVMValueRef
+lp_build_iceil(struct lp_build_context *bld,
+ LLVMValueRef a)
+{
+ const struct lp_type type = bld->type;
+ LLVMTypeRef int_vec_type = lp_build_int_vec_type(type);
+ LLVMValueRef res;
+
+ assert(type.floating);
+ assert(lp_check_value(type, a));
+
+ if(util_cpu_caps.has_sse4_1) {
+ res = lp_build_round_sse41(bld, a, LP_BUILD_ROUND_SSE41_CEIL);
+ }
+ else {
+ assert(0);
+ res = bld->undef;
+ }
+
+ res = LLVMBuildFPToSI(bld->builder, res, int_vec_type, "");
+
+ return res;
}
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_arit.h b/src/gallium/drivers/llvmpipe/lp_bld_arit.h
index d68a97c4b8..095a8e1cab 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_arit.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_arit.h
@@ -126,11 +126,18 @@ lp_build_trunc(struct lp_build_context *bld,
LLVMValueRef a);
LLVMValueRef
-lp_build_int(struct lp_build_context *bld,
- LLVMValueRef a);
+lp_build_ifloor(struct lp_build_context *bld,
+ LLVMValueRef a);
+LLVMValueRef
+lp_build_iceil(struct lp_build_context *bld,
+ LLVMValueRef a);
LLVMValueRef
-lp_build_ifloor(struct lp_build_context *bld,
+lp_build_iround(struct lp_build_context *bld,
+ LLVMValueRef a);
+
+LLVMValueRef
+lp_build_itrunc(struct lp_build_context *bld,
LLVMValueRef a);
LLVMValueRef
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_sample_soa.c b/src/gallium/drivers/llvmpipe/lp_bld_sample_soa.c
index 8ca1be6f1b..1a47ca32d2 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_sample_soa.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_sample_soa.c
@@ -274,8 +274,8 @@ lp_build_sample_2d_linear_soa(struct lp_build_sample_context *bld,
s_fpart = lp_build_sub(&bld->coord_bld, s, s_ipart);
t_fpart = lp_build_sub(&bld->coord_bld, t, t_ipart);
- x0 = lp_build_int(&bld->coord_bld, s_ipart);
- y0 = lp_build_int(&bld->coord_bld, t_ipart);
+ x0 = lp_build_itrunc(&bld->coord_bld, s_ipart);
+ y0 = lp_build_itrunc(&bld->coord_bld, t_ipart);
x0 = lp_build_sample_wrap(bld, x0, width, bld->static_state->pot_width, bld->static_state->wrap_s);
y0 = lp_build_sample_wrap(bld, y0, height, bld->static_state->pot_height, bld->static_state->wrap_t);