mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-02-14 22:00:28 +01:00
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:
parent
f478b6fe76
commit
272dadbe4e
5 changed files with 227 additions and 41 deletions
|
|
@ -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_,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue