Define dereferencing varying pointer to uniform struct with 'bound uniform' member.

This commit is contained in:
Vsevolod Livinskiy
2016-02-05 14:49:42 +03:00
parent 243d6c2625
commit 0ef3d3b429
3 changed files with 76 additions and 4 deletions

40
ctx.cpp
View File

@@ -2805,7 +2805,8 @@ FunctionEmitContext::loadUniformFromSOA(llvm::Value *ptr, llvm::Value *mask,
llvm::Value * llvm::Value *
FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask, FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask,
const Type *ptrRefType, const char *name) { const Type *ptrRefType, const char *name,
bool one_elem) {
if (ptr == NULL) { if (ptr == NULL) {
AssertPos(currentPos, m->errorCount > 0); AssertPos(currentPos, m->errorCount > 0);
return NULL; return NULL;
@@ -2861,7 +2862,33 @@ FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask,
else { else {
// Otherwise we should have a varying ptr and it's time for a // Otherwise we should have a varying ptr and it's time for a
// gather. // gather.
return gather(ptr, ptrType, GetFullMask(), name); llvm::Value *gather_result = gather(ptr, ptrType, GetFullMask(), name);
if (!one_elem)
return gather_result;
// It is a kludge. When we dereference varying pointer to uniform struct
// with "bound uniform" member, we should return first unmasked member.
Warning(currentPos, "Dereferencing varying pointer to uniform struct with 'bound uniform' member,\n"
" only one value will survive. Possible loss of data.");
// Call the target-dependent movmsk function to turn the vector mask
// into an i64 value
std::vector<Symbol *> mm;
m->symbolTable->LookupFunction("__movmsk", &mm);
if (g->target->getMaskBitCount() == 1)
AssertPos(currentPos, mm.size() == 1);
else
// There should be one with signed int signature, one unsigned int.
AssertPos(currentPos, mm.size() == 2);
// We can actually call either one, since both are i32s as far as
// LLVM's type system is concerned...
llvm::Function *fmm = mm[0]->function;
llvm::Value *int_mask = CallInst(fmm, NULL, mask, LLVMGetName(mask, "_movmsk"));
std::vector<Symbol *> lz;
m->symbolTable->LookupFunction("__count_trailing_zeros_i64", &lz);
llvm::Function *flz = lz[0]->function;
llvm::Value *elem_idx = CallInst(flz, NULL, int_mask, LLVMGetName(mask, "_clz"));
llvm::Value *elem = llvm::ExtractElementInst::Create(gather_result, elem_idx, LLVMGetName(gather_result, "_umasked_elem"), bblock);
return elem;
} }
} }
@@ -2882,6 +2909,9 @@ FunctionEmitContext::gather(llvm::Value *ptr, const PointerType *ptrType,
// result. // result.
llvm::Value *retValue = llvm::UndefValue::get(llvmReturnType); llvm::Value *retValue = llvm::UndefValue::get(llvmReturnType);
const CollectionType *returnCollectionType =
CastType<CollectionType>(returnType->GetBaseType());
for (int i = 0; i < collectionType->GetElementCount(); ++i) { for (int i = 0; i < collectionType->GetElementCount(); ++i) {
const PointerType *eltPtrType; const PointerType *eltPtrType;
llvm::Value *eltPtr = llvm::Value *eltPtr =
@@ -2889,8 +2919,12 @@ FunctionEmitContext::gather(llvm::Value *ptr, const PointerType *ptrType,
eltPtr = addVaryingOffsetsIfNeeded(eltPtr, eltPtrType); eltPtr = addVaryingOffsetsIfNeeded(eltPtr, eltPtrType);
// It is a kludge. When we dereference varying pointer to uniform struct
// with "bound uniform" member, we should return first unmasked member.
int need_one_elem = CastType<StructType>(ptrType->GetBaseType()) &&
returnCollectionType->GetElementType(i)->IsUniformType();
// This in turn will be another gather // This in turn will be another gather
llvm::Value *eltValues = LoadInst(eltPtr, mask, eltPtrType, name); llvm::Value *eltValues = LoadInst(eltPtr, mask, eltPtrType, name, need_one_elem);
retValue = InsertInst(retValue, eltValues, i, "set_value"); retValue = InsertInst(retValue, eltValues, i, "set_value");
} }

3
ctx.h
View File

@@ -481,7 +481,8 @@ public:
pointer values given by the lvalue. If the lvalue is not varying, pointer values given by the lvalue. If the lvalue is not varying,
then both the mask pointer and the type pointer may be NULL. */ then both the mask pointer and the type pointer may be NULL. */
llvm::Value *LoadInst(llvm::Value *ptr, llvm::Value *mask, llvm::Value *LoadInst(llvm::Value *ptr, llvm::Value *mask,
const Type *ptrType, const char *name = NULL); const Type *ptrType, const char *name = NULL,
bool one_elem = false);
llvm::Value *LoadInst(llvm::Value *ptr, const char *name = NULL); llvm::Value *LoadInst(llvm::Value *ptr, const char *name = NULL);

View File

@@ -0,0 +1,37 @@
export uniform int width() { return programCount; }
struct Foo {
uniform float x;
varying float y;
};
inline varying Foo func(uniform Foo * varying f)
{
return *f;
}
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex];
uniform Foo struct_1;
struct_1.x = b;
struct_1.y = aFOO[programIndex];
uniform Foo * varying ptr = &(struct_1);
varying Foo struct_2;
struct_2.x = -100;
struct_2.y = -150;
if (programIndex % 3 == 0)
struct_2 = func(ptr);
RET[programIndex] = struct_2.x + struct_2.y;
}
export void result(uniform float RET[]) {
if (programIndex % 3 == 0)
RET[programIndex] = 5 + programIndex + 1;
else
RET[programIndex] = -145;
}