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:
Matt Pharr
2011-10-14 11:20:08 -07:00
parent 2460fa5c83
commit 9f2aa8d92a
5 changed files with 163 additions and 15 deletions

88
opt.cpp
View File

@@ -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
View 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
View 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
View 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
View 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;
}