diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -33,6 +33,7 @@ #include "llvm/Analysis/OverflowInstAnalysis.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" @@ -689,6 +690,24 @@ return ::SimplifyAddInst(Op0, Op1, IsNSW, IsNUW, Query, RecursionLimit); } +static Type *getBiggestTypeIfDifferent(const DataLayout &DL, + ArrayRef Constants) { + assert(Constants.size() > 1 && "Expect at least two constant values!"); + bool AllEqual = true; + Type *MaxTy = Constants.front()->getType(); + TypeSize MaxTS = DL.getTypeSizeInBits(MaxTy); + for (Constant *C : Constants.drop_front()) { + Type *Ty = C->getType(); + TypeSize TS = DL.getTypeSizeInBits(Ty); + AllEqual &= Ty == MaxTy; + if (TS <= MaxTS) + continue; + MaxTy = Ty; + MaxTS = TS; + } + return AllEqual ? nullptr : MaxTy; +} + /// Compute the base pointer and cumulative constant offsets for V. /// /// This strips all constant offsets off of V, leaving it the base pointer, and @@ -699,6 +718,10 @@ /// This is very similar to GetPointerBaseWithConstantOffset except it doesn't /// follow non-inbounds geps. This allows it to remain usable for icmp ult/etc. /// folding. +/// +/// Note that this may trace through `addrspacecast` and the offset bit width +/// might not match the stripped value type. Instead, it will match the input +/// value type index size. static Constant *stripAndComputeConstantOffsets(const DataLayout &DL, Value *&V, bool AllowNonInbounds = false) { assert(V->getType()->isPtrOrPtrVectorTy()); @@ -706,12 +729,8 @@ APInt Offset = APInt::getZero(DL.getIndexTypeSizeInBits(V->getType())); V = V->stripAndAccumulateConstantOffsets(DL, Offset, AllowNonInbounds); - // As that strip may trace through `addrspacecast`, need to sext or trunc - // the offset calculated. - Type *IntIdxTy = DL.getIndexType(V->getType())->getScalarType(); - Offset = Offset.sextOrTrunc(IntIdxTy->getIntegerBitWidth()); - Constant *OffsetIntPtr = ConstantInt::get(IntIdxTy, Offset); + Constant *OffsetIntPtr = ConstantInt::get(V->getContext(), Offset); if (VectorType *VecTy = dyn_cast(V->getType())) return ConstantVector::getSplat(VecTy->getElementCount(), OffsetIntPtr); return OffsetIntPtr; @@ -723,6 +742,10 @@ Value *RHS) { Constant *LHSOffset = stripAndComputeConstantOffsets(DL, LHS); Constant *RHSOffset = stripAndComputeConstantOffsets(DL, RHS); + // Note that we do not need to adjust the offset bit widths as they match + // LHS/RHS which are expected to have equal type. + assert(LHSOffset->getType() == RHSOffset->getType() && + "Stripped offset types should match!"); // If LHS and RHS are not related via constant offsets to the same base // value, there is nothing we can do here. @@ -2590,6 +2613,16 @@ // doesn't need to guarantee pointer inequality when it says NoAlias. Constant *LHSOffset = stripAndComputeConstantOffsets(DL, LHS); Constant *RHSOffset = stripAndComputeConstantOffsets(DL, RHS); + // Since we started with stripped versions of LHS/RHS the inbounds offsets + // might not have the same bit widths. + if (Type *MaxTy = getBiggestTypeIfDifferent(DL, {LHSOffset, RHSOffset})) { + if (LHSOffset->getType() != MaxTy) + LHSOffset = ConstantExpr::getZExt(LHSOffset, MaxTy); + if (RHSOffset->getType() != MaxTy) + RHSOffset = ConstantExpr::getZExt(RHSOffset, MaxTy); + } + assert(LHSOffset->getType() == RHSOffset->getType() && + "Stripped offset types should match!"); // If LHS and RHS are related via constant offsets to the same base // value, we can replace it with an icmp which just compares the offsets. @@ -2665,10 +2698,26 @@ // stripAndComputeConstantOffsets left off and accumulate the offsets. Constant *LHSNoBound = stripAndComputeConstantOffsets(DL, LHS, true); Constant *RHSNoBound = stripAndComputeConstantOffsets(DL, RHS, true); - if (LHS == RHS) + if (LHS == RHS) { + // Since we started with stripped versions of LHS/RHS the no-inbounds + // offsets might not have the same bit widths. We adjust all constants to + // the biggest type among them to ensure constant expressions below use + // equal-typed operands. + if (Type *MaxTy = getBiggestTypeIfDifferent( + DL, {LHSOffset, LHSNoBound, RHSNoBound})) { + if (LHSOffset->getType() != MaxTy) + LHSOffset = ConstantExpr::getZExt(LHSOffset, MaxTy); + if (RHSOffset->getType() != MaxTy) + RHSOffset = ConstantExpr::getZExt(RHSOffset, MaxTy); + if (LHSNoBound->getType() != MaxTy) + LHSNoBound = ConstantExpr::getZExt(LHSNoBound, MaxTy); + if (RHSNoBound->getType() != MaxTy) + RHSNoBound = ConstantExpr::getZExt(RHSNoBound, MaxTy); + } return ConstantExpr::getICmp(Pred, ConstantExpr::getAdd(LHSOffset, LHSNoBound), ConstantExpr::getAdd(RHSOffset, RHSNoBound)); + } // If one side of the equality comparison must come from a noalias call // (meaning a system memory allocation function), and the other side must