[llvm] [InstCombine] Canonicalize the stored value type with inttoptr/ptrtoint (PR #76339)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Dec 24 12:25:34 PST 2023


https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/76339

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](https://github.com/Z3Prover/z3/blob/ebe5ebf0ae63bf520839b4d34d7b19e0af87fe36/src/smt/smt_enode.h#L41):
```
diff --git a/bench/z3/optimized/smt_enode.cpp.ll b/bench/z3/optimized/smt_enode.cpp.ll
index 6f42a9f4..91bc9b0e 100644
--- a/bench/z3/optimized/smt_enode.cpp.ll
+++ b/bench/z3/optimized/smt_enode.cpp.ll
@@ -4,12 +4,12 @@ target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:
 target triple = "x86_64-unknown-linux-gnu"
 
 %"class.std::ios_base::Init" = type { i8 }
-%"class.smt::eq_justification" = type { ptr }
 %"class.smt::enode" = type { ptr, ptr, ptr, ptr, i32, i32, i32, i16, i32, i8, i8, %class.ptr_vector, %class.id_var_list, %"struct.smt::trans_justification", %class.approx_set, %class.approx_set, [0 x ptr] }
 %class.ptr_vector = type { %class.vector }
 %class.vector = type { ptr }
 %class.id_var_list = type { i32, ptr }
 %"struct.smt::trans_justification" = type { ptr, %"class.smt::eq_justification" }
+%"class.smt::eq_justification" = type { ptr }
 %class.approx_set = type { %class.approx_set_tpl }
 %class.approx_set_tpl = type { i64 }
 %class.ast = type { i32, i24, i32, i32 }
@@ -454,7 +454,7 @@ $_ZTI11value_trailI10approx_setE = comdat any
 
 @_ZStL8__ioinit = internal global %"class.std::ios_base::Init" zeroinitializer, align 1
 @__dso_handle = external hidden global i8
- at _ZN3smtL21null_eq_justificationE = internal unnamed_addr global %"class.smt::eq_justification" zeroinitializer, align 8
+ at _ZN3smtL21null_eq_justificationE.0 = internal unnamed_addr global i1 false, align 8
 @.str = private unnamed_addr constant [2 x i8] c"#\00", align 1
 @.str.7 = private unnamed_addr constant [8 x i8] c"  ->  #\00", align 1
 @.str.8 = private unnamed_addr constant [9 x i8] c", lbls: \00", align 1
@@ -504,7 +504,8 @@ entry:
   %m_next.i.i = getelementptr inbounds %"class.smt::enode", ptr %mem, i64 0, i32 12, i32 1
   %m_justification.i.i = getelementptr inbounds %"class.smt::enode", ptr %mem, i64 0, i32 13, i32 1
   tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %m_next.i.i, i8 0, i64 16, i1 false)
-  %0 = load i64, ptr @_ZN3smtL21null_eq_justificationE, align 8
+  %.b = load i1, ptr @_ZN3smtL21null_eq_justificationE.0, align 8
+  %0 = select i1 %.b, i64 3, i64 0
   store i64 %0, ptr %m_justification.i.i, align 8
   %m_lbls.i = getelementptr inbounds %"class.smt::enode", ptr %mem, i64 0, i32 14
   tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 8 dereferenceable(16) %m_lbls.i, i8 0, i64 16, i1 false)
@@ -2125,7 +2126,7 @@ define internal void @_GLOBAL__sub_I_smt_enode.cpp() #17 section ".text.startup"
 entry:
   tail call void @_ZNSt8ios_base4InitC1Ev(ptr noundef nonnull align 1 dereferenceable(1) @_ZStL8__ioinit)
   %0 = tail call i32 @__cxa_atexit(ptr nonnull @_ZNSt8ios_base4InitD1Ev, ptr nonnull @_ZStL8__ioinit, ptr nonnull @__dso_handle) #20
-  store ptr inttoptr (i64 3 to ptr), ptr @_ZN3smtL21null_eq_justificationE, align 8
+  store i1 true, ptr @_ZN3smtL21null_eq_justificationE.0, align 8
   ret void
 }
```


>From d23a410849755cc947bdc9b5ba081e2e7ef698b1 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 25 Dec 2023 03:55:52 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.

---
 .../InstCombine/store-inttoptr-ptrtoint.ll    | 89 +++++++++++++++++++
 1 file changed, 89 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll

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..7ba36953f2808d
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll
@@ -0,0 +1,89 @@
+; 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:    [[Y:%.*]] = inttoptr i64 [[X]] to ptr
+; CHECK-NEXT:    store ptr [[Y]], 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 ptr [[Y]], 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 ptr inttoptr (i64 65 to ptr), 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:    [[Y:%.*]] = ptrtoint ptr [[X]] to i64
+; CHECK-NEXT:    store i64 [[Y]], 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 i64 [[Y]], 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:    [[Y:%.*]] = inttoptr i64 [[TMP1]] to ptr
+; CHECK-NEXT:    store ptr [[Y]], 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
+}

>From 58ea7c4850821984e9ff3dc68442dfd228038ec8 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 25 Dec 2023 03:57:29 +0800
Subject: [PATCH 2/2] [InstCombine] Canonicalize the stored value type with
 inttoptr/ptrtoint

---
 .../InstCombine/InstCombineLoadStoreAlloca.cpp    | 14 ++++++++++++++
 .../InstCombine/store-inttoptr-ptrtoint.ll        | 15 ++++++---------
 2 files changed, 20 insertions(+), 9 deletions(-)

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
index 7ba36953f2808d..8336f5eccd3841 100644
--- a/llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll
+++ b/llvm/test/Transforms/InstCombine/store-inttoptr-ptrtoint.ll
@@ -8,8 +8,7 @@ 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:    [[Y:%.*]] = inttoptr i64 [[X]] to ptr
-; CHECK-NEXT:    store ptr [[Y]], ptr [[P]], align 8
+; CHECK-NEXT:    store i64 [[X]], ptr [[P]], align 8
 ; CHECK-NEXT:    ret void
 ;
   %y = inttoptr i64 %x to ptr
@@ -21,7 +20,7 @@ define void @test_inttoptr_multiuse(ptr %p, i64 %x) {
 ; CHECK-SAME: ptr [[P:%.*]], i64 [[X:%.*]]) {
 ; CHECK-NEXT:    [[Y:%.*]] = inttoptr i64 [[X]] to ptr
 ; CHECK-NEXT:    call void @useptr(ptr [[Y]])
-; CHECK-NEXT:    store ptr [[Y]], ptr [[P]], align 8
+; CHECK-NEXT:    store i64 [[X]], ptr [[P]], align 8
 ; CHECK-NEXT:    ret void
 ;
   %y = inttoptr i64 %x to ptr
@@ -32,7 +31,7 @@ define void @test_inttoptr_multiuse(ptr %p, i64 %x) {
 define void @test_inttoptr_constant_expr(ptr %p) {
 ; CHECK-LABEL: define void @test_inttoptr_constant_expr(
 ; CHECK-SAME: ptr [[P:%.*]]) {
-; CHECK-NEXT:    store ptr inttoptr (i64 65 to ptr), ptr [[P]], align 8
+; CHECK-NEXT:    store i64 65, ptr [[P]], align 8
 ; CHECK-NEXT:    ret void
 ;
   store ptr inttoptr (i64 65 to ptr), ptr %p, align 8
@@ -41,8 +40,7 @@ define void @test_inttoptr_constant_expr(ptr %p) {
 define void @test_ptrtoint(ptr %p, ptr %x) {
 ; CHECK-LABEL: define void @test_ptrtoint(
 ; CHECK-SAME: ptr [[P:%.*]], ptr [[X:%.*]]) {
-; CHECK-NEXT:    [[Y:%.*]] = ptrtoint ptr [[X]] to i64
-; CHECK-NEXT:    store i64 [[Y]], ptr [[P]], align 8
+; CHECK-NEXT:    store ptr [[X]], ptr [[P]], align 8
 ; CHECK-NEXT:    ret void
 ;
   %y = ptrtoint ptr %x to i64
@@ -54,7 +52,7 @@ define void @test_ptrtoint_multiuse(ptr %p, ptr %x) {
 ; CHECK-SAME: ptr [[P:%.*]], ptr [[X:%.*]]) {
 ; CHECK-NEXT:    [[Y:%.*]] = ptrtoint ptr [[X]] to i64
 ; CHECK-NEXT:    call void @use64(i64 [[Y]])
-; CHECK-NEXT:    store i64 [[Y]], ptr [[P]], align 8
+; CHECK-NEXT:    store ptr [[X]], ptr [[P]], align 8
 ; CHECK-NEXT:    ret void
 ;
   %y = ptrtoint ptr %x to i64
@@ -67,8 +65,7 @@ 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:    [[Y:%.*]] = inttoptr i64 [[TMP1]] to ptr
-; CHECK-NEXT:    store ptr [[Y]], ptr [[P]], align 8
+; CHECK-NEXT:    store i64 [[TMP1]], ptr [[P]], align 8
 ; CHECK-NEXT:    ret void
 ;
   %y = inttoptr i32 %x to ptr



More information about the llvm-commits mailing list