From b48775a549d866c1cc500054a8bf0c0ebcb3dd18 Mon Sep 17 00:00:00 2001 From: Matt Pharr Date: Wed, 30 Nov 2011 12:29:49 -0800 Subject: [PATCH] Handle global arrays better in varying pointer analysis. Specifically, indexing into global arrays sometimes comes in as a big llvm::ConstantVector, so we need to handle traversing those as well when we do the corresponding checks in GatherScatterFlattenOpt so that we still detect cases where we can convert them into the base pointer + offsets form that's used in later analysis. --- opt.cpp | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/opt.cpp b/opt.cpp index fade6563..a27dbf32 100644 --- a/opt.cpp +++ b/opt.cpp @@ -854,6 +854,27 @@ lGetBasePointer(llvm::Value *v) { } +/** Given the two operands to a constant add expression, see if we have the + form "base pointer + offset", whee op0 is the base pointer and op1 is + the offset; if so return the base and the offset. */ +static llvm::Constant * +lGetConstantAddExprBaseOffset(llvm::Constant *op0, llvm::Constant *op1, + llvm::Constant **delta) { + llvm::ConstantExpr *op = llvm::dyn_cast(op0); + if (op == NULL || op->getOpcode() != llvm::Instruction::PtrToInt) + // the first operand isn't a pointer + return NULL; + + llvm::ConstantInt *opDelta = llvm::dyn_cast(op1); + if (opDelta == NULL) + // the second operand isn't an integer operand + return NULL; + + *delta = opDelta; + return op0; +} + + /** Given a varying pointer in ptrs, this function checks to see if it can be determined to be indexing from a common uniform base pointer. If so, the function returns the base pointer llvm::Value and initializes @@ -885,7 +906,67 @@ lGetBasePtrAndOffsets(llvm::Value *ptrs, llvm::Value **offsets) { return base; } } - + + llvm::ConstantVector *cv = llvm::dyn_cast(ptrs); + if (cv != NULL) { + // Indexing into global arrays can lead to this form, with + // ConstantVectors.. + llvm::SmallVector elements; + cv->getVectorElements(elements); + + llvm::Constant *delta[ISPC_MAX_NVEC]; + for (unsigned int i = 0; i < elements.size(); ++i) { + // For each element, try to decompose it into either a straight + // up base pointer, or a base pointer plus an integer value. + llvm::ConstantExpr *ce = llvm::dyn_cast(elements[i]); + if (ce == NULL) + return NULL; + + delta[i] = NULL; + llvm::Value *elementBase = NULL; // base pointer for this element + if (ce->getOpcode() == llvm::Instruction::PtrToInt) { + // If the element is just a ptr to int instruction, treat + // it as having an offset of zero + elementBase = ce; + delta[i] = g->target.is32Bit ? LLVMInt32(0) : LLVMInt64(0); + } + else if (ce->getOpcode() == llvm::Instruction::Add) { + // Try both orderings of the operands to see if we can get + // a pointer+offset out of them. + elementBase = + lGetConstantAddExprBaseOffset(ce->getOperand(0), + ce->getOperand(1), + &delta[i]); + if (elementBase == NULL) + elementBase = + lGetConstantAddExprBaseOffset(ce->getOperand(1), + ce->getOperand(0), + &delta[i]); + } + + // We weren't able to find a base pointer in the above. (We + // don't expect this to happen; if it does, it may be necessary + // to handle more cases in the decomposition above.) + if (elementBase == NULL) + return NULL; + + assert(delta[i] != NULL); + if (base == NULL) + // The first time we've found a base pointer + base = elementBase; + else if (base != elementBase) + // Different program instances have different base + // pointers, so no luck. + return NULL; + } + + assert(base != NULL); + llvm::ArrayRef deltas(&delta[0], + &delta[elements.size()]); + *offsets = llvm::ConstantVector::get(deltas); + return base; + } + return NULL; }