diff options
author | Florian Hahn <flo@fhahn.com> | 2025-01-30 20:58:38 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-01-30 20:58:38 +0000 |
commit | 55815b621b3a8f56a36c93229de1356e325a136f (patch) | |
tree | b41456d4e22d70229b81bbbd3248e2acbbe63346 /llvm | |
parent | 9b52dbe0e0c3298438fd0a32495dd796b1d33970 (diff) | |
download | llvm-55815b621b3a8f56a36c93229de1356e325a136f.zip llvm-55815b621b3a8f56a36c93229de1356e325a136f.tar.gz llvm-55815b621b3a8f56a36c93229de1356e325a136f.tar.bz2 |
[Value] Look through inttoptr (add ..) in accumulateConstantOffsets (#124981)
Look through inttoptr (add (ptrtoint P), C) when accumulating offsets.
Adds a missing fold after
https://github.com/llvm/llvm-project/pull/123518
Alive2 for the tests with changes: https://alive2.llvm.org/ce/z/VvPrzv
PR: https://github.com/llvm/llvm-project/pull/124981
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/IR/Value.h | 14 | ||||
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 13 | ||||
-rw-r--r-- | llvm/lib/IR/Value.cpp | 21 | ||||
-rw-r--r-- | llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll | 33 |
4 files changed, 62 insertions, 19 deletions
diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h index 011aedec..cfed12e 100644 --- a/llvm/include/llvm/IR/Value.h +++ b/llvm/include/llvm/IR/Value.h @@ -710,6 +710,10 @@ public: /// For example, for a value \p ExternalAnalysis might try to calculate a /// lower bound. If \p ExternalAnalysis is successful, it should return true. /// + /// If \p LookThroughIntToPtr is true then this method also looks through + /// IntToPtr and PtrToInt constant expressions. The returned pointer may not + /// have the same provenance as this value. + /// /// If this is called on a non-pointer value, it returns 'this' and the /// \p Offset is not modified. /// @@ -722,17 +726,19 @@ public: const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup = false, function_ref<bool(Value &Value, APInt &Offset)> ExternalAnalysis = - nullptr) const; + nullptr, + bool LookThroughIntToPtr = false) const; Value *stripAndAccumulateConstantOffsets( const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup = false, function_ref<bool(Value &Value, APInt &Offset)> ExternalAnalysis = - nullptr) { + nullptr, + bool LookThroughIntToPtr = false) { return const_cast<Value *>( static_cast<const Value *>(this)->stripAndAccumulateConstantOffsets( - DL, Offset, AllowNonInbounds, AllowInvariantGroup, - ExternalAnalysis)); + DL, Offset, AllowNonInbounds, AllowInvariantGroup, ExternalAnalysis, + LookThroughIntToPtr)); } /// This is a wrapper around stripAndAccumulateConstantOffsets with the diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 80c1277..d645bf8 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1258,11 +1258,16 @@ Constant *llvm::ConstantFoldCompareInstOperands( if (Ops0->getType()->isPointerTy() && !ICmpInst::isSigned(Predicate)) { unsigned IndexWidth = DL.getIndexTypeSizeInBits(Ops0->getType()); APInt Offset0(IndexWidth, 0); - Value *Stripped0 = - Ops0->stripAndAccumulateInBoundsConstantOffsets(DL, Offset0); + bool IsEqPred = ICmpInst::isEquality(Predicate); + Value *Stripped0 = Ops0->stripAndAccumulateConstantOffsets( + DL, Offset0, /*AllowNonInbounds=*/IsEqPred, + /*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr, + /*LookThroughIntToPtr=*/IsEqPred); APInt Offset1(IndexWidth, 0); - Value *Stripped1 = - Ops1->stripAndAccumulateInBoundsConstantOffsets(DL, Offset1); + Value *Stripped1 = Ops1->stripAndAccumulateConstantOffsets( + DL, Offset1, /*AllowNonInbounds=*/IsEqPred, + /*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr, + /*LookThroughIntToPtr=*/IsEqPred); if (Stripped0 == Stripped1) return ConstantInt::getBool( Ops0->getContext(), diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index eddb672..b5a69b9 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -714,7 +714,8 @@ const Value *Value::stripPointerCastsForAliasAnalysis() const { const Value *Value::stripAndAccumulateConstantOffsets( const DataLayout &DL, APInt &Offset, bool AllowNonInbounds, bool AllowInvariantGroup, - function_ref<bool(Value &, APInt &)> ExternalAnalysis) const { + function_ref<bool(Value &, APInt &)> ExternalAnalysis, + bool LookThroughIntToPtr) const { if (!getType()->isPtrOrPtrVectorTy()) return this; @@ -775,6 +776,24 @@ const Value *Value::stripAndAccumulateConstantOffsets( V = RV; if (AllowInvariantGroup && Call->isLaunderOrStripInvariantGroup()) V = Call->getArgOperand(0); + } else if (auto *Int2Ptr = dyn_cast<Operator>(V)) { + // Try to accumulate across (inttoptr (add (ptrtoint p), off)). + if (!AllowNonInbounds || !LookThroughIntToPtr || !Int2Ptr || + Int2Ptr->getOpcode() != Instruction::IntToPtr || + Int2Ptr->getOperand(0)->getType()->getScalarSizeInBits() != BitWidth) + return V; + + auto *Add = dyn_cast<AddOperator>(Int2Ptr->getOperand(0)); + if (!Add) + return V; + + auto *Ptr2Int = dyn_cast<PtrToIntOperator>(Add->getOperand(0)); + auto *CI = dyn_cast<ConstantInt>(Add->getOperand(1)); + if (!Ptr2Int || !CI) + return V; + + Offset += CI->getValue(); + V = Ptr2Int->getOperand(0); } assert(V->getType()->isPtrOrPtrVectorTy() && "Unexpected operand type!"); } while (Visited.insert(V).second); diff --git a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll index 59b4157..34dee39 100644 --- a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll +++ b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll @@ -1,12 +1,11 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; RUN: opt -p instcombine -S %s | FileCheck %s +; RUN: opt -p instsimplify -S %s | FileCheck %s @glob = external global [314 x i64] define i1 @known_constexpr_add_eq() { ; CHECK-LABEL: define i1 @known_constexpr_add_eq() { -; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr) -; CHECK-NEXT: ret i1 [[COND]] +; CHECK-NEXT: ret i1 false ; %cond = icmp eq ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr) ret i1 %cond @@ -14,17 +13,15 @@ define i1 @known_constexpr_add_eq() { define i1 @known_constexpr_add_eq_ops_swapped() { ; CHECK-LABEL: define i1 @known_constexpr_add_eq_ops_swapped() { -; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr) -; CHECK-NEXT: ret i1 [[COND]] +; CHECK-NEXT: ret i1 false ; - %cond = icmp eq ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr) + %cond = icmp eq ptr inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr), getelementptr inbounds nuw (i8, ptr @glob, i64 80) ret i1 %cond } define i1 @known_constexpr_add_ne() { ; CHECK-LABEL: define i1 @known_constexpr_add_ne() { -; CHECK-NEXT: [[COND:%.*]] = icmp ne ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr) -; CHECK-NEXT: ret i1 [[COND]] +; CHECK-NEXT: ret i1 true ; %cond = icmp ne ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr) ret i1 %cond @@ -41,8 +38,7 @@ define i1 @wrap_positive_to_negate() { ; 9223372036854775808 = 2^63 define i1 @wrap_positive_to_zero() { ; CHECK-LABEL: define i1 @wrap_positive_to_zero() { -; CHECK-NEXT: [[COND:%.*]] = icmp eq ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr getelementptr nuw (i8, ptr @glob, i64 -9223372036854775808) to i64), i64 -9223372036854775808) to ptr) -; CHECK-NEXT: ret i1 [[COND]] +; CHECK-NEXT: ret i1 true ; %cond = icmp eq ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr getelementptr nuw (i8, ptr @glob, i64 9223372036854775808)to i64), i64 9223372036854775808) to ptr) ret i1 %cond @@ -99,3 +95,20 @@ define ptr @return_inttoptr() { ; ret ptr inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 8) to ptr) } + +define i1 @known_constexpr_add_nested_1() { +; CHECK-LABEL: define i1 @known_constexpr_add_nested_1() { +; CHECK-NEXT: ret i1 true +; + %cond = icmp eq ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80) to i64), i64 -80) to ptr) + ret i1 %cond +} + +define i1 @known_constexpr_add_nested_2() { +; CHECK-LABEL: define i1 @known_constexpr_add_nested_2() { +; CHECK-NEXT: ret i1 true +; + ;%cond = icmp eq ptr @glob, ptr getelementptr inbounds nuw (i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr), i64 80) + %cond = icmp eq ptr @glob, getelementptr inbounds nuw (i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr), i64 80) + ret i1 %cond +} |