Define dereferencing varying pointer to uniform struct with 'bound uniform' member.
This commit is contained in:
40
ctx.cpp
40
ctx.cpp
@@ -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
3
ctx.h
@@ -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);
|
||||||
|
|
||||||
|
|||||||
37
tests/struct-test-127.ispc
Normal file
37
tests/struct-test-127.ispc
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user