Constant *Ptr = Ops[0];
if (!TD || !cast<PointerType>(Ptr->getType())->getElementType()->isSized())
return 0;
-
- uint64_t BasePtr = 0;
+
+ unsigned BitWidth = TD->getTypeSizeInBits(TD->getIntPtrType(Context));
+ APInt BasePtr(BitWidth, 0);
bool BaseIsInt = true;
if (!Ptr->isNullValue()) {
// If this is a inttoptr from a constant int, we can fold this as the base,
// otherwise we can't.
if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Ptr))
if (CE->getOpcode() == Instruction::IntToPtr)
- if (ConstantInt *Base = dyn_cast<ConstantInt>(CE->getOperand(0)))
- BasePtr = Base->getZExtValue();
+ if (ConstantInt *Base = dyn_cast<ConstantInt>(CE->getOperand(0))) {
+ BasePtr = Base->getValue();
+ BasePtr.zextOrTrunc(BitWidth);
+ }
if (BasePtr == 0)
BaseIsInt = false;
if (!isa<ConstantInt>(Ops[i]))
return 0;
- uint64_t Offset = TD->getIndexedOffset(Ptr->getType(),
- (Value**)Ops+1, NumOps-1);
+ APInt Offset = APInt(BitWidth,
+ TD->getIndexedOffset(Ptr->getType(),
+ (Value**)Ops+1, NumOps-1));
// If the base value for this address is a literal integer value, fold the
// getelementptr to the resulting integer value casted to the pointer type.
if (BaseIsInt) {
- Constant *C = ConstantInt::get(TD->getIntPtrType(Context), Offset+BasePtr);
+ Constant *C = ConstantInt::get(Context, Offset+BasePtr);
return ConstantExpr::getIntToPtr(C, ResultTy);
}
// Also, this helps GlobalOpt do SROA on GlobalVariables.
const Type *Ty = Ptr->getType();
SmallVector<Constant*, 32> NewIdxs;
- for (unsigned Index = 1; Index != NumOps; ++Index) {
+ do {
if (const SequentialType *ATy = dyn_cast<SequentialType>(Ty)) {
+ // The only pointer indexing we'll do is on the first index of the GEP.
+ if (isa<PointerType>(ATy) && !NewIdxs.empty())
+ break;
// Determine which element of the array the offset points into.
- uint64_t ElemSize = TD->getTypeAllocSize(ATy->getElementType());
+ APInt ElemSize(BitWidth, TD->getTypeAllocSize(ATy->getElementType()));
if (ElemSize == 0)
return 0;
- uint64_t NewIdx = Offset / ElemSize;
+ APInt NewIdx = Offset.udiv(ElemSize);
Offset -= NewIdx * ElemSize;
NewIdxs.push_back(ConstantInt::get(TD->getIntPtrType(Context), NewIdx));
Ty = ATy->getElementType();
} else if (const StructType *STy = dyn_cast<StructType>(Ty)) {
- // Determine which field of the struct the offset points into.
+ // Determine which field of the struct the offset points into. The
+ // getZExtValue is at least as safe as the StructLayout API because we
+ // know the offset is within the struct at this point.
const StructLayout &SL = *TD->getStructLayout(STy);
- unsigned ElIdx = SL.getElementContainingOffset(Offset);
+ unsigned ElIdx = SL.getElementContainingOffset(Offset.getZExtValue());
NewIdxs.push_back(ConstantInt::get(Type::getInt32Ty(Context), ElIdx));
- Offset -= SL.getElementOffset(ElIdx);
+ Offset -= APInt(BitWidth, SL.getElementOffset(ElIdx));
Ty = STy->getTypeAtIndex(ElIdx);
} else {
- return 0;
+ // We've reached some non-indexable type.
+ break;
}
- }
+ } while (Ty != cast<PointerType>(ResultTy)->getElementType());
+
+ // If we haven't used up the entire offset by descending the static
+ // type, then the offset is pointing into the middle of an indivisible
+ // member, so we can't simplify it.
+ if (Offset != 0)
+ return 0;
// If the base is the start of a GlobalVariable and all the array indices
// remain in their static bounds, the GEP is inbounds. We can check that
// all indices are in bounds by just checking the first index only
// because we've just normalized all the indices.
- if (isa<GlobalVariable>(Ptr) && NewIdxs[0]->isNullValue())
- return ConstantExpr::getInBoundsGetElementPtr(Ptr,
- &NewIdxs[0], NewIdxs.size());
+ Constant *C = isa<GlobalVariable>(Ptr) && NewIdxs[0]->isNullValue() ?
+ ConstantExpr::getInBoundsGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size()) :
+ ConstantExpr::getGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size());
+ assert(cast<PointerType>(C->getType())->getElementType() == Ty &&
+ "Computed GetElementPtr has unexpected type!");
- // Otherwise it may not be inbounds.
- return ConstantExpr::getGetElementPtr(Ptr, &NewIdxs[0], NewIdxs.size());
+ // If we ended up indexing a member with a type that doesn't match
+ // the type of what the original indices indexed, add a cast.
+ if (Ty != cast<PointerType>(ResultTy)->getElementType())
+ C = ConstantExpr::getBitCast(C, ResultTy);
+
+ return C;
}
/// FoldBitCast - Constant fold bitcast, symbolically evaluating it with