-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-llvm-transforms Author: Florian Hahn (fhahn) ChangesLook through inttoptr (add (ptrtoint P), C) when accumulating offsets. Adds a missing fold after 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:
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
+}
|
There was a problem hiding this 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.
llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
Outdated
Show resolved
Hide resolved
766ac5d
to
96ddc6f
Compare
There was a problem hiding this 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.
llvm/test/Transforms/InstSimplify/constant-fold-inttoptr-add.ll
Outdated
Show resolved
Hide resolved
There was a problem hiding this 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/*LookThroughIntToPtr*/ IsEqPred); | |
/*LookThroughIntToPtr=*/IsEqPred); |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/*LookThroughIntToPtr*/ IsEqPred); | |
/*LookThroughIntToPtr=*/IsEqPred); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done thanks
llvm/lib/IR/Value.cpp
Outdated
const APInt &AddOffset = CI->getValue(); | ||
Offset += AddOffset; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const APInt &AddOffset = CI->getValue(); | |
Offset += AddOffset; | |
Offset += CI->getValue(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done thanks
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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
96ddc6f
to
fb338c3
Compare
…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
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