Skip to content

Commit 6df6320

Browse files
authored
[ValueTracking] isNonEqual Pointers with with a recursive GEP (llvm#70459)
Handles canonical icmp eq(ptr1, ptr2) -> where ptr1/ptr2 is a recursive GEP. Can helps scenarios where InstCombineCompares folds icmp eq(sub(ptr2int, ptr2int), 0) -> icmp eq(ptr1, ptr2) and icmp eq(phi(sub(ptr2int, ptr2int), ...)) -> phi i1 (icmp eq(sub(ptr2int, ptr2int), 0), ....)
1 parent 08b306d commit 6df6320

File tree

4 files changed

+661
-4
lines changed

4 files changed

+661
-4
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3096,6 +3096,58 @@ static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth,
30963096
isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q);
30973097
}
30983098

3099+
// Check to see if A is both a GEP and is the incoming value for a PHI in the
3100+
// loop, and B is either a ptr or another GEP. If the PHI has 2 incoming values,
3101+
// one of them being the recursive GEP A and the other a ptr at same base and at
3102+
// the same/higher offset than B we are only incrementing the pointer further in
3103+
// loop if offset of recursive GEP is greater than 0.
3104+
static bool isNonEqualPointersWithRecursiveGEP(const Value *A, const Value *B,
3105+
const SimplifyQuery &Q) {
3106+
if (!A->getType()->isPointerTy() || !B->getType()->isPointerTy())
3107+
return false;
3108+
3109+
auto *GEPA = dyn_cast<GEPOperator>(A);
3110+
if (!GEPA || GEPA->getNumIndices() != 1 || !isa<Constant>(GEPA->idx_begin()))
3111+
return false;
3112+
3113+
// Handle 2 incoming PHI values with one being a recursive GEP.
3114+
auto *PN = dyn_cast<PHINode>(GEPA->getPointerOperand());
3115+
if (!PN || PN->getNumIncomingValues() != 2)
3116+
return false;
3117+
3118+
// Search for the recursive GEP as an incoming operand, and record that as
3119+
// Step.
3120+
Value *Start = nullptr;
3121+
Value *Step = const_cast<Value *>(A);
3122+
if (PN->getIncomingValue(0) == Step)
3123+
Start = PN->getIncomingValue(1);
3124+
else if (PN->getIncomingValue(1) == Step)
3125+
Start = PN->getIncomingValue(0);
3126+
else
3127+
return false;
3128+
3129+
// Other incoming node base should match the B base.
3130+
// StartOffset >= OffsetB && StepOffset > 0?
3131+
// StartOffset <= OffsetB && StepOffset < 0?
3132+
// Is non-equal if above are true.
3133+
// We use stripAndAccumulateInBoundsConstantOffsets to restrict the
3134+
// optimisation to inbounds GEPs only.
3135+
unsigned IndexWidth = Q.DL.getIndexTypeSizeInBits(Start->getType());
3136+
APInt StartOffset(IndexWidth, 0);
3137+
Start = Start->stripAndAccumulateInBoundsConstantOffsets(Q.DL, StartOffset);
3138+
APInt StepOffset(IndexWidth, 0);
3139+
Step = Step->stripAndAccumulateInBoundsConstantOffsets(Q.DL, StepOffset);
3140+
3141+
// Check if Base Pointer of Step matches the PHI.
3142+
if (Step != PN)
3143+
return false;
3144+
APInt OffsetB(IndexWidth, 0);
3145+
B = B->stripAndAccumulateInBoundsConstantOffsets(Q.DL, OffsetB);
3146+
return Start == B &&
3147+
((StartOffset.sge(OffsetB) && StepOffset.isStrictlyPositive()) ||
3148+
(StartOffset.sle(OffsetB) && StepOffset.isNegative()));
3149+
}
3150+
30993151
/// Return true if it is known that V1 != V2.
31003152
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
31013153
const SimplifyQuery &Q) {
@@ -3149,6 +3201,10 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
31493201
if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q))
31503202
return true;
31513203

3204+
if (isNonEqualPointersWithRecursiveGEP(V1, V2, Q) ||
3205+
isNonEqualPointersWithRecursiveGEP(V2, V1, Q))
3206+
return true;
3207+
31523208
return false;
31533209
}
31543210

llvm/test/Analysis/ValueTracking/known-non-equal.ll

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,5 +1813,42 @@ exit:
18131813
ret i1 %res
18141814
}
18151815

1816+
; Illustrate if 2 pointers are non-equal when one of them is a recursive GEP.
1817+
define i1 @icmp_recursiveGEP_withPtr(ptr %val1) {
1818+
; CHECK-LABEL: @icmp_recursiveGEP_withPtr(
1819+
; CHECK-NEXT: entry:
1820+
; CHECK-NEXT: [[CMP_I:%.*]] = icmp eq ptr [[VAL1:%.*]], null
1821+
; CHECK-NEXT: br i1 [[CMP_I]], label [[_Z9STRINGLENPKS_EXIT:%.*]], label [[WHILE_COND_I:%.*]]
1822+
; CHECK: while.cond.i:
1823+
; CHECK-NEXT: [[A_PN_I:%.*]] = phi ptr [ [[TEST_0_I:%.*]], [[WHILE_COND_I]] ], [ [[VAL1]], [[ENTRY:%.*]] ]
1824+
; CHECK-NEXT: [[TEST_0_I]] = getelementptr inbounds i8, ptr [[A_PN_I]], i64 1
1825+
; CHECK-NEXT: [[TMP0:%.*]] = load i8, ptr [[TEST_0_I]], align 2
1826+
; CHECK-NEXT: [[CMP3_NOT_I:%.*]] = icmp eq i8 [[TMP0]], 0
1827+
; CHECK-NEXT: br i1 [[CMP3_NOT_I]], label [[WHILE_END_I:%.*]], label [[WHILE_COND_I]]
1828+
; CHECK: while.end.i:
1829+
; CHECK-NEXT: br label [[_Z9STRINGLENPKS_EXIT]]
1830+
; CHECK: _Z9stringlenPKs.exit:
1831+
; CHECK-NEXT: [[RETVAL_0_I:%.*]] = phi i1 [ false, [[WHILE_END_I]] ], [ true, [[ENTRY]] ]
1832+
; CHECK-NEXT: ret i1 [[RETVAL_0_I]]
1833+
;
1834+
entry:
1835+
%cmp.i = icmp eq ptr %val1, null
1836+
br i1 %cmp.i, label %_Z9stringlenPKs.exit, label %while.cond.i
1837+
1838+
while.cond.i:
1839+
%a.pn.i = phi ptr [ %test.0.i, %while.cond.i ], [ %val1, %entry ]
1840+
%test.0.i = getelementptr inbounds i8, ptr %a.pn.i, i64 1
1841+
%0 = load i8, ptr %test.0.i, align 2
1842+
%cmp3.not.i = icmp eq i8 %0, 0
1843+
br i1 %cmp3.not.i, label %while.end.i, label %while.cond.i
1844+
1845+
while.end.i:
1846+
%bool = icmp eq ptr %test.0.i, %val1
1847+
br label %_Z9stringlenPKs.exit
1848+
1849+
_Z9stringlenPKs.exit:
1850+
%retval.0.i = phi i1 [ %bool, %while.end.i ], [ true, %entry ]
1851+
ret i1 %retval.0.i
1852+
}
18161853

18171854
!0 = !{ i8 1, i8 5 }

0 commit comments

Comments
 (0)