diff options
author | bipmis <102525366+bipmis@users.noreply.github.com> | 2023-12-15 10:02:57 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-12-15 10:02:57 +0000 |
commit | 6df63203749200e09199577a7646442f77fc67ce (patch) | |
tree | 0393a6b775c5c66ce740f1bcd1c40d121445f8e3 /llvm/lib/Analysis/ValueTracking.cpp | |
parent | 08b306dc8e7c0b2498f4f194a3c51686d56dbd20 (diff) | |
download | llvm-6df63203749200e09199577a7646442f77fc67ce.zip llvm-6df63203749200e09199577a7646442f77fc67ce.tar.gz llvm-6df63203749200e09199577a7646442f77fc67ce.tar.bz2 |
[ValueTracking] isNonEqual Pointers with with a recursive GEP (#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), ....)
Diffstat (limited to 'llvm/lib/Analysis/ValueTracking.cpp')
-rw-r--r-- | llvm/lib/Analysis/ValueTracking.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 8f32a1ba..9ae05a4 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3096,6 +3096,58 @@ static bool isNonEqualSelect(const Value *V1, const Value *V2, unsigned Depth, isKnownNonEqual(SI1->getFalseValue(), V2, Depth + 1, Q); } +// Check to see if A is both a GEP and is the incoming value for a PHI in the +// loop, and B is either a ptr or another GEP. If the PHI has 2 incoming values, +// one of them being the recursive GEP A and the other a ptr at same base and at +// the same/higher offset than B we are only incrementing the pointer further in +// loop if offset of recursive GEP is greater than 0. +static bool isNonEqualPointersWithRecursiveGEP(const Value *A, const Value *B, + const SimplifyQuery &Q) { + if (!A->getType()->isPointerTy() || !B->getType()->isPointerTy()) + return false; + + auto *GEPA = dyn_cast<GEPOperator>(A); + if (!GEPA || GEPA->getNumIndices() != 1 || !isa<Constant>(GEPA->idx_begin())) + return false; + + // Handle 2 incoming PHI values with one being a recursive GEP. + auto *PN = dyn_cast<PHINode>(GEPA->getPointerOperand()); + if (!PN || PN->getNumIncomingValues() != 2) + return false; + + // Search for the recursive GEP as an incoming operand, and record that as + // Step. + Value *Start = nullptr; + Value *Step = const_cast<Value *>(A); + if (PN->getIncomingValue(0) == Step) + Start = PN->getIncomingValue(1); + else if (PN->getIncomingValue(1) == Step) + Start = PN->getIncomingValue(0); + else + return false; + + // Other incoming node base should match the B base. + // StartOffset >= OffsetB && StepOffset > 0? + // StartOffset <= OffsetB && StepOffset < 0? + // Is non-equal if above are true. + // We use stripAndAccumulateInBoundsConstantOffsets to restrict the + // optimisation to inbounds GEPs only. + unsigned IndexWidth = Q.DL.getIndexTypeSizeInBits(Start->getType()); + APInt StartOffset(IndexWidth, 0); + Start = Start->stripAndAccumulateInBoundsConstantOffsets(Q.DL, StartOffset); + APInt StepOffset(IndexWidth, 0); + Step = Step->stripAndAccumulateInBoundsConstantOffsets(Q.DL, StepOffset); + + // Check if Base Pointer of Step matches the PHI. + if (Step != PN) + return false; + APInt OffsetB(IndexWidth, 0); + B = B->stripAndAccumulateInBoundsConstantOffsets(Q.DL, OffsetB); + return Start == B && + ((StartOffset.sge(OffsetB) && StepOffset.isStrictlyPositive()) || + (StartOffset.sle(OffsetB) && StepOffset.isNegative())); +} + /// Return true if it is known that V1 != V2. static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth, const SimplifyQuery &Q) { @@ -3149,6 +3201,10 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth, if (isNonEqualSelect(V1, V2, Depth, Q) || isNonEqualSelect(V2, V1, Depth, Q)) return true; + if (isNonEqualPointersWithRecursiveGEP(V1, V2, Q) || + isNonEqualPointersWithRecursiveGEP(V2, V1, Q)) + return true; + return false; } |