Incorporate per-lane offsets for varying data in the front-end.

Previously, it was only in the GatherScatterFlattenOpt optimization pass that
we added the per-lane offsets when we were indexing into varying data.
(Specifically, the case of float foo[]; int index; foo[index], where foo
is an array of varying elements rather than uniform elements.)  Now, this
is done in the front-end as we're first emitting code.

In addition to the basic ugliness of doing this in an optimization pass, 
it was also error-prone to do it there, since we no longer have access
to all of the type information that's around in the front-end.

No functionality or performance change.
This commit is contained in:
Matt Pharr
2011-11-03 13:15:07 -07:00
parent 6084d6aeaf
commit 43a2d510bf
7 changed files with 247 additions and 129 deletions

47
ctx.cpp
View File

@@ -1302,7 +1302,7 @@ FunctionEmitContext::GetElementPtrInst(llvm::Value *basePtr, llvm::Value *index0
} }
// FIXME: do we need need to handle the case of the first index being // FIXME: do we need need to handle the case of the first index being
// varying? It's currently needed... // varying? It's not currently needed...
assert(!llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(index0->getType())); assert(!llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(index0->getType()));
LLVM_TYPE_CONST llvm::Type *basePtrType = basePtr->getType(); LLVM_TYPE_CONST llvm::Type *basePtrType = basePtr->getType();
@@ -1499,6 +1499,8 @@ FunctionEmitContext::gather(llvm::Value *lvalue, llvm::Value *mask,
} }
assert(gather != NULL); assert(gather != NULL);
lvalue = addVaryingOffsetsIfNeeded(lvalue, type);
llvm::Value *voidlvalue = BitCastInst(lvalue, LLVMTypes::VoidPointerType); llvm::Value *voidlvalue = BitCastInst(lvalue, LLVMTypes::VoidPointerType);
llvm::Instruction *call = CallInst(gather, voidlvalue, mask, name); llvm::Instruction *call = CallInst(gather, voidlvalue, mask, name);
// Add metadata about the source file location so that the // Add metadata about the source file location so that the
@@ -1716,6 +1718,8 @@ FunctionEmitContext::scatter(llvm::Value *rvalue, llvm::Value *lvalue,
AddInstrumentationPoint("scatter"); AddInstrumentationPoint("scatter");
lvalue = addVaryingOffsetsIfNeeded(lvalue, rvalueType);
llvm::Value *voidlvalue = BitCastInst(lvalue, LLVMTypes::VoidPointerType); llvm::Value *voidlvalue = BitCastInst(lvalue, LLVMTypes::VoidPointerType);
std::vector<llvm::Value *> args; std::vector<llvm::Value *> args;
args.push_back(voidlvalue); args.push_back(voidlvalue);
@@ -2041,3 +2045,44 @@ FunctionEmitContext::SyncInst() {
SetCurrentBasicBlock(bPostSync); SetCurrentBasicBlock(bPostSync);
} }
/** When we gathering from or scattering to a varying atomic type, we need
to add an appropraite toffset to the final address for each lane right
before we use it. Given a varying pointer we're about to use and its
type, this function determines whether these offsets are needed and
returns an updated pointer that incorporates these offsets if needed.
*/
llvm::Value *
FunctionEmitContext::addVaryingOffsetsIfNeeded(llvm::Value *ptr, const Type *type) {
// We should only have varying pointers here, which are represented as
// arrays of pointers in ispc.
LLVM_TYPE_CONST llvm::ArrayType *at =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(ptr->getType());
assert(at != NULL);
LLVM_TYPE_CONST llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(at->getElementType());
assert(pt != NULL);
// If we have pointers to vector types, e.g. [8 x <8 x float> *], then
// the data we're gathering from/scattering to is varying in memory.
// If we have pointers to scalar types, e.g. [8 x float *], then the
// data is uniform in memory and doesn't need any additional offsets.
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(pt->getElementType()) == false)
return ptr;
llvm::Value *varyingOffsets = llvm::UndefValue::get(LLVMTypes::Int32VectorType);
for (int i = 0; i < g->target.vectorWidth; ++i)
varyingOffsets = InsertInst(varyingOffsets, LLVMInt32(i), i,
"varying_delta");
// Cast the pointer type to the corresponding uniform type--e.g. cast
// <8 x float> * to float *s.
LLVM_TYPE_CONST llvm::Type *unifType = type->GetAsUniformType()->LLVMType(g->ctx);
LLVM_TYPE_CONST llvm::PointerType *ptrCastType =
llvm::PointerType::get(llvm::ArrayType::get(unifType, 0), 0);
ptr = BitCastInst(ptr, ptrCastType, "ptr2unif");
// And now we can do the per-lane offsets...
return GetElementPtrInst(ptr, LLVMInt32(0), varyingOffsets);
}

1
ctx.h
View File

@@ -525,6 +525,7 @@ private:
const Type *type, const char *name); const Type *type, const char *name);
void maskedStore(llvm::Value *rvalue, llvm::Value *lvalue, void maskedStore(llvm::Value *rvalue, llvm::Value *lvalue,
const Type *rvalueType, llvm::Value *maskPtr); const Type *rvalueType, llvm::Value *maskPtr);
llvm::Value *addVaryingOffsetsIfNeeded(llvm::Value *value, const Type *type);
}; };
#endif // ISPC_CTX_H #endif // ISPC_CTX_H

240
expr.cpp
View File

@@ -2522,6 +2522,78 @@ lCastUniformVectorBasePtr(llvm::Value *ptr, FunctionEmitContext *ctx) {
} }
/** When computing pointer values, we need to apply a per-lane offset when
we're indexing into varying data. Consdier the following ispc code:
uniform float u[] = ...;
float v[] = ...;
int index = ...;
float a = u[index];
float b = v[index];
To compute the varying pointer that holds the addresses to load from
for u[index], we basically just need to multiply index element-wise by
sizeof(float) before doing the memory load. For v[index], we need to
do the same scaling but also need to add per-lane offsets <0,
sizeof(float), 2*sizeof(float), ...> so that the i'th lane loads the
i'th of the varying values at its index value.
This function handles figuring out when this additional offset is
needed and then incorporates it in the varying pointer value.
*/
static llvm::Value *
lAddVaryingOffsetsIfNeeded(FunctionEmitContext *ctx, llvm::Value *ptr,
const Type *returnType, const Type *indexedType) {
// If the result of the indexing isn't a varying atomic type, then
// nothing to do here.
if (returnType->IsVaryingType() == false ||
dynamic_cast<const AtomicType *>(returnType) == NULL)
return ptr;
// We should now have an array of pointer values, represing in a
// varying pointer.
LLVM_TYPE_CONST llvm::ArrayType *at =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::ArrayType>(ptr->getType());
if (at == NULL)
return ptr;
LLVM_TYPE_CONST llvm::PointerType *pt =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(at->getElementType());
assert(pt != NULL);
// If the pointers are to uniform types (e.g. ptr->getType() ==
// [8 x float *]), then we have the u[index] situation from the comment
// above, and no additional offset is needed. Otherwise we have
// pointers to varying atomic types--e.g. ptr->getType() ==
// [8 x <8 x float> *]
if (llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(pt->getElementType()) == false)
return ptr;
// But not so fast: if the reason we have a vector of pointers is that
// we're indexing into an array of uniform short-vector types, then we
// don't need the offsets.
if (dynamic_cast<const VectorType *>(indexedType) != NULL)
return ptr;
// Onward: compute the per lane offsets.
llvm::Value *varyingOffsets =
llvm::UndefValue::get(LLVMTypes::Int32VectorType);
for (int i = 0; i < g->target.vectorWidth; ++i)
varyingOffsets = ctx->InsertInst(varyingOffsets, LLVMInt32(i), i,
"varying_delta");
// Cast the pointer to the corresponding uniform pointer
// type--e.g. from [8 x <8 x float> *] to [8 x float *].
LLVM_TYPE_CONST llvm::Type *unifType =
returnType->GetAsUniformType()->LLVMType(g->ctx);
LLVM_TYPE_CONST llvm::PointerType *ptrCastType =
llvm::PointerType::get(llvm::ArrayType::get(unifType, 0), 0);
ptr = ctx->BitCastInst(ptr, ptrCastType, "ptr2unif");
// And finally add the per-lane offsets.
return ctx->GetElementPtrInst(ptr, LLVMInt32(0), varyingOffsets);
}
llvm::Value * llvm::Value *
IndexExpr::GetValue(FunctionEmitContext *ctx) const { IndexExpr::GetValue(FunctionEmitContext *ctx) const {
const Type *arrayOrVectorType; const Type *arrayOrVectorType;
@@ -2547,6 +2619,8 @@ IndexExpr::GetValue(FunctionEmitContext *ctx) const {
ctx->StoreInst(val, ptr); ctx->StoreInst(val, ptr);
ptr = lCastUniformVectorBasePtr(ptr, ctx); ptr = lCastUniformVectorBasePtr(ptr, ctx);
lvalue = ctx->GetElementPtrInst(ptr, LLVMInt32(0), index->GetValue(ctx)); lvalue = ctx->GetElementPtrInst(ptr, LLVMInt32(0), index->GetValue(ctx));
lvalue = lAddVaryingOffsetsIfNeeded(ctx, lvalue, GetType(),
arrayOrVectorType);
mask = LLVMMaskAllOn; mask = LLVMMaskAllOn;
} }
else { else {
@@ -2593,19 +2667,20 @@ IndexExpr::GetBaseSymbol() const {
llvm::Value * llvm::Value *
IndexExpr::GetLValue(FunctionEmitContext *ctx) const { IndexExpr::GetLValue(FunctionEmitContext *ctx) const {
const Type *type; const Type *arrayOrVectorType;
if (!arrayOrVector || !index || ((type = arrayOrVector->GetType()) == NULL)) if (arrayOrVector == NULL || index == NULL ||
((arrayOrVectorType = arrayOrVector->GetType()) == NULL))
return NULL; return NULL;
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
llvm::Value *basePtr = NULL; llvm::Value *basePtr = NULL;
if (dynamic_cast<const ArrayType *>(type) || if (dynamic_cast<const ArrayType *>(arrayOrVectorType) ||
dynamic_cast<const VectorType *>(type)) dynamic_cast<const VectorType *>(arrayOrVectorType))
basePtr = arrayOrVector->GetLValue(ctx); basePtr = arrayOrVector->GetLValue(ctx);
else { else {
type = type->GetReferenceTarget(); arrayOrVectorType = arrayOrVectorType->GetReferenceTarget();
assert(dynamic_cast<const ArrayType *>(type) || assert(dynamic_cast<const ArrayType *>(arrayOrVectorType) ||
dynamic_cast<const VectorType *>(type)); dynamic_cast<const VectorType *>(arrayOrVectorType));
basePtr = arrayOrVector->GetValue(ctx); basePtr = arrayOrVector->GetValue(ctx);
} }
if (!basePtr) if (!basePtr)
@@ -2614,7 +2689,8 @@ IndexExpr::GetLValue(FunctionEmitContext *ctx) const {
// If the array index is a compile time constant, check to see if it // If the array index is a compile time constant, check to see if it
// may lead to an out-of-bounds access. // may lead to an out-of-bounds access.
ConstExpr *ce = dynamic_cast<ConstExpr *>(index); ConstExpr *ce = dynamic_cast<ConstExpr *>(index);
const SequentialType *seqType = dynamic_cast<const SequentialType *>(type); const SequentialType *seqType =
dynamic_cast<const SequentialType *>(arrayOrVectorType);
assert(seqType != NULL); assert(seqType != NULL);
int nElements = seqType->GetElementCount(); int nElements = seqType->GetElementCount();
if (ce != NULL && nElements > 0) { if (ce != NULL && nElements > 0) {
@@ -2630,7 +2706,11 @@ IndexExpr::GetLValue(FunctionEmitContext *ctx) const {
basePtr = lCastUniformVectorBasePtr(basePtr, ctx); basePtr = lCastUniformVectorBasePtr(basePtr, ctx);
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
return ctx->GetElementPtrInst(basePtr, LLVMInt32(0), index->GetValue(ctx)); llvm::Value *ptr = ctx->GetElementPtrInst(basePtr, LLVMInt32(0),
index->GetValue(ctx));
ptr = lAddVaryingOffsetsIfNeeded(ctx, ptr, GetType(), arrayOrVectorType);
return ptr;
} }
@@ -2731,27 +2811,32 @@ lIdentifierToVectorElement(char id) {
} }
} }
//////////////////////////////////////////////////
// StructMemberExpr
class StructMemberExpr : public MemberExpr class StructMemberExpr : public MemberExpr
{ {
public: public:
StructMemberExpr(Expr *e, const char *id, SourcePos p, StructMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, const StructType* structType); SourcePos idpos, const StructType *structType);
const Type* GetType() const;
const Type *GetType() const;
int getElementNumber() const; int getElementNumber() const;
const Type *getElementType() const;
private: private:
const StructType* exprStructType; const StructType *exprStructType;
}; };
StructMemberExpr::StructMemberExpr(Expr *e, const char *id, SourcePos p, StructMemberExpr::StructMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, SourcePos idpos,
const StructType* structType) const StructType *structType)
: MemberExpr(e, id, p, idpos), exprStructType(structType) { : MemberExpr(e, id, p, idpos), exprStructType(structType) {
} }
const Type*
const Type *
StructMemberExpr::GetType() const { StructMemberExpr::GetType() const {
// It's a struct, and the result type is the element // It's a struct, and the result type is the element
// type, possibly promoted to varying if the struct type / lvalue // type, possibly promoted to varying if the struct type / lvalue
@@ -2780,26 +2865,35 @@ StructMemberExpr::getElementNumber() const {
return elementNumber; return elementNumber;
} }
const Type *
StructMemberExpr::getElementType() const {
return exprStructType->GetAsUniformType()->GetElementType(identifier);
}
//////////////////////////////////////////////////
// VectorMemberExpr
class VectorMemberExpr : public MemberExpr class VectorMemberExpr : public MemberExpr
{ {
public: public:
VectorMemberExpr(Expr *e, const char *id, SourcePos p, VectorMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, const VectorType* vectorType); SourcePos idpos, const VectorType* vectorType);
~VectorMemberExpr(); const Type *GetType() const;
llvm::Value *GetLValue(FunctionEmitContext* ctx) const;
const Type* GetType() const; llvm::Value *GetValue(FunctionEmitContext* ctx) const;
llvm::Value* GetLValue(FunctionEmitContext* ctx) const;
llvm::Value* GetValue(FunctionEmitContext* ctx) const;
int getElementNumber() const; int getElementNumber() const;
const Type *getElementType() const;
private: private:
const VectorType* exprVectorType; const VectorType *exprVectorType;
const VectorType* memberType; const VectorType *memberType;
}; };
VectorMemberExpr::VectorMemberExpr(Expr *e, const char *id, SourcePos p, VectorMemberExpr::VectorMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, SourcePos idpos,
const VectorType* vectorType) const VectorType* vectorType)
@@ -2808,11 +2902,8 @@ VectorMemberExpr::VectorMemberExpr(Expr *e, const char *id, SourcePos p,
identifier.length()); identifier.length());
} }
VectorMemberExpr::~VectorMemberExpr() {
delete memberType;
}
const Type* const Type *
VectorMemberExpr::GetType() const { VectorMemberExpr::GetType() const {
// For 1-element expressions, we have the base vector element // For 1-element expressions, we have the base vector element
// type. For n-element expressions, we have a shortvec type // type. For n-element expressions, we have a shortvec type
@@ -2826,7 +2917,7 @@ VectorMemberExpr::GetType() const {
} }
llvm::Value* llvm::Value *
VectorMemberExpr::GetLValue(FunctionEmitContext* ctx) const { VectorMemberExpr::GetLValue(FunctionEmitContext* ctx) const {
if (identifier.length() == 1) { if (identifier.length() == 1) {
return MemberExpr::GetLValue(ctx); return MemberExpr::GetLValue(ctx);
@@ -2836,11 +2927,12 @@ VectorMemberExpr::GetLValue(FunctionEmitContext* ctx) const {
} }
llvm::Value* llvm::Value *
VectorMemberExpr::GetValue(FunctionEmitContext* ctx) const { VectorMemberExpr::GetValue(FunctionEmitContext* ctx) const {
if (identifier.length() == 1) { if (identifier.length() == 1) {
return MemberExpr::GetValue(ctx); return MemberExpr::GetValue(ctx);
} else { }
else {
std::vector<int> indices; std::vector<int> indices;
for (size_t i = 0; i < identifier.size(); ++i) { for (size_t i = 0; i < identifier.size(); ++i) {
@@ -2866,8 +2958,7 @@ VectorMemberExpr::GetValue(FunctionEmitContext* ctx) const {
llvm::Value *ptmp = llvm::Value *ptmp =
ctx->GetElementPtrInst(ltmp, 0, i, "new_offset"); ctx->GetElementPtrInst(ltmp, 0, i, "new_offset");
llvm::Value *initLValue = llvm::Value *initLValue =
ctx->GetElementPtrInst(basePtr , 0, ctx->GetElementPtrInst(basePtr, 0, indices[i], "orig_offset");
indices[i], "orig_offset");
llvm::Value *initValue = llvm::Value *initValue =
ctx->LoadInst(initLValue, NULL, memberType->GetElementType(), ctx->LoadInst(initLValue, NULL, memberType->GetElementType(),
"vec_element"); "vec_element");
@@ -2878,6 +2969,7 @@ VectorMemberExpr::GetValue(FunctionEmitContext* ctx) const {
} }
} }
int int
VectorMemberExpr::getElementNumber() const { VectorMemberExpr::getElementNumber() const {
int elementNumber = lIdentifierToVectorElement(identifier[0]); int elementNumber = lIdentifierToVectorElement(identifier[0]);
@@ -2887,43 +2979,51 @@ VectorMemberExpr::getElementNumber() const {
return elementNumber; return elementNumber;
} }
const Type *
VectorMemberExpr::getElementType() const {
return memberType;
}
///////////////////////////////////////////////////////////////////////////
// ReferenceMemberExpr
class ReferenceMemberExpr : public MemberExpr class ReferenceMemberExpr : public MemberExpr
{ {
public: public:
ReferenceMemberExpr(Expr *e, const char *id, SourcePos p, ReferenceMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, const ReferenceType* referenceType); SourcePos idpos, const ReferenceType* referenceType);
const Type* GetType() const; const Type *GetType() const;
llvm::Value *GetLValue(FunctionEmitContext* ctx) const;
int getElementNumber() const; int getElementNumber() const;
const Type *getElementType() const;
llvm::Value* GetLValue(FunctionEmitContext* ctx) const;
private: private:
const ReferenceType* exprReferenceType; const ReferenceType *exprReferenceType;
MemberExpr* dereferencedExpr; MemberExpr *dereferencedExpr;
}; };
ReferenceMemberExpr::ReferenceMemberExpr(Expr *e, const char *id, SourcePos p, ReferenceMemberExpr::ReferenceMemberExpr(Expr *e, const char *id, SourcePos p,
SourcePos idpos, SourcePos idpos,
const ReferenceType* referenceType) const ReferenceType *referenceType)
: MemberExpr(e, id, p, idpos), exprReferenceType(referenceType) { : MemberExpr(e, id, p, idpos), exprReferenceType(referenceType) {
const Type* refTarget = exprReferenceType->GetReferenceTarget(); const Type *refTarget = exprReferenceType->GetReferenceTarget();
const StructType* structType const StructType *structType = dynamic_cast<const StructType *>(refTarget);
= dynamic_cast<const StructType *>(refTarget); const VectorType *vectorType = dynamic_cast<const VectorType *>(refTarget);
const VectorType* vectorType
= dynamic_cast<const VectorType *>(refTarget);
if (structType != NULL) { if (structType != NULL)
dereferencedExpr = new StructMemberExpr(e, id, p, idpos, structType); dereferencedExpr = new StructMemberExpr(e, id, p, idpos, structType);
} else if (vectorType != NULL) { else if (vectorType != NULL)
dereferencedExpr = new VectorMemberExpr(e, id, p, idpos, vectorType); dereferencedExpr = new VectorMemberExpr(e, id, p, idpos, vectorType);
} else { else
dereferencedExpr = NULL; dereferencedExpr = NULL;
}
} }
const Type*
const Type *
ReferenceMemberExpr::GetType() const { ReferenceMemberExpr::GetType() const {
if (dereferencedExpr == NULL) { if (dereferencedExpr == NULL) {
Error(pos, "Can't access member of non-struct/vector type \"%s\".", Error(pos, "Can't access member of non-struct/vector type \"%s\".",
@@ -2934,6 +3034,7 @@ ReferenceMemberExpr::GetType() const {
} }
} }
int int
ReferenceMemberExpr::getElementNumber() const { ReferenceMemberExpr::getElementNumber() const {
if (dereferencedExpr == NULL) { if (dereferencedExpr == NULL) {
@@ -2945,7 +3046,15 @@ ReferenceMemberExpr::getElementNumber() const {
} }
} }
llvm::Value*
const Type *
ReferenceMemberExpr::getElementType() const {
assert(dereferencedExpr != NULL);
return dereferencedExpr->getElementType();
}
llvm::Value *
ReferenceMemberExpr::GetLValue(FunctionEmitContext* ctx) const { ReferenceMemberExpr::GetLValue(FunctionEmitContext* ctx) const {
if (dereferencedExpr == NULL) { if (dereferencedExpr == NULL) {
// FIXME: again I think typechecking should have caught this // FIXME: again I think typechecking should have caught this
@@ -2965,29 +3074,35 @@ ReferenceMemberExpr::GetLValue(FunctionEmitContext* ctx) const {
return NULL; return NULL;
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
return ctx->GetElementPtrInst(basePtr, 0, elementNumber); llvm::Value *ptr = ctx->GetElementPtrInst(basePtr, 0, elementNumber);
const Type *elementType = getElementType();
ptr = lAddVaryingOffsetsIfNeeded(ctx, ptr, GetType(), elementType);
return ptr;
} }
MemberExpr* MemberExpr *
MemberExpr::create(Expr *e, const char *id, SourcePos p, SourcePos idpos) { MemberExpr::create(Expr *e, const char *id, SourcePos p, SourcePos idpos) {
const Type* exprType; const Type *exprType;
if (e == NULL || (exprType = e->GetType()) == NULL) if (e == NULL || (exprType = e->GetType()) == NULL)
return new MemberExpr(e, id, p, idpos); return NULL;
const StructType* structType = dynamic_cast<const StructType*>(exprType); const StructType *structType = dynamic_cast<const StructType*>(exprType);
if (structType != NULL) if (structType != NULL)
return new StructMemberExpr(e, id, p, idpos, structType); return new StructMemberExpr(e, id, p, idpos, structType);
const VectorType* vectorType = dynamic_cast<const VectorType*>(exprType); const VectorType *vectorType = dynamic_cast<const VectorType*>(exprType);
if (vectorType != NULL) if (vectorType != NULL)
return new VectorMemberExpr(e, id, p, idpos, vectorType); return new VectorMemberExpr(e, id, p, idpos, vectorType);
const ReferenceType* referenceType = dynamic_cast<const ReferenceType*>(exprType); const ReferenceType *referenceType = dynamic_cast<const ReferenceType*>(exprType);
if (referenceType != NULL) if (referenceType != NULL)
return new ReferenceMemberExpr(e, id, p, idpos, referenceType); return new ReferenceMemberExpr(e, id, p, idpos, referenceType);
return new MemberExpr(e, id, p, idpos); FATAL("Unexpected case in MemberExpr::create()");
return NULL;
} }
@@ -3024,6 +3139,8 @@ MemberExpr::GetValue(FunctionEmitContext *ctx) const {
if (elementNumber == -1) if (elementNumber == -1)
return NULL; return NULL;
lvalue = ctx->GetElementPtrInst(ptr, 0, elementNumber); lvalue = ctx->GetElementPtrInst(ptr, 0, elementNumber);
lvalue = lAddVaryingOffsetsIfNeeded(ctx, lvalue, GetType(), getElementType());
mask = LLVMMaskAllOn; mask = LLVMMaskAllOn;
} }
else { else {
@@ -3074,7 +3191,10 @@ MemberExpr::GetLValue(FunctionEmitContext *ctx) const {
return NULL; return NULL;
ctx->SetDebugPos(pos); ctx->SetDebugPos(pos);
return ctx->GetElementPtrInst(basePtr, 0, elementNumber); llvm::Value *ptr = ctx->GetElementPtrInst(basePtr, 0, elementNumber);
ptr = lAddVaryingOffsetsIfNeeded(ctx, ptr, GetType(), getElementType());
return ptr;
} }

4
expr.h
View File

@@ -303,8 +303,8 @@ public:
Expr *TypeCheck(); Expr *TypeCheck();
int EstimateCost() const; int EstimateCost() const;
virtual int getElementNumber() const; virtual int getElementNumber() const = 0;
virtual const Type *getElementType() const = 0;
std::string getCandidateNearMatches() const; std::string getCandidateNearMatches() const;
Expr *expr; Expr *expr;

72
opt.cpp
View File

@@ -899,7 +899,7 @@ lGetTypeSize(LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *insertBefore)
static llvm::Value * static llvm::Value *
lTraverseConstantExpr(llvm::Constant *value, llvm::Value **offsetPtr, lTraverseConstantExpr(llvm::Constant *value, llvm::Value **offsetPtr,
LLVM_TYPE_CONST llvm::Type **scaleType, LLVM_TYPE_CONST llvm::Type **scaleType,
bool *leafIsVarying, llvm::Instruction *insertBefore) { llvm::Instruction *insertBefore) {
llvm::GlobalVariable *gv = NULL; llvm::GlobalVariable *gv = NULL;
llvm::ConstantExpr *ce = llvm::dyn_cast<llvm::ConstantExpr>(value); llvm::ConstantExpr *ce = llvm::dyn_cast<llvm::ConstantExpr>(value);
if (ce != NULL) { if (ce != NULL) {
@@ -907,7 +907,7 @@ lTraverseConstantExpr(llvm::Constant *value, llvm::Value **offsetPtr,
case llvm::Instruction::BitCast: case llvm::Instruction::BitCast:
*offsetPtr = LLVMInt32(0); *offsetPtr = LLVMInt32(0);
return lTraverseConstantExpr(ce->getOperand(0), offsetPtr, return lTraverseConstantExpr(ce->getOperand(0), offsetPtr,
scaleType, leafIsVarying, insertBefore); scaleType, insertBefore);
case llvm::Instruction::GetElementPtr: { case llvm::Instruction::GetElementPtr: {
gv = llvm::dyn_cast<llvm::GlobalVariable>(ce->getOperand(0)); gv = llvm::dyn_cast<llvm::GlobalVariable>(ce->getOperand(0));
assert(gv != NULL); assert(gv != NULL);
@@ -943,30 +943,13 @@ lTraverseConstantExpr(llvm::Constant *value, llvm::Value **offsetPtr,
if (gv == NULL) if (gv == NULL)
gv = llvm::dyn_cast<llvm::GlobalVariable>(value); gv = llvm::dyn_cast<llvm::GlobalVariable>(value);
if (gv != NULL) { return gv;
// FIXME: is this broken for arrays of varying???!? (I think so).
// IF so, then why does the other copy if it work. (Or is that
// broken, too?!?!?)
if (leafIsVarying != NULL) {
LLVM_TYPE_CONST llvm::Type *pt = value->getType();
LLVM_TYPE_CONST llvm::PointerType *ptrType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(pt);
assert(ptrType);
LLVM_TYPE_CONST llvm::Type *eltType = ptrType->getElementType();
*leafIsVarying = llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(eltType);
//printf("decided that leaf %s varying!\n", *leafIsVarying ? "is" : "is not");
}
return gv;
}
return NULL;
} }
static llvm::Value * static llvm::Value *
lGetOffsetForLane(int lane, llvm::Value *value, llvm::Value **offset, lGetOffsetForLane(int lane, llvm::Value *value, llvm::Value **offset,
LLVM_TYPE_CONST llvm::Type **scaleType, bool *leafIsVarying, LLVM_TYPE_CONST llvm::Type **scaleType,
llvm::Instruction *insertBefore) { llvm::Instruction *insertBefore) {
if (!llvm::isa<llvm::GetElementPtrInst>(value)) { if (!llvm::isa<llvm::GetElementPtrInst>(value)) {
assert(llvm::isa<llvm::BitCastInst>(value)); assert(llvm::isa<llvm::BitCastInst>(value));
@@ -986,15 +969,6 @@ lGetOffsetForLane(int lane, llvm::Value *value, llvm::Value **offset,
value = iv->getOperand(1); value = iv->getOperand(1);
} }
if (leafIsVarying != NULL) {
LLVM_TYPE_CONST llvm::Type *pt = value->getType();
LLVM_TYPE_CONST llvm::PointerType *ptrType =
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(pt);
assert(ptrType);
LLVM_TYPE_CONST llvm::Type *eltType = ptrType->getElementType();
*leafIsVarying = llvm::isa<LLVM_TYPE_CONST llvm::VectorType>(eltType);
}
llvm::GetElementPtrInst *gep = llvm::dyn_cast<llvm::GetElementPtrInst>(value); llvm::GetElementPtrInst *gep = llvm::dyn_cast<llvm::GetElementPtrInst>(value);
assert(gep); assert(gep);
@@ -1041,18 +1015,13 @@ lGetOffsetForLane(int lane, llvm::Value *value, llvm::Value **offset,
deconstructs the LLVM array, storing the offset from the base pointer deconstructs the LLVM array, storing the offset from the base pointer
as an llvm::Value for the i'th element into the i'th element of the as an llvm::Value for the i'th element into the i'th element of the
offsets[] array passed in to the function. It returns a scale factor offsets[] array passed in to the function. It returns a scale factor
for the offsets via *scaleType, and sets *leafIsVarying to true if the for the offsets via *scaleType. The return value is either the base
leaf data type being indexed into is a 'varying' ispc type. The pointer or the an array of pointers for the next dimension of indexing
return value is either the base pointer or the an array of pointers for (that we'll in turn deconstruct with this function).
the next dimension of indexing (that we'll in turn deconstruct with
this function).
@todo All of the additional indexing magic for varying stuff should
happen in the front end.
*/ */
static llvm::Value * static llvm::Value *
lTraverseInsertChain(llvm::Value *ptrs, llvm::Value *offsets[ISPC_MAX_NVEC], lTraverseInsertChain(llvm::Value *ptrs, llvm::Value *offsets[ISPC_MAX_NVEC],
LLVM_TYPE_CONST llvm::Type **scaleType, bool *leafIsVarying, LLVM_TYPE_CONST llvm::Type **scaleType,
llvm::Instruction *insertBefore) { llvm::Instruction *insertBefore) {
// The pointer values may be an array of constant pointers (this // The pointer values may be an array of constant pointers (this
// happens, for example, when indexing into global arrays.) In that // happens, for example, when indexing into global arrays.) In that
@@ -1064,8 +1033,7 @@ lTraverseInsertChain(llvm::Value *ptrs, llvm::Value *offsets[ISPC_MAX_NVEC],
llvm::Value *base = NULL; llvm::Value *base = NULL;
for (int i = 0; i < g->target.vectorWidth; ++i) { for (int i = 0; i < g->target.vectorWidth; ++i) {
llvm::Value *b = lTraverseConstantExpr(ca->getOperand(i), &offsets[i], llvm::Value *b = lTraverseConstantExpr(ca->getOperand(i), &offsets[i],
scaleType, leafIsVarying, scaleType, insertBefore);
insertBefore);
if (i == 0) if (i == 0)
base = b; base = b;
else else
@@ -1102,7 +1070,7 @@ lTraverseInsertChain(llvm::Value *ptrs, llvm::Value *offsets[ISPC_MAX_NVEC],
// array being indexed into. // array being indexed into.
llvm::Value *myNext = lGetOffsetForLane(elementIndex, ivInst->getOperand(1), llvm::Value *myNext = lGetOffsetForLane(elementIndex, ivInst->getOperand(1),
&offsets[elementIndex], scaleType, &offsets[elementIndex], scaleType,
leafIsVarying, insertBefore); insertBefore);
if (nextChain == NULL) if (nextChain == NULL)
nextChain = myNext; nextChain = myNext;
else else
@@ -1144,7 +1112,6 @@ static llvm::Value *
lGetPtrAndOffsets(llvm::Value *ptrs, llvm::Value **basePtr, lGetPtrAndOffsets(llvm::Value *ptrs, llvm::Value **basePtr,
llvm::Instruction *insertBefore, int eltSize) { llvm::Instruction *insertBefore, int eltSize) {
llvm::Value *offset = LLVMInt32Vector(0); llvm::Value *offset = LLVMInt32Vector(0);
bool firstLoop = true, leafIsVarying;
while (ptrs != NULL) { while (ptrs != NULL) {
llvm::Value *offsets[ISPC_MAX_NVEC]; llvm::Value *offsets[ISPC_MAX_NVEC];
@@ -1153,8 +1120,7 @@ lGetPtrAndOffsets(llvm::Value *ptrs, llvm::Value **basePtr,
LLVM_TYPE_CONST llvm::Type *scaleType = NULL; LLVM_TYPE_CONST llvm::Type *scaleType = NULL;
llvm::Value *nextChain = llvm::Value *nextChain =
lTraverseInsertChain(ptrs, offsets, &scaleType, lTraverseInsertChain(ptrs, offsets, &scaleType, insertBefore);
firstLoop ? &leafIsVarying : NULL, insertBefore);
for (int i = 0; i < g->target.vectorWidth; ++i) for (int i = 0; i < g->target.vectorWidth; ++i)
assert(offsets[i] != NULL); assert(offsets[i] != NULL);
@@ -1185,22 +1151,6 @@ lGetPtrAndOffsets(llvm::Value *ptrs, llvm::Value **basePtr,
*basePtr = nextChain; *basePtr = nextChain;
break; break;
} }
firstLoop = false;
}
// handle varying stuff...
if (leafIsVarying) {
llvm::Value *deltaVector = llvm::UndefValue::get(LLVMTypes::Int32VectorType);
for (int i = 0; i < g->target.vectorWidth; ++i) {
deltaVector =
llvm::InsertElementInst::Create(deltaVector, LLVMInt32(eltSize*i),
LLVMInt32(i), "delta", insertBefore);
lCopyMetadata(deltaVector, insertBefore);
}
offset = llvm::BinaryOperator::Create(llvm::Instruction::Add, offset,
deltaVector, "offset_varying_delta",
insertBefore);
lCopyMetadata(offset, insertBefore);
} }
return offset; return offset;

View File

@@ -6,15 +6,17 @@ struct Foo {
float x; float x;
float f; float f;
}; };
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) { export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
float a = aFOO[programIndex]; float a = aFOO[programIndex];
uniform Foo myFoo[3] = { { a, a }, {a, a}, {a, a} }; uniform Foo myFoo[3] = { { -1, -2 }, {a, -3}, {-4, -5} };
int i = 1; int i = aFOO[0];
varying Foo barFoo = myFoo[i]; varying Foo barFoo = myFoo[i];
//CO print("% %\n", myFoo[i].x, barFoo.x);
RET[programIndex] = barFoo.x; RET[programIndex] = barFoo.x;
} }
export void result(uniform float RET[4]) { export void result(uniform float RET[]) {
RET[programIndex] = 1+programIndex; RET[programIndex] = 1+programIndex;
} }

View File

@@ -12,12 +12,12 @@ export void f_fi(uniform float RET[], uniform float a[], uniform int bFOO[]) {
uniform int i; uniform int i;
for (i = 0; i < 17; ++i) { for (i = 0; i < 17; ++i) {
myFoo[i].x = i; myFoo[i].x = i;
myFoo[i].f = 2*i; myFoo[i].f = 17+2*i;
} }
RET[programIndex] = myFoo[b/2].f; RET[programIndex] = myFoo[b/2].f;
} }
export void result(uniform float RET[]) { export void result(uniform float RET[]) {
RET[programIndex] = 2 + 2 * programIndex; RET[programIndex] = 19 + 2 * programIndex;
} }