llvmpipe: Introduce a custom typing system.

Straightforward representation of floating-point/fixed-point/integer,
normalized/scaled, signed/unsigned SIMD vector types.
This commit is contained in:
José Fonseca 2009-08-02 13:52:40 +01:00
parent f478b6fe76
commit 272dadbe4e
5 changed files with 227 additions and 41 deletions

View file

@ -46,6 +46,7 @@
struct pipe_blend_state;
union lp_type;
/**
@ -134,6 +135,7 @@ lp_build_logicop(LLVMBuilderRef builder,
LLVMValueRef
lp_build_blend(LLVMBuilderRef builder,
const struct pipe_blend_state *blend,
union lp_type type,
LLVMValueRef src,
LLVMValueRef dst,
LLVMValueRef const_,

View file

@ -50,56 +50,143 @@
#include "lp_bld_arit.h"
LLVMTypeRef
lp_build_elem_type(union lp_type type)
{
if (type.kind == LP_TYPE_FLOAT) {
assert(type.sign);
switch(type.width) {
case 32:
return LLVMFloatType();
break;
case 64:
return LLVMDoubleType();
break;
default:
assert(0);
return LLVMFloatType();
}
}
else {
return LLVMIntType(type.width);
}
}
LLVMTypeRef
lp_build_vec_type(union lp_type type)
{
LLVMTypeRef elem_type = lp_build_elem_type(type);
return LLVMVectorType(elem_type, type.length);
}
/**
* This function is a mirrot of lp_build_elem_type() above.
*
* XXX: I'm not sure if it wouldn't be easier/efficient to just recreate the
* type and check for identity.
*/
boolean
lp_check_elem_type(union lp_type type, LLVMTypeRef elem_type)
{
LLVMTypeKind elem_kind = LLVMGetTypeKind(elem_type);
if (type.kind == LP_TYPE_FLOAT) {
switch(type.width) {
case 32:
if(elem_kind != LLVMFloatTypeKind)
return FALSE;
break;
case 64:
if(elem_kind != LLVMDoubleTypeKind)
return FALSE;
break;
default:
assert(0);
return FALSE;
}
}
else {
if(elem_kind != LLVMIntegerTypeKind)
return FALSE;
if(LLVMGetIntTypeWidth(elem_type) != type.width)
return FALSE;
}
return TRUE;
}
boolean
lp_check_vec_type(union lp_type type, LLVMTypeRef vec_type)
{
LLVMTypeRef elem_type;
if(LLVMGetTypeKind(vec_type) != LLVMVectorTypeKind)
return FALSE;
if(LLVMGetVectorSize(vec_type) != type.length)
return FALSE;
elem_type = LLVMGetElementType(vec_type);
return lp_check_elem_type(type, elem_type);
}
LLVMValueRef
lp_build_const_aos(LLVMTypeRef type,
lp_build_const_aos(union lp_type type,
double r, double g, double b, double a,
const unsigned char *swizzle)
{
const unsigned char default_swizzle[4] = {0, 1, 2, 3};
LLVMTypeRef elem_type;
unsigned num_elems;
unsigned elem_width;
LLVMValueRef elems[LP_MAX_VECTOR_SIZE];
double scale;
LLVMValueRef elems[LP_MAX_VECTOR_LENGTH];
unsigned i;
num_elems = LLVMGetVectorSize(type);
assert(num_elems % 4 == 0);
assert(num_elems < LP_MAX_VECTOR_SIZE);
assert(type.length % 4 == 0);
assert(type.length < LP_MAX_VECTOR_LENGTH);
elem_type = LLVMGetElementType(type);
elem_type = lp_build_elem_type(type);
if(swizzle == NULL)
swizzle = default_swizzle;
switch(LLVMGetTypeKind(elem_type)) {
case LLVMFloatTypeKind:
for(i = 0; i < num_elems; i += 4) {
if(type.kind == LP_TYPE_FLOAT) {
for(i = 0; i < type.length; i += 4) {
elems[i + swizzle[0]] = LLVMConstReal(elem_type, r);
elems[i + swizzle[1]] = LLVMConstReal(elem_type, g);
elems[i + swizzle[2]] = LLVMConstReal(elem_type, b);
elems[i + swizzle[3]] = LLVMConstReal(elem_type, a);
}
break;
}
else {
unsigned shift;
long long llscale;
double dscale;
case LLVMIntegerTypeKind:
elem_width = LLVMGetIntTypeWidth(elem_type);
assert(elem_width <= 32);
scale = (double)((1 << elem_width) - 1);
for(i = 0; i < num_elems; i += 4) {
elems[i + swizzle[0]] = LLVMConstInt(elem_type, r*scale + 0.5, 0);
elems[i + swizzle[1]] = LLVMConstInt(elem_type, g*scale + 0.5, 0);
elems[i + swizzle[2]] = LLVMConstInt(elem_type, b*scale + 0.5, 0);
elems[i + swizzle[3]] = LLVMConstInt(elem_type, a*scale + 0.5, 0);
if(type.kind == LP_TYPE_FIXED)
shift = type.width/2;
else if(type.norm)
shift = type.sign ? type.width - 1 : type.width;
else
shift = 0;
llscale = (long long)1 << shift;
dscale = (double)llscale;
assert((long long)dscale == llscale);
for(i = 0; i < type.length; i += 4) {
elems[i + swizzle[0]] = LLVMConstInt(elem_type, r*dscale + 0.5, 0);
elems[i + swizzle[1]] = LLVMConstInt(elem_type, g*dscale + 0.5, 0);
elems[i + swizzle[2]] = LLVMConstInt(elem_type, b*dscale + 0.5, 0);
elems[i + swizzle[3]] = LLVMConstInt(elem_type, a*dscale + 0.5, 0);
}
break;
default:
assert(0);
return LLVMGetUndef(type);
}
return LLVMConstVector(elems, num_elems);
return LLVMConstVector(elems, type.length);
}

View file

@ -25,6 +25,14 @@
*
**************************************************************************/
/**
* @file
* Helper arithmetic functions.
*
* @author Jose Fonseca <jfonseca@vmware.com>
*/
#ifndef LP_BLD_ARIT_H
#define LP_BLD_ARIT_H
@ -32,7 +40,87 @@
#include <llvm-c/Core.h>
#define LP_MAX_VECTOR_SIZE 16
#define LP_MAX_VECTOR_LENGTH 16
/*
* Types
*/
enum lp_type_kind {
LP_TYPE_INTEGER = 0,
LP_TYPE_FLOAT = 1,
LP_TYPE_FIXED = 2
};
/**
* The LLVM type system can't conveniently express all the things we care about
* on the types used for intermediate computations, such as signed vs unsigned,
* normalized values, or fixed point.
*/
union lp_type {
struct {
/**
* Integer. floating-point, or fixed point as established by the
* lp_build_type_kind enum above.
*/
unsigned kind:2;
/**
* Whether it can represent negative values or not.
*
* Floating point values
*/
unsigned sign:1;
/**
* Whether values are normalized to fit [0, 1] interval, or [-1, 1] interval for
* signed types.
*
* For integer types
*
* It makes no sense to use this with fixed point values.
*/
unsigned norm:1;
/**
* Element width.
*
* For fixed point values, the fixed point is assumed to be at half the width.
*/
unsigned width:14;
/**
* Vector length.
*
* width*length should be a power of two greater or equal to height.
*
* Several functions can only cope with vectors of length up to
* LP_MAX_VECTOR_LENGTH, so you may need to increase that value if you
* want to represent bigger vectors.
*/
unsigned length:14;
};
uint32_t value;
};
LLVMTypeRef
lp_build_elem_type(union lp_type type);
LLVMTypeRef
lp_build_vec_type(union lp_type type);
boolean
lp_check_elem_type(union lp_type type, LLVMTypeRef elem_type);
boolean
lp_check_vec_type(union lp_type type, LLVMTypeRef vec_type);
/*
@ -40,7 +128,7 @@
*/
LLVMValueRef
lp_build_const_aos(LLVMTypeRef type,
lp_build_const_aos(union lp_type type,
double r, double g, double b, double a,
const unsigned char *swizzle);

View file

@ -182,7 +182,7 @@ lp_build_blend_swizzle(struct lp_build_blend_values *values,
unsigned alpha_swizzle,
unsigned n)
{
LLVMValueRef swizzles[LP_MAX_VECTOR_SIZE];
LLVMValueRef swizzles[LP_MAX_VECTOR_LENGTH];
unsigned i, j;
if(rgb == alpha) {
@ -268,6 +268,7 @@ lp_build_blend_func(struct lp_build_blend_values *values,
LLVMValueRef
lp_build_blend(LLVMBuilderRef builder,
const struct pipe_blend_state *blend,
union lp_type type,
LLVMValueRef src,
LLVMValueRef dst,
LLVMValueRef const_,
@ -276,19 +277,17 @@ lp_build_blend(LLVMBuilderRef builder,
struct lp_build_blend_values values;
LLVMValueRef src_term;
LLVMValueRef dst_term;
LLVMTypeRef type;
unsigned n;
LLVMTypeRef vec_type;
type = LLVMTypeOf(src);
n = LLVMGetVectorSize(type);
vec_type = lp_build_vec_type(type);
/*
* Compute constants
*/
memset(&values, 0, sizeof values);
values.builder = builder;
values.undef = LLVMGetUndef(type);
values.zero = LLVMConstNull(type);
values.undef = LLVMGetUndef(vec_type);
values.zero = LLVMConstNull(vec_type);
values.one = lp_build_const_aos(type, 1.0, 1.0, 1.0, 1.0, NULL);
values.src = src;
@ -299,8 +298,8 @@ lp_build_blend(LLVMBuilderRef builder,
* combinations it is possible to reorder the operations and therefor saving
* some instructions. */
src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, n);
dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, n);
src_term = lp_build_blend_factor(&values, src, blend->rgb_src_factor, blend->alpha_src_factor, alpha_swizzle, type.length);
dst_term = lp_build_blend_factor(&values, dst, blend->rgb_dst_factor, blend->alpha_dst_factor, alpha_swizzle, type.length);
if(blend->rgb_func == blend->alpha_func) {
return lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
@ -314,6 +313,6 @@ lp_build_blend(LLVMBuilderRef builder,
rgb = lp_build_blend_func(&values, blend->rgb_func, src_term, dst_term);
alpha = lp_build_blend_func(&values, blend->alpha_func, src_term, dst_term);
return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, n);
return lp_build_blend_swizzle(&values, rgb, alpha, LP_BUILD_BLEND_SWIZZLE_RGBA, alpha_swizzle, type.length);
}
}

View file

@ -52,6 +52,7 @@
#include "util/u_math.h"
#include "lp_bld.h"
#include "lp_bld_arit.h"
unsigned verbose = 0;
@ -64,6 +65,8 @@ static LLVMValueRef
add_blend_test(LLVMModuleRef module,
const struct pipe_blend_state *blend)
{
union lp_type type;
LLVMTypeRef args[4];
LLVMValueRef func;
LLVMValueRef src_ptr;
@ -77,6 +80,13 @@ add_blend_test(LLVMModuleRef module,
LLVMValueRef const_;
LLVMValueRef res;
type.value = 0;
type.kind = LP_TYPE_FLOAT;
type.sign = TRUE;
type.norm = TRUE;
type.width = 32;
type.length = 4;
args[0] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
args[1] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
args[2] = LLVMPointerType(LLVMVectorType(LLVMFloatType(), 4), 0);
@ -96,7 +106,7 @@ add_blend_test(LLVMModuleRef module,
dst = LLVMBuildLoad(builder, dst_ptr, "dst");
const_ = LLVMBuildLoad(builder, const_ptr, "const");
res = lp_build_blend(builder, blend, src, dst, const_, 3);
res = lp_build_blend(builder, blend, type, src, dst, const_, 3);
LLVMSetValueName(res, "res");