Skip to content

Commit

Permalink
[InstCombine] Remove GEP of bitcast folds (NFC)
Browse files Browse the repository at this point in the history
These only support typed pointers, and as such are no longer
relevant.
  • Loading branch information
nikic committed Apr 6, 2023
1 parent 616c806 commit db6b30b
Showing 1 changed file with 0 additions and 169 deletions.
169 changes: 0 additions & 169 deletions llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2327,175 +2327,6 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
if (GEPType->isVectorTy())
return nullptr;

// Handle gep(bitcast x) and gep(gep x, 0, 0, 0).
Value *StrippedPtr = PtrOp->stripPointerCasts();
PointerType *StrippedPtrTy = cast<PointerType>(StrippedPtr->getType());

// TODO: The basic approach of these folds is not compatible with opaque
// pointers, because we can't use bitcasts as a hint for a desirable GEP
// type. Instead, we should perform canonicalization directly on the GEP
// type. For now, skip these.
if (StrippedPtr != PtrOp && !StrippedPtrTy->isOpaque()) {
bool HasZeroPointerIndex = false;
Type *StrippedPtrEltTy = StrippedPtrTy->getNonOpaquePointerElementType();

if (auto *C = dyn_cast<ConstantInt>(GEP.getOperand(1)))
HasZeroPointerIndex = C->isZero();

// Transform: GEP (bitcast [10 x i8]* X to [0 x i8]*), i32 0, ...
// into : GEP [10 x i8]* X, i32 0, ...
//
// Likewise, transform: GEP (bitcast i8* X to [0 x i8]*), i32 0, ...
// into : GEP i8* X, ...
//
// This occurs when the program declares an array extern like "int X[];"
if (HasZeroPointerIndex) {
if (auto *CATy = dyn_cast<ArrayType>(GEPEltType)) {
// GEP (bitcast i8* X to [0 x i8]*), i32 0, ... ?
if (CATy->getElementType() == StrippedPtrEltTy) {
// -> GEP i8* X, ...
SmallVector<Value *, 8> Idx(drop_begin(GEP.indices()));
GetElementPtrInst *Res = GetElementPtrInst::Create(
StrippedPtrEltTy, StrippedPtr, Idx, GEP.getName());
Res->setIsInBounds(GEP.isInBounds());
if (StrippedPtrTy->getAddressSpace() == GEP.getAddressSpace())
return Res;
// Insert Res, and create an addrspacecast.
// e.g.,
// GEP (addrspacecast i8 addrspace(1)* X to [0 x i8]*), i32 0, ...
// ->
// %0 = GEP i8 addrspace(1)* X, ...
// addrspacecast i8 addrspace(1)* %0 to i8*
return new AddrSpaceCastInst(Builder.Insert(Res), GEPType);
}

if (auto *XATy = dyn_cast<ArrayType>(StrippedPtrEltTy)) {
// GEP (bitcast [10 x i8]* X to [0 x i8]*), i32 0, ... ?
if (CATy->getElementType() == XATy->getElementType()) {
// -> GEP [10 x i8]* X, i32 0, ...
// At this point, we know that the cast source type is a pointer
// to an array of the same type as the destination pointer
// array. Because the array type is never stepped over (there
// is a leading zero) we can fold the cast into this GEP.
if (StrippedPtrTy->getAddressSpace() == GEP.getAddressSpace()) {
GEP.setSourceElementType(XATy);
return replaceOperand(GEP, 0, StrippedPtr);
}
// Cannot replace the base pointer directly because StrippedPtr's
// address space is different. Instead, create a new GEP followed by
// an addrspacecast.
// e.g.,
// GEP (addrspacecast [10 x i8] addrspace(1)* X to [0 x i8]*),
// i32 0, ...
// ->
// %0 = GEP [10 x i8] addrspace(1)* X, ...
// addrspacecast i8 addrspace(1)* %0 to i8*
SmallVector<Value *, 8> Idx(GEP.indices());
Value *NewGEP =
Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, Idx,
GEP.getName(), GEP.isInBounds());
return new AddrSpaceCastInst(NewGEP, GEPType);
}
}
}
} else if (GEP.getNumOperands() == 2 && !IsGEPSrcEleScalable) {
// Skip if GEP source element type is scalable. The type alloc size is
// unknown at compile-time.
// Transform things like: %t = getelementptr i32*
// bitcast ([2 x i32]* %str to i32*), i32 %V into: %t1 = getelementptr [2
// x i32]* %str, i32 0, i32 %V; bitcast
if (StrippedPtrEltTy->isArrayTy() &&
DL.getTypeAllocSize(StrippedPtrEltTy->getArrayElementType()) ==
DL.getTypeAllocSize(GEPEltType)) {
Type *IdxType = DL.getIndexType(GEPType);
Value *Idx[2] = {Constant::getNullValue(IdxType), GEP.getOperand(1)};
Value *NewGEP = Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, Idx,
GEP.getName(), GEP.isInBounds());

// V and GEP are both pointer types --> BitCast
return CastInst::CreatePointerBitCastOrAddrSpaceCast(NewGEP, GEPType);
}

// Transform things like:
// %V = mul i64 %N, 4
// %t = getelementptr i8* bitcast (i32* %arr to i8*), i32 %V
// into: %t1 = getelementptr i32* %arr, i32 %N; bitcast
if (GEPEltType->isSized() && StrippedPtrEltTy->isSized()) {
// Check that changing the type amounts to dividing the index by a scale
// factor.
uint64_t ResSize = DL.getTypeAllocSize(GEPEltType).getFixedValue();
uint64_t SrcSize =
DL.getTypeAllocSize(StrippedPtrEltTy).getFixedValue();
if (ResSize && SrcSize % ResSize == 0) {
Value *Idx = GEP.getOperand(1);
unsigned BitWidth = Idx->getType()->getPrimitiveSizeInBits();
uint64_t Scale = SrcSize / ResSize;

// Earlier transforms ensure that the index has the right type
// according to Data Layout, which considerably simplifies the
// logic by eliminating implicit casts.
assert(Idx->getType() == DL.getIndexType(GEPType) &&
"Index type does not match the Data Layout preferences");

bool NSW;
if (Value *NewIdx = Descale(Idx, APInt(BitWidth, Scale), NSW)) {
// Successfully decomposed Idx as NewIdx * Scale, form a new GEP.
// If the multiplication NewIdx * Scale may overflow then the new
// GEP may not be "inbounds".
Value *NewGEP =
Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, NewIdx,
GEP.getName(), GEP.isInBounds() && NSW);

// The NewGEP must be pointer typed, so must the old one -> BitCast
return CastInst::CreatePointerBitCastOrAddrSpaceCast(NewGEP,
GEPType);
}
}
}

// Similarly, transform things like:
// getelementptr i8* bitcast ([100 x double]* X to i8*), i32 %tmp
// (where tmp = 8*tmp2) into:
// getelementptr [100 x double]* %arr, i32 0, i32 %tmp2; bitcast
if (GEPEltType->isSized() && StrippedPtrEltTy->isSized() &&
StrippedPtrEltTy->isArrayTy()) {
// Check that changing to the array element type amounts to dividing the
// index by a scale factor.
uint64_t ResSize = DL.getTypeAllocSize(GEPEltType).getFixedValue();
uint64_t ArrayEltSize =
DL.getTypeAllocSize(StrippedPtrEltTy->getArrayElementType())
.getFixedValue();
if (ResSize && ArrayEltSize % ResSize == 0) {
Value *Idx = GEP.getOperand(1);
unsigned BitWidth = Idx->getType()->getPrimitiveSizeInBits();
uint64_t Scale = ArrayEltSize / ResSize;

// Earlier transforms ensure that the index has the right type
// according to the Data Layout, which considerably simplifies
// the logic by eliminating implicit casts.
assert(Idx->getType() == DL.getIndexType(GEPType) &&
"Index type does not match the Data Layout preferences");

bool NSW;
if (Value *NewIdx = Descale(Idx, APInt(BitWidth, Scale), NSW)) {
// Successfully decomposed Idx as NewIdx * Scale, form a new GEP.
// If the multiplication NewIdx * Scale may overflow then the new
// GEP may not be "inbounds".
Type *IndTy = DL.getIndexType(GEPType);
Value *Off[2] = {Constant::getNullValue(IndTy), NewIdx};

Value *NewGEP =
Builder.CreateGEP(StrippedPtrEltTy, StrippedPtr, Off,
GEP.getName(), GEP.isInBounds() && NSW);
// The NewGEP must be pointer typed, so must the old one -> BitCast
return CastInst::CreatePointerBitCastOrAddrSpaceCast(NewGEP,
GEPType);
}
}
}
}
}

if (!GEP.isInBounds()) {
unsigned IdxWidth =
DL.getIndexSizeInBits(PtrOp->getType()->getPointerAddressSpace());
Expand Down

0 comments on commit db6b30b

Please sign in to comment.