Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -8199,6 +8199,57 @@ return std::nullopt; } +bool matchLoadConstantArrayWithConstant(const LoadInst *LI, + const GetElementPtrInst *GEP, + const Value *Index, Constant *&ConstArray) { + + if (GEP->getOperand(1) != Index || GEP->getNumIndices() != 1) + return false; + + auto *GV = dyn_cast(GEP->getOperand(0)); + + if (!GV || LI->isVolatile() || LI->getType() != GEP->getResultElementType() || + GV->getValueType()->getArrayElementType() != + GEP->getSourceElementType() || + !GV->isConstant() || !GV->hasDefinitiveInitializer()) + return false; + + Constant *Init = GV->getInitializer(); + if (!isa(Init) && !isa(Init)) + return false; + + ConstArray = Init; + return true; +} + +static std::optional isImpliedCondLoadConstantArrayWithConstant( + Value *Index, CmpInst::Predicate LPred, const APInt &LC, + GetElementPtrInst *GEP, CmpInst::Predicate RPred, const APInt &RC, + Constant *ConstArray) { + unsigned BitWidth = GEP->getSourceElementType()->getScalarSizeInBits(); + ConstantRange IndexCR = ConstantRange::makeExactICmpRegion(LPred, LC); + int64_t MinIndex = IndexCR.getSignedMin().getSExtValue(); + int64_t MaxIndex = IndexCR.getSignedMax().getSExtValue(); + int64_t ElementCount = ConstArray->getType()->getArrayNumElements(); + if (MaxIndex >= ElementCount || MinIndex < 0) + return std::nullopt; + + ConstantRange DomCR = ConstantRange::getEmpty(BitWidth); + for (int64_t i = MinIndex; i <= MaxIndex; ++i) { + APInt Element = ConstArray->getAggregateElement(i)->getUniqueInteger(); + DomCR = DomCR.unionWith(ConstantRange::getNonEmpty(Element, Element + 1)); + } + ConstantRange CR = ConstantRange::makeExactICmpRegion(RPred, RC); + + ConstantRange Intersection = DomCR.intersectWith(CR); + ConstantRange Difference = DomCR.difference(CR); + if (Intersection.isEmptySet()) + return false; + if (Difference.isEmptySet()) + return true; + return std::nullopt; +} + /// Return true if LHS implies RHS (expanded to its components as "R0 RPred R1") /// is true. Return false if LHS implies RHS is false. Otherwise, return /// std::nullopt if we can't infer anything. @@ -8226,6 +8277,17 @@ if (L0 == R0 && match(L1, m_APInt(LC)) && match(R1, m_APInt(RC))) return isImpliedCondCommonOperandWithConstants(LPred, *LC, RPred, *RC); + Value *Loaded; + Constant* ConstArray; + GetElementPtrInst *GEP; + if (match(L1, m_APInt(LC)) && match(R1, m_APInt(RC)) && + match(R0, m_Load(m_Value(Loaded))) && + (GEP = dyn_cast(Loaded)) && + matchLoadConstantArrayWithConstant(cast(R0), GEP, L0, + ConstArray)) + return isImpliedCondLoadConstantArrayWithConstant(L0, LPred, *LC, GEP, + RPred, *RC, ConstArray); + if (LPred == RPred) return isImpliedCondOperands(LPred, L0, L1, R0, R1, DL, Depth); Index: llvm/test/Transforms/InstCombine/load-cmp-index.ll =================================================================== --- llvm/test/Transforms/InstCombine/load-cmp-index.ll +++ llvm/test/Transforms/InstCombine/load-cmp-index.ll @@ -12,10 +12,7 @@ ; CHECK: case2: ; CHECK-NEXT: ret i1 false ; CHECK: case1: -; CHECK-NEXT: [[ISOK_PTR:%.*]] = getelementptr inbounds i32, ptr @CG, i64 [[X]] -; CHECK-NEXT: [[ISOK:%.*]] = load i32, ptr [[ISOK_PTR]], align 4 -; CHECK-NEXT: [[COND_INFERRED:%.*]] = icmp ult i32 [[ISOK]], 3 -; CHECK-NEXT: ret i1 [[COND_INFERRED]] +; CHECK-NEXT: ret i1 true ; entry: %cond = icmp ult i64 %x, 2 @@ -40,10 +37,7 @@ ; CHECK: case2: ; CHECK-NEXT: ret i1 false ; CHECK: case1: -; CHECK-NEXT: [[ISOK_PTR:%.*]] = getelementptr inbounds i32, ptr @CG, i64 [[X]] -; CHECK-NEXT: [[ISOK:%.*]] = load i32, ptr [[ISOK_PTR]], align 4 -; CHECK-NEXT: [[COND_INFERRED:%.*]] = icmp ugt i32 [[ISOK]], 10 -; CHECK-NEXT: ret i1 [[COND_INFERRED]] +; CHECK-NEXT: ret i1 false ; entry: %cond = icmp ult i64 %x, 2