[llvm] [Value] Look through inttoptr (add ..) in accumulateConstantOffsets (PR #124981)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 30 10:36:28 PST 2025


https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/124981

>From 9f59ca7c217140585709be5cec475dc670d8b94a Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 29 Jan 2025 20:23:07 +0000
Subject: [PATCH 1/3] [Value] Look through inttoptr (add ..) in
 accumulateConstantOffsets

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
---
 llvm/lib/Analysis/ConstantFolding.cpp         |  9 +++++----
 llvm/lib/IR/Value.cpp                         | 19 +++++++++++++++++++
 .../constant-fold-inttoptr-add.ll             |  9 +++------
 3 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 80c1277e631653..04741c57492ae6 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1258,11 +1258,12 @@ 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 AllowNonInbounds = ICmpInst::isEquality(Predicate);
+      Value *Stripped0 = Ops0->stripAndAccumulateConstantOffsets(
+          DL, Offset0, AllowNonInbounds);
       APInt Offset1(IndexWidth, 0);
-      Value *Stripped1 =
-          Ops1->stripAndAccumulateInBoundsConstantOffsets(DL, Offset1);
+      Value *Stripped1 = Ops1->stripAndAccumulateConstantOffsets(
+          DL, Offset1, AllowNonInbounds);
       if (Stripped0 == Stripped1)
         return ConstantInt::getBool(
             Ops0->getContext(),
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index eddb67282fca46..48905609429b19 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -775,6 +775,25 @@ 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 (!Int2Ptr || Int2Ptr->getOpcode() != Instruction::IntToPtr ||
+          Int2Ptr->getOperand(0)->getType()->getScalarSizeInBits() != BitWidth)
+        return V;
+      auto *Add = dyn_cast<AddOperator>(Int2Ptr->getOperand(0));
+      if (!AllowNonInbounds || !Add)
+        return V;
+      auto *Ptr2Int = dyn_cast<PtrToIntOperator>(Add->getOperand(0));
+      auto *CI = dyn_cast<ConstantInt>(Add->getOperand(1));
+      if (!Ptr2Int || !CI)
+        return V;
+
+      APInt AddOffset = CI->getValue();
+      if (AddOffset.getSignificantBits() > BitWidth)
+        return V;
+
+      Offset = AddOffset.sextOrTrunc(BitWidth);
+      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 59b41574102464..18488fa171f07e 100644
--- a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
+++ b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
@@ -5,8 +5,7 @@
 
 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
@@ -23,8 +22,7 @@ define i1 @known_constexpr_add_eq_ops_swapped() {
 
 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 +39,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

>From d5fb1db8b7a9beb867462ea70eb39c355c1371ee Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 30 Jan 2025 12:18:00 +0000
Subject: [PATCH 2/3] !fixup add LookThroughIntToPtr flag

---
 llvm/include/llvm/IR/Value.h                  | 14 +++++++++----
 llvm/lib/Analysis/ConstantFolding.cpp         | 10 +++++++---
 llvm/lib/IR/Value.cpp                         | 17 ++++++++--------
 .../constant-fold-inttoptr-add.ll             | 20 +++++++++++++++++--
 4 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h
index 011aedece94ab7..cfed12e2f5f8d2 100644
--- a/llvm/include/llvm/IR/Value.h
+++ b/llvm/include/llvm/IR/Value.h
@@ -710,6 +710,10 @@ class Value {
   /// 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 @@ class Value {
       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 04741c57492ae6..46a4901ee65db8 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1258,12 +1258,16 @@ Constant *llvm::ConstantFoldCompareInstOperands(
     if (Ops0->getType()->isPointerTy() && !ICmpInst::isSigned(Predicate)) {
       unsigned IndexWidth = DL.getIndexTypeSizeInBits(Ops0->getType());
       APInt Offset0(IndexWidth, 0);
-      bool AllowNonInbounds = ICmpInst::isEquality(Predicate);
+      bool IsEqPred = ICmpInst::isEquality(Predicate);
       Value *Stripped0 = Ops0->stripAndAccumulateConstantOffsets(
-          DL, Offset0, AllowNonInbounds);
+          DL, Offset0, /*AllowNonInbounds=*/IsEqPred,
+          /*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr,
+          /*LookThroughIntToPtr*/ IsEqPred);
       APInt Offset1(IndexWidth, 0);
       Value *Stripped1 = Ops1->stripAndAccumulateConstantOffsets(
-          DL, Offset1, AllowNonInbounds);
+          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 48905609429b19..4c3b11f6ce6443 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;
 
@@ -777,22 +778,22 @@ const Value *Value::stripAndAccumulateConstantOffsets(
           V = Call->getArgOperand(0);
     } else if (auto *Int2Ptr = dyn_cast<Operator>(V)) {
       // Try to accumulate across (inttoptr (add (ptrtoint p), off)).
-      if (!Int2Ptr || Int2Ptr->getOpcode() != Instruction::IntToPtr ||
+      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 (!AllowNonInbounds || !Add)
+      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;
 
-      APInt AddOffset = CI->getValue();
-      if (AddOffset.getSignificantBits() > BitWidth)
-        return V;
-
-      Offset = AddOffset.sextOrTrunc(BitWidth);
+      const APInt &AddOffset = CI->getValue();
+      Offset += AddOffset;
       V = Ptr2Int->getOperand(0);
     }
     assert(V->getType()->isPtrOrPtrVectorTy() && "Unexpected operand type!");
diff --git a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
index 18488fa171f07e..7a09542dd1f4ca 100644
--- a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
+++ b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
@@ -13,8 +13,7 @@ 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)
   ret i1 %cond
@@ -96,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
+}

>From fb338c3b20ea3d701d168120c972cba703ad7ecc Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 30 Jan 2025 18:35:15 +0000
Subject: [PATCH 3/3] !fixup address comments, thanks

---
 llvm/lib/Analysis/ConstantFolding.cpp                         | 4 ++--
 llvm/lib/IR/Value.cpp                                         | 3 +--
 .../Transforms/InstSimplify/constant-fold-inttoptr-add.ll     | 4 ++--
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 46a4901ee65db8..d645bf8f7b6212 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1262,12 +1262,12 @@ Constant *llvm::ConstantFoldCompareInstOperands(
       Value *Stripped0 = Ops0->stripAndAccumulateConstantOffsets(
           DL, Offset0, /*AllowNonInbounds=*/IsEqPred,
           /*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr,
-          /*LookThroughIntToPtr*/ IsEqPred);
+          /*LookThroughIntToPtr=*/IsEqPred);
       APInt Offset1(IndexWidth, 0);
       Value *Stripped1 = Ops1->stripAndAccumulateConstantOffsets(
           DL, Offset1, /*AllowNonInbounds=*/IsEqPred,
           /*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr,
-          /*LookThroughIntToPtr*/ IsEqPred);
+          /*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 4c3b11f6ce6443..b5a69b9ecdde45 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -792,8 +792,7 @@ const Value *Value::stripAndAccumulateConstantOffsets(
       if (!Ptr2Int || !CI)
         return V;
 
-      const APInt &AddOffset = CI->getValue();
-      Offset += AddOffset;
+      Offset += CI->getValue();
       V = Ptr2Int->getOperand(0);
     }
     assert(V->getType()->isPtrOrPtrVectorTy() && "Unexpected operand type!");
diff --git a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
index 7a09542dd1f4ca..34dee39463d9b6 100644
--- a/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
+++ b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
@@ -1,5 +1,5 @@
 ; 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]
 
@@ -15,7 +15,7 @@ define i1 @known_constexpr_add_eq_ops_swapped() {
 ; CHECK-LABEL: define i1 @known_constexpr_add_eq_ops_swapped() {
 ; 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
 }
 



More information about the llvm-commits mailing list