Handle ConstantExpressions when computing address+offset vectors for scatter/gather.
In particular, this fixes issue #81, where a global variable access was leading to ConstantExpressions showing up in this code, which it wasn't previously expecting.
This commit is contained in:
88
opt.cpp
88
opt.cpp
@@ -888,6 +888,74 @@ lGetTypeSize(LLVM_TYPE_CONST llvm::Type *type, llvm::Instruction *insertBefore)
|
||||
}
|
||||
|
||||
|
||||
static llvm::Value *
|
||||
lTraverseConstantExpr(llvm::Constant *value, llvm::Value **offsetPtr,
|
||||
LLVM_TYPE_CONST llvm::Type **scaleType,
|
||||
bool *leafIsVarying, llvm::Instruction *insertBefore) {
|
||||
llvm::GlobalVariable *gv = NULL;
|
||||
llvm::ConstantExpr *ce = llvm::dyn_cast<llvm::ConstantExpr>(value);
|
||||
if (ce != NULL) {
|
||||
switch (ce->getOpcode()) {
|
||||
case llvm::Instruction::BitCast:
|
||||
*offsetPtr = LLVMInt32(0);
|
||||
return lTraverseConstantExpr(ce->getOperand(0), offsetPtr,
|
||||
scaleType, leafIsVarying, insertBefore);
|
||||
case llvm::Instruction::GetElementPtr: {
|
||||
gv = llvm::dyn_cast<llvm::GlobalVariable>(ce->getOperand(0));
|
||||
assert(gv != NULL);
|
||||
|
||||
assert(lGetIntValue(ce->getOperand(1)) == 0);
|
||||
LLVM_TYPE_CONST llvm::PointerType *targetPtrType =
|
||||
llvm::dyn_cast<LLVM_TYPE_CONST llvm::PointerType>(ce->getOperand(0)->getType());
|
||||
assert(targetPtrType);
|
||||
LLVM_TYPE_CONST llvm::Type *targetType = targetPtrType->getElementType();
|
||||
|
||||
if (llvm::isa<const llvm::StructType>(targetType)) {
|
||||
*offsetPtr = lStructOffset(targetType, lGetIntValue(ce->getOperand(2)),
|
||||
insertBefore);
|
||||
*offsetPtr = new llvm::TruncInst(*offsetPtr, LLVMTypes::Int32Type, "member32",
|
||||
insertBefore);
|
||||
//CO lCopyMetadata(*offset, insertBefore);
|
||||
*scaleType = LLVMTypes::Int8Type; // aka char aka sizeof(1)
|
||||
}
|
||||
else {
|
||||
*offsetPtr = ce->getOperand(2);
|
||||
assert(*scaleType == NULL || *scaleType == targetType);
|
||||
*scaleType = targetType;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FATAL("Unexpected opcode in constant expression!");
|
||||
//printf("other op %s\n", ce->getOpcodeName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gv == NULL)
|
||||
gv = llvm::dyn_cast<llvm::GlobalVariable>(value);
|
||||
|
||||
if (gv != NULL) {
|
||||
// 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 *
|
||||
lGetOffsetForLane(int lane, llvm::Value *value, llvm::Value **offset,
|
||||
LLVM_TYPE_CONST llvm::Type **scaleType, bool *leafIsVarying,
|
||||
@@ -978,6 +1046,26 @@ static llvm::Value *
|
||||
lTraverseInsertChain(llvm::Value *ptrs, llvm::Value *offsets[ISPC_MAX_NVEC],
|
||||
LLVM_TYPE_CONST llvm::Type **scaleType, bool *leafIsVarying,
|
||||
llvm::Instruction *insertBefore) {
|
||||
// The pointer values may be an array of constant pointers (this
|
||||
// happens, for example, when indexing into global arrays.) In that
|
||||
// case, we have llvm::ConstantExprs to deconstruct to dig out the
|
||||
// common base pointer and the per-lane offsets.
|
||||
llvm::ConstantArray *ca = llvm::dyn_cast<llvm::ConstantArray>(ptrs);
|
||||
if (ca != NULL) {
|
||||
assert((int)ca->getNumOperands() == g->target.vectorWidth);
|
||||
llvm::Value *base = NULL;
|
||||
for (int i = 0; i < g->target.vectorWidth; ++i) {
|
||||
llvm::Value *b = lTraverseConstantExpr(ca->getOperand(i), &offsets[i],
|
||||
scaleType, leafIsVarying,
|
||||
insertBefore);
|
||||
if (i == 0)
|
||||
base = b;
|
||||
else
|
||||
assert(base == b);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
// This depends on the front-end constructing the arrays of pointers
|
||||
// via InsertValue instructions. (Which it does do in
|
||||
// FunctionEmitContext::GetElementPtrInst()).
|
||||
|
||||
15
tests/global-array-1.ispc
Normal file
15
tests/global-array-1.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
uniform float a[100];
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||
for (uniform int i = 0; i < programCount; ++i)
|
||||
a[i] = i;
|
||||
RET[programIndex] = a[programIndex+b-5];
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = programIndex;
|
||||
}
|
||||
15
tests/global-array-3.ispc
Normal file
15
tests/global-array-3.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
float a[100];
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||
for (uniform int i = 0; i < programCount; ++i)
|
||||
a[i] = i*programCount+programIndex;
|
||||
RET[programIndex] = a[b-5];
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = programIndex;
|
||||
}
|
||||
15
tests/global-array-4.ispc
Normal file
15
tests/global-array-4.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
float a[100];
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_fu(uniform float RET[], uniform float aFOO[], uniform float b) {
|
||||
for (uniform int i = 0; i < programCount; ++i)
|
||||
a[i] = i*programCount+programIndex;
|
||||
RET[programIndex] = a[programIndex+b-5];
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = (programCount+1) * programIndex;
|
||||
}
|
||||
15
tests/global-array.ispc
Normal file
15
tests/global-array.ispc
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
uniform float a[100];
|
||||
|
||||
export uniform int width() { return programCount; }
|
||||
|
||||
|
||||
export void f_f(uniform float RET[], uniform float aFOO[]) {
|
||||
for (uniform int i = 0; i < programCount; ++i)
|
||||
a[i] = i;
|
||||
RET[programIndex] = a[programIndex];
|
||||
}
|
||||
|
||||
export void result(uniform float RET[]) {
|
||||
RET[programIndex] = programIndex;
|
||||
}
|
||||
Reference in New Issue
Block a user