llvmpipe: Clamped float to unsigned norm via mantissa manipulation.

This commit is contained in:
José Fonseca 2009-08-21 07:35:49 +01:00
parent 33ce51bc0d
commit 3dbf00f9ab
3 changed files with 113 additions and 17 deletions

View file

@ -46,6 +46,7 @@
#include "util/u_debug.h"
#include "util/u_math.h"
#include "lp_bld_type.h"
#include "lp_bld_const.h"
@ -54,6 +55,79 @@
#include "lp_bld_conv.h"
LLVMValueRef
lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
union lp_type src_type,
unsigned dst_width,
LLVMValueRef src)
{
LLVMTypeRef int_vec_type = lp_build_int_vec_type(src_type);
LLVMValueRef res;
unsigned mantissa;
unsigned n;
unsigned long long ubound;
unsigned long long mask;
double scale;
double bias;
assert(src_type.floating);
switch(src_type.width) {
case 32:
mantissa = 23;
break;
case 64:
mantissa = 53;
break;
default:
assert(0);
return LLVMGetUndef(int_vec_type);
}
/* We cannot carry more bits than the mantissa */
n = MIN2(mantissa, dst_width);
/* This magic coefficients will make the desired result to appear in the
* lowest significant bits of the mantissa.
*/
ubound = ((unsigned long long)1 << n);
mask = ubound - 1;
scale = (double)mask/ubound;
bias = (double)((unsigned long long)1 << (mantissa - n));
res = LLVMBuildMul(builder, src, lp_build_const_uni(src_type, scale), "");
res = LLVMBuildAdd(builder, res, lp_build_const_uni(src_type, bias), "");
res = LLVMBuildBitCast(builder, res, int_vec_type, "");
if(dst_width < src_type.width)
res = LLVMBuildAnd(builder, res, lp_build_int_const_uni(src_type, mask), "");
if(dst_width > n) {
int shift = dst_width - n;
res = LLVMBuildShl(builder, res, lp_build_int_const_uni(src_type, shift), "");
/* Fill in the empty lower bits for added precision? */
#if 0
{
LLVMValueRef msb;
msb = LLVMBuildLShr(builder, res, lp_build_int_const_uni(src_type, dst_width - 1), "");
msb = LLVMBuildShl(builder, msb, lp_build_int_const_uni(src_type, shift), "");
msb = LLVMBuildSub(builder, msb, lp_build_int_const_uni(src_type, 1), "");
res = LLVMBuildOr(builder, res, msb, "");
}
#elif 0
while(shift > 0) {
res = LLVMBuildOr(builder, res, LLVMBuildLShr(builder, res, lp_build_int_const_uni(src_type, n), ""), "");
shift -= n;
n *= 2;
}
#endif
}
return res;
}
/**
* Build shuffle vectors that match PUNPCKLxx and PUNPCKHxx instructions.
*/
@ -259,28 +333,39 @@ lp_build_conv(LLVMBuilderRef builder,
/* Nothing to do */
}
else if(tmp_type.floating) {
double dst_scale = lp_const_scale(dst_type);
LLVMTypeRef tmp_vec_type;
if (dst_scale != 1.0) {
LLVMValueRef scale = lp_build_const_uni(tmp_type, dst_scale);
for(i = 0; i < num_tmps; ++i)
tmp[i] = LLVMBuildMul(builder, tmp[i], scale, "");
if(!dst_type.fixed && !dst_type.sign && dst_type.norm) {
for(i = 0; i < num_tmps; ++i) {
tmp[i] = lp_build_clamped_float_to_unsigned_norm(builder,
tmp_type,
dst_type.width,
tmp[i]);
}
tmp_type.floating = FALSE;
}
else {
double dst_scale = lp_const_scale(dst_type);
LLVMTypeRef tmp_vec_type;
/* Use an equally sized integer for intermediate computations */
tmp_type.floating = FALSE;
tmp_vec_type = lp_build_vec_type(tmp_type);
for(i = 0; i < num_tmps; ++i) {
if (dst_scale != 1.0) {
LLVMValueRef scale = lp_build_const_uni(tmp_type, dst_scale);
for(i = 0; i < num_tmps; ++i)
tmp[i] = LLVMBuildMul(builder, tmp[i], scale, "");
}
/* Use an equally sized integer for intermediate computations */
tmp_type.floating = FALSE;
tmp_vec_type = lp_build_vec_type(tmp_type);
for(i = 0; i < num_tmps; ++i) {
#if 0
if(dst_type.sign)
tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
else
tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, "");
if(dst_type.sign)
tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
else
tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, "");
#else
/* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */
tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
/* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */
tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
#endif
}
}
}
else {

View file

@ -43,6 +43,13 @@
union lp_type type;
LLVMValueRef
lp_build_clamped_float_to_unsigned_norm(LLVMBuilderRef builder,
union lp_type src_type,
unsigned dst_width,
LLVMValueRef src);
void
lp_build_conv(LLVMBuilderRef builder,
union lp_type src_type,

View file

@ -113,6 +113,10 @@ void
random_vec(union lp_type type, void *dst);
boolean
compare_vec_with_eps(union lp_type type, const void *res, const void *ref, double eps);
boolean
compare_vec(union lp_type type, const void *res, const void *ref);