Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 30, 2025

Conversation

fhahn
Copy link
Contributor

@fhahn fhahn commented Jan 29, 2025

Look through inttoptr (add (ptrtoint P), C) when accumulating offsets.

Adds a missing fold after
#123518

Alive2 for the tests with changes: https://alive2.llvm.org/ce/z/VvPrzv

@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:ir llvm:analysis Includes value tracking, cost tables and constant folding llvm:transforms labels Jan 29, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 29, 2025

@llvm/pr-subscribers-llvm-ir
@llvm/pr-subscribers-llvm-analysis

@llvm/pr-subscribers-llvm-transforms

Author: Florian Hahn (fhahn)

Changes

Look through inttoptr (add (ptrtoint P), C) when accumulating offsets.

Adds a missing fold after
#123518

Alive2 for the tests with changes: https://alive2.llvm.org/ce/z/VvPrzv


Full diff: https://github.com/llvm/llvm-project/pull/124981.diff

3 Files Affected:

  • (modified) llvm/lib/Analysis/ConstantFolding.cpp (+5-4)
  • (modified) llvm/lib/IR/Value.cpp (+19)
  • (added) llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll (+84)
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
new file mode 100644
index 00000000000000..a0a34e2fe73958
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
@@ -0,0 +1,84 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -p instcombine -S %s | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+
+@glob = external global [314 x i64]
+
+define i1 @known_constexpr_add_eq() {
+; CHECK-LABEL: define i1 @known_constexpr_add_eq() {
+; 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
+}
+
+define i1 @known_constexpr_add_ne() {
+; CHECK-LABEL: define i1 @known_constexpr_add_ne() {
+; 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
+}
+
+define i1 @wrap_positive_to_negate() {
+; CHECK-LABEL: define i1 @wrap_positive_to_negate() {
+; CHECK-NEXT:    ret i1 false
+;
+  %cond = icmp eq ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr getelementptr nuw (i8, ptr @glob, i64 1)to i64), i64 9223372036854775808) to ptr)
+  ret i1 %cond
+}
+
+; 9223372036854775808 = 2^63
+define i1 @wrap_positive_to_zero() {
+; CHECK-LABEL: define i1 @wrap_positive_to_zero() {
+; 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
+}
+
+define i1 @not_known_constexpr_add_sle() {
+; CHECK-LABEL: define i1 @not_known_constexpr_add_sle() {
+; CHECK-NEXT:    [[COND:%.*]] = icmp sle ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %cond = icmp sle ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+  ret i1 %cond
+}
+
+define i1 @not_known_constexpr_add_ule() {
+; CHECK-LABEL: define i1 @not_known_constexpr_add_ule() {
+; CHECK-NEXT:    [[COND:%.*]] = icmp ule ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %cond = icmp ule ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+  ret i1 %cond
+}
+
+define i1 @not_known_constexpr_add_sge() {
+; CHECK-LABEL: define i1 @not_known_constexpr_add_sge() {
+; CHECK-NEXT:    [[COND:%.*]] = icmp sge ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %cond = icmp sge ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+  ret i1 %cond
+}
+
+define i1 @not_known_constexpr_add_uge() {
+; CHECK-LABEL: define i1 @not_known_constexpr_add_uge() {
+; CHECK-NEXT:    [[COND:%.*]] = icmp uge ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %cond = icmp uge ptr @glob, inttoptr (i64 add (i64 ptrtoint (ptr @glob to i64), i64 -80) to ptr)
+  ret i1 %cond
+}
+
+define i1 @not_known_integer_width_does_not_match_pointer_index_width() {
+; CHECK-LABEL: define i1 @not_known_integer_width_does_not_match_pointer_index_width() {
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i32 add (i32 ptrtoint (ptr @glob to i32), i32 -80) to ptr)
+; CHECK-NEXT:    ret i1 [[COND]]
+;
+  %cond = icmp eq ptr getelementptr inbounds nuw (i8, ptr @glob, i64 80), inttoptr (i32 add (i32 ptrtoint (ptr @glob to i32), i32 -80) to ptr)
+  ret i1 %cond
+}

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is valid for this particular icmp transform, but generally users of stripAndAccumulateConstantOffsets will assume that the result still has the same provenance, which is not the case if you look through inttoptr. This needs to be behind a flag.

fhahn added a commit that referenced this pull request Jan 30, 2025
github-actions bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 30, 2025
@fhahn fhahn force-pushed the accumulate-inttoptr-add branch 2 times, most recently from 766ac5d to 96ddc6f Compare January 30, 2025 13:03
Copy link
Contributor Author

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I briefly tried to come up with a tests where the result would be used incorrectly, but wasn't able to.

I added a new LookThroughIntToPtr flag.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Value *Stripped0 = Ops0->stripAndAccumulateConstantOffsets(
DL, Offset0, /*AllowNonInbounds=*/IsEqPred,
/*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr,
/*LookThroughIntToPtr*/ IsEqPred);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/*LookThroughIntToPtr*/ IsEqPred);
/*LookThroughIntToPtr=*/IsEqPred);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks

Value *Stripped1 = Ops1->stripAndAccumulateConstantOffsets(
DL, Offset1, /*AllowNonInbounds=*/IsEqPred,
/*AllowInvariantGroup=*/false, /*ExternalAnalysis=*/nullptr,
/*LookThroughIntToPtr*/ IsEqPred);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/*LookThroughIntToPtr*/ IsEqPred);
/*LookThroughIntToPtr=*/IsEqPred);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks

Comment on lines 795 to 796
const APInt &AddOffset = CI->getValue();
Offset += AddOffset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const APInt &AddOffset = CI->getValue();
Offset += AddOffset;
Offset += CI->getValue();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done thanks

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test should either use -p instsimplify or be in the InstCombine directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I had it in instcombine, then moved but. not updated the run-line should be fixed now thanks

@@ -5,26 +5,23 @@

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
}

define i1 @known_constexpr_add_eq_ops_swapped() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get what the difference between this test and the previous is. What's swapped here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adjusted the name but not the code... fixed now, thanks

fhahn added 3 commits January 30, 2025 18:18
Look through inttoptr (add (ptrtoint P), C) when accumulating offsets.

Adds a missing fold after
llvm#123518

Alive2 for the tests with changes: https://alive2.llvm.org/ce/z/VvPrzv
@fhahn fhahn force-pushed the accumulate-inttoptr-add branch from 96ddc6f to fb338c3 Compare January 30, 2025 18:36
@fhahn fhahn merged commit 55815b6 into llvm:main Jan 30, 2025
6 of 8 checks passed
@fhahn fhahn deleted the accumulate-inttoptr-add branch January 30, 2025 21:05
github-actions bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 30, 2025
…ntOffsets (#124981)

Look through inttoptr (add (ptrtoint P), C) when accumulating offsets.

Adds a missing fold after
llvm/llvm-project#123518

Alive2 for the tests with changes: https://alive2.llvm.org/ce/z/VvPrzv

PR: llvm/llvm-project#124981
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:analysis Includes value tracking, cost tables and constant folding llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:ir llvm:transforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants