[llvm] [ValueTracking] isNonZero trunc of sub of ptr2int's with recursive GEP where pointers are limited to a 32bit alloc. (PR #84933)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 22 10:57:19 PDT 2024
================
@@ -2644,6 +2649,81 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
// ext X != 0 if X != 0.
return isKnownNonZero(I->getOperand(0), Q, Depth);
+ case Instruction::Trunc:
+ // trunc(operand) is KnownNonZero if lower order bits of operand is a
+ // KnownNonZero. Handle scenarios like trunc i64 (sub(ptr2int, ptr2int)) to
+ // i32 / trunc i64 (lshr(sub(ptr2int, ptr2int))) to i32, where the ptrs are
+ // from same object and one of the pointers is a recursive GEP. And either
+ // the objectSize is known OR is indicative via a compiler flag, which
+ // suggests objectSize<4G.
+ Value *A, *B;
+ if (match(I->getOperand(0), m_Sub(m_PtrToIntSameSize(Q.DL, m_Value(A)),
+ m_PtrToIntSameSize(Q.DL, m_Value(B)))) ||
+ match(I->getOperand(0),
+ m_LShr(m_Sub(m_PtrToIntSameSize(Q.DL, m_Value(A)),
+ m_PtrToIntSameSize(Q.DL, m_Value(B))),
+ m_ConstantInt()))) {
+ // Check for a specific pattern where A is recursive GEP with a PHI ptr
+ // with incoming values as (Start,Step) and Start==B.
+ auto *GEPA = dyn_cast<GEPOperator>(A);
+ if (!GEPA) {
+ GEPA = dyn_cast<GEPOperator>(B);
+ std::swap(A, B);
+ }
+ 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;
+
+ // Check if the pointers Start and B are same and ObjectSize can be
+ // determined/PointerAllocationsLimitedto32bit flag set.
+ if (Start == B) {
+ ObjectSizeOpts Opts;
+ Opts.RoundToAlign = false;
+ Opts.NullIsUnknownSize = true;
+ uint64_t ObjSize = 0;
+ // Can we get the ObjectSize and ObjectSize is within range.
+ // There is possibly more that we can do when ObjSize if known, and
+ // extend the same for other truncates. Restricting it for a 32bit
+ // truncate result.
+ if (getObjectSize(Start, ObjSize, Q.DL, Q.TLI, Opts)) {
+ if (ObjSize == 0 || ObjSize > (uint64_t)0xFFFFFFFF)
+ return false;
+ }
+ // Does the compiler flag specify Object allocs within 4G.
+ else if (!PointerAllocationsLimitedto32bit)
+ return false;
+ } else
+ return false;
+
+ // Check if trunc src type is same as Ptr type and dest is a 32bit.
+ // If objectSize<4G or PointerAllocationsLimitedto32bit flag set, check if
+ // the trunc operand is a KnownNonZero.
+ LLVMContext &Ctx = I->getContext();
+ Type *SrcTy = I->getOperand(0)->getType();
+ Type *DstTy = I->getType();
+ unsigned IntPtrWidth = Q.DL.getPointerSizeInBits();
+ unsigned TruncSrcBits = Q.DL.getTypeSizeInBits(SrcTy);
+ if (TruncSrcBits == IntPtrWidth && DstTy == Type::getInt32Ty(Ctx))
----------------
goldsteinn wrote:
Think this check should be at the very top.
https://github.com/llvm/llvm-project/pull/84933
More information about the llvm-commits
mailing list