From 0ef3d3b429030ebd26d762e6dd945bc00f5ab6f8 Mon Sep 17 00:00:00 2001 From: Vsevolod Livinskiy Date: Fri, 5 Feb 2016 14:49:42 +0300 Subject: [PATCH] Define dereferencing varying pointer to uniform struct with 'bound uniform' member. --- ctx.cpp | 40 +++++++++++++++++++++++++++++++++++--- ctx.h | 3 ++- tests/struct-test-127.ispc | 37 +++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 tests/struct-test-127.ispc diff --git a/ctx.cpp b/ctx.cpp index 367ec381..d0aa9ef2 100644 --- a/ctx.cpp +++ b/ctx.cpp @@ -2805,7 +2805,8 @@ FunctionEmitContext::loadUniformFromSOA(llvm::Value *ptr, llvm::Value *mask, llvm::Value * 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) { AssertPos(currentPos, m->errorCount > 0); return NULL; @@ -2861,7 +2862,33 @@ FunctionEmitContext::LoadInst(llvm::Value *ptr, llvm::Value *mask, else { // Otherwise we should have a varying ptr and it's time for a // 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 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 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. llvm::Value *retValue = llvm::UndefValue::get(llvmReturnType); + const CollectionType *returnCollectionType = + CastType(returnType->GetBaseType()); + for (int i = 0; i < collectionType->GetElementCount(); ++i) { const PointerType *eltPtrType; llvm::Value *eltPtr = @@ -2889,8 +2919,12 @@ FunctionEmitContext::gather(llvm::Value *ptr, const PointerType *ptrType, 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(ptrType->GetBaseType()) && + returnCollectionType->GetElementType(i)->IsUniformType(); // 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"); } diff --git a/ctx.h b/ctx.h index 3f52cdc4..dff5f3ec 100644 --- a/ctx.h +++ b/ctx.h @@ -481,7 +481,8 @@ public: pointer values given by the lvalue. If the lvalue is not varying, then both the mask pointer and the type pointer may be NULL. */ 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); diff --git a/tests/struct-test-127.ispc b/tests/struct-test-127.ispc new file mode 100644 index 00000000..75e04498 --- /dev/null +++ b/tests/struct-test-127.ispc @@ -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; +} +