-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
[InstCombine] Canonicalize the stored value type with inttoptr/ptrtoint #76339
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesThis patch folds away the
Full diff: https://github.com/llvm/llvm-project/pull/76339.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index bb2a77daa60a76..7a5a811c5e0b2e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -1209,6 +1209,20 @@ static bool combineStoreToValueType(InstCombinerImpl &IC, StoreInst &SI) {
return true;
}
+ // Fold away inttoptr/ptrtoint of the stored value by storing the original
+ // type.
+ Value *X;
+ if (match(V, m_IntToPtr(m_Value(X))) || match(V, m_PtrToInt(m_Value(X)))) {
+ const DataLayout &DL = IC.getDataLayout();
+ if (DL.getTypeStoreSize(V->getType()->getScalarType()) !=
+ DL.getTypeStoreSize(X->getType()->getScalarType()))
+ return false;
+ if (!SI.isAtomic() || isSupportedAtomicType(X->getType())) {
+ combineStoreToNewValue(IC, SI, X);
+ return true;
+ }
+ }
+
// FIXME: We should also canonicalize stores of vectors when their elements
// are cast to other types.
return false;
diff --git a/llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll b/llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll
new file mode 100644
index 00000000000000..8336f5eccd3841
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll
@@ -0,0 +1,86 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=instcombine -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"
+
+declare void @use64(i64)
+declare void @useptr(ptr)
+define void @test_inttoptr(ptr %p, i64 %x) {
+; CHECK-LABEL: define void @test_inttoptr(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[X:%.*]]) {
+; CHECK-NEXT: store i64 [[X]], ptr [[P]], align 8
+; CHECK-NEXT: ret void
+;
+ %y = inttoptr i64 %x to ptr
+ store ptr %y, ptr %p, align 8
+ ret void
+}
+define void @test_inttoptr_multiuse(ptr %p, i64 %x) {
+; CHECK-LABEL: define void @test_inttoptr_multiuse(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[X:%.*]]) {
+; CHECK-NEXT: [[Y:%.*]] = inttoptr i64 [[X]] to ptr
+; CHECK-NEXT: call void @useptr(ptr [[Y]])
+; CHECK-NEXT: store i64 [[X]], ptr [[P]], align 8
+; CHECK-NEXT: ret void
+;
+ %y = inttoptr i64 %x to ptr
+ call void @useptr(ptr %y)
+ store ptr %y, ptr %p, align 8
+ ret void
+}
+define void @test_inttoptr_constant_expr(ptr %p) {
+; CHECK-LABEL: define void @test_inttoptr_constant_expr(
+; CHECK-SAME: ptr [[P:%.*]]) {
+; CHECK-NEXT: store i64 65, ptr [[P]], align 8
+; CHECK-NEXT: ret void
+;
+ store ptr inttoptr (i64 65 to ptr), ptr %p, align 8
+ ret void
+}
+define void @test_ptrtoint(ptr %p, ptr %x) {
+; CHECK-LABEL: define void @test_ptrtoint(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: store ptr [[X]], ptr [[P]], align 8
+; CHECK-NEXT: ret void
+;
+ %y = ptrtoint ptr %x to i64
+ store i64 %y, ptr %p, align 8
+ ret void
+}
+define void @test_ptrtoint_multiuse(ptr %p, ptr %x) {
+; CHECK-LABEL: define void @test_ptrtoint_multiuse(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: [[Y:%.*]] = ptrtoint ptr [[X]] to i64
+; CHECK-NEXT: call void @use64(i64 [[Y]])
+; CHECK-NEXT: store ptr [[X]], ptr [[P]], align 8
+; CHECK-NEXT: ret void
+;
+ %y = ptrtoint ptr %x to i64
+ call void @use64(i64 %y)
+ store i64 %y, ptr %p, align 8
+ ret void
+}
+; Negative tests
+define void @test_inttoptr_mismatched_size(ptr %p, i32 %x) {
+; CHECK-LABEL: define void @test_inttoptr_mismatched_size(
+; CHECK-SAME: ptr [[P:%.*]], i32 [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[X]] to i64
+; CHECK-NEXT: store i64 [[TMP1]], ptr [[P]], align 8
+; CHECK-NEXT: ret void
+;
+ %y = inttoptr i32 %x to ptr
+ store ptr %y, ptr %p, align 8
+ ret void
+}
+define void @test_ptrtoint_mismatched_size(ptr %p, ptr %x) {
+; CHECK-LABEL: define void @test_ptrtoint_mismatched_size(
+; CHECK-SAME: ptr [[P:%.*]], ptr [[X:%.*]]) {
+; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[X]] to i64
+; CHECK-NEXT: [[Y:%.*]] = trunc i64 [[TMP1]] to i32
+; CHECK-NEXT: store i32 [[Y]], ptr [[P]], align 4
+; CHECK-NEXT: ret void
+;
+ %y = ptrtoint ptr %x to i32
+ store i32 %y, ptr %p, align 4
+ ret void
+}
|
This looks like the store variant of the load fold we explicitly removed in 544a6aa. Generally we don't want to introduce type-punning between pointers and integers, as the semantics are very unclear (but it's very likely that at least one of these transforms is unsound). |
Thank you for the explanation! |
This patch folds away the
inttoptr/ptrtoint
of the stored value by storing the original type. It will enable more optimizations.An example in z3/src/smt/smt_enode.h: