[llvm] [CodeGenPrepare] Handle address sinking obtained from invoke (PR #143566)

Evgenii Kudriashov via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 13 10:19:28 PDT 2025


https://github.com/e-kud updated https://github.com/llvm/llvm-project/pull/143566

>From b7f4b17c69c0fd021aea986c3b802d3645c9a1ba Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Tue, 10 Jun 2025 09:00:35 -0700
Subject: [PATCH 1/5] [CodeGenPrepare] Handle address sinking obtained from
 invoke

---
 llvm/lib/CodeGen/CodeGenPrepare.cpp           |  3 +-
 .../CodeGenPrepare/X86/sink-addr-reuse.ll     | 35 +++++++++++++++++++
 2 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 32348a899683d..7529ead8af202 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -5790,7 +5790,8 @@ static BasicBlock::iterator findInsertPos(Value *Addr, Instruction *MemoryInst,
   // instruction after it.
   if (SunkAddr) {
     if (Instruction *AddrInst = dyn_cast<Instruction>(SunkAddr))
-      return std::next(AddrInst->getIterator());
+      return AddrInst->isTerminator() ? MemoryInst->getIterator()
+                                      : std::next(AddrInst->getIterator());
   }
 
   // Find the first user of Addr in current BB.
diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll
index 019f311406550..5f084fc7ea2b5 100644
--- a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll
@@ -42,3 +42,38 @@ bb3:
 bb7:
   ret void
 }
+
+; Test a scenario when the address is the last instruction in the basic block.
+
+define void @adress_terminator() personality ptr null {
+; CHECK-LABEL: define void @adress_terminator() personality ptr null {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[PTR:%.*]] = invoke ptr null(i64 0)
+; CHECK-NEXT:            to label %[[BODY_1:.*]] unwind label %[[EHCLEANUP:.*]]
+; CHECK:       [[EHCLEANUP]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = cleanuppad within none []
+; CHECK-NEXT:    cleanupret from [[TMP0]] unwind to caller
+; CHECK:       [[BODY_1]]:
+; CHECK-NEXT:    [[TMP1:%.*]] = bitcast ptr [[PTR]] to ptr
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP1]], align 4
+; CHECK-NEXT:    [[V0:%.*]] = load <4 x i32>, ptr [[PTR]], align 4
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[PTR]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %ptr = invoke ptr null(i64 0) to label %body.1 unwind label %ehcleanup
+
+body.2:
+  %v0 = load <4 x i32>, ptr %2, align 4
+  store <4 x i32> zeroinitializer, ptr %2, align 4
+  ret void
+
+ehcleanup:
+  %1 = cleanuppad within none []
+  cleanupret from %1 unwind to caller
+
+body.1:
+  %2 = getelementptr { i32 }, ptr %ptr, i64 0, i32 0
+  store <4 x i32> zeroinitializer, ptr %2, align 4
+  br label %body.2
+}

>From 8d928bc05274e347b92de88db5f9aeff858dd317 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Wed, 11 Jun 2025 16:50:00 -0700
Subject: [PATCH 2/5] Don't try to sink addresses that we can't recreate

---
 llvm/lib/CodeGen/CodeGenPrepare.cpp           | 10 ++++-
 .../CodeGenPrepare/X86/sink-addr-recreate.ll  | 42 +++++++++++++++++++
 .../CodeGenPrepare/X86/sink-addr-reuse.ll     | 35 ----------------
 3 files changed, 50 insertions(+), 37 deletions(-)
 create mode 100644 llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll

diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 7529ead8af202..a3b7e09156b85 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -5790,8 +5790,7 @@ static BasicBlock::iterator findInsertPos(Value *Addr, Instruction *MemoryInst,
   // instruction after it.
   if (SunkAddr) {
     if (Instruction *AddrInst = dyn_cast<Instruction>(SunkAddr))
-      return AddrInst->isTerminator() ? MemoryInst->getIterator()
-                                      : std::next(AddrInst->getIterator());
+      return std::next(AddrInst->getIterator());
   }
 
   // Find the first user of Addr in current BB.
@@ -6100,6 +6099,13 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
       }
 
       if (!ResultIndex) {
+        auto PtrInst = dyn_cast<Instruction>(ResultPtr);
+        // Here we know that we have just a pointer without any offsets.  If
+        // this pointer comes from a different from the current basic block we
+        // need to know how to recreate it in another basic block.
+        // Currently we don't support recreation of any of instruction.
+        if (PtrInst && PtrInst->getParent() != MemoryInst->getParent())
+          return Modified;
         SunkAddr = ResultPtr;
       } else {
         if (ResultPtr->getType() != I8PtrTy)
diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
new file mode 100644
index 0000000000000..2cb92d413c5ff
--- /dev/null
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -p 'require<profile-summary>,codegenprepare' -cgpp-huge-func=0 < %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"
+target triple = "x86_64-grtev4-linux-gnu"
+
+; Test a scenario when the address cannot be recreated in the current basic block
+
+declare ptr @get_ptr(i64)
+define void @address_terminator() personality ptr null {
+; CHECK-LABEL: define void @address_terminator() personality ptr null {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[PTR:%.*]] = invoke ptr @get_ptr(i64 0)
+; CHECK-NEXT:            to label %[[BODY_1:.*]] unwind label %[[EHCLEANUP:.*]]
+; CHECK:       [[EHCLEANUP]]:
+; CHECK-NEXT:    [[PAD:%.*]] = cleanuppad within none []
+; CHECK-NEXT:    cleanupret from [[PAD]] unwind to caller
+; CHECK:       [[BODY_1]]:
+; CHECK-NEXT:    [[GEP1:%.*]] = bitcast ptr [[PTR]] to ptr
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[GEP1]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = bitcast ptr [[PTR]] to ptr
+; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr [[TMP0]], align 4
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP0]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %ptr = invoke ptr @get_ptr(i64 0) to label %body.1 unwind label %ehcleanup
+
+body.2:
+  %unused = load <4 x i32>, ptr %gep, align 4
+  store <4 x i32> zeroinitializer, ptr %gep, align 4
+  ret void
+
+ehcleanup:
+  %pad = cleanuppad within none []
+  cleanupret from %pad unwind to caller
+
+body.1:
+  %gep = getelementptr { i32 }, ptr %ptr, i64 0, i32 0
+  store <4 x i32> zeroinitializer, ptr %gep, align 4
+  br label %body.2
+}
diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll
index 5f084fc7ea2b5..019f311406550 100644
--- a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-reuse.ll
@@ -42,38 +42,3 @@ bb3:
 bb7:
   ret void
 }
-
-; Test a scenario when the address is the last instruction in the basic block.
-
-define void @adress_terminator() personality ptr null {
-; CHECK-LABEL: define void @adress_terminator() personality ptr null {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[PTR:%.*]] = invoke ptr null(i64 0)
-; CHECK-NEXT:            to label %[[BODY_1:.*]] unwind label %[[EHCLEANUP:.*]]
-; CHECK:       [[EHCLEANUP]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = cleanuppad within none []
-; CHECK-NEXT:    cleanupret from [[TMP0]] unwind to caller
-; CHECK:       [[BODY_1]]:
-; CHECK-NEXT:    [[TMP1:%.*]] = bitcast ptr [[PTR]] to ptr
-; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP1]], align 4
-; CHECK-NEXT:    [[V0:%.*]] = load <4 x i32>, ptr [[PTR]], align 4
-; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[PTR]], align 4
-; CHECK-NEXT:    ret void
-;
-entry:
-  %ptr = invoke ptr null(i64 0) to label %body.1 unwind label %ehcleanup
-
-body.2:
-  %v0 = load <4 x i32>, ptr %2, align 4
-  store <4 x i32> zeroinitializer, ptr %2, align 4
-  ret void
-
-ehcleanup:
-  %1 = cleanuppad within none []
-  cleanupret from %1 unwind to caller
-
-body.1:
-  %2 = getelementptr { i32 }, ptr %ptr, i64 0, i32 0
-  store <4 x i32> zeroinitializer, ptr %2, align 4
-  br label %body.2
-}

>From 0c804d3d8b06b4ff03c03f577397f3f32d70947b Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Wed, 11 Jun 2025 16:56:35 -0700
Subject: [PATCH 3/5] Rename the test

---
 llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
index 2cb92d413c5ff..3cd5a9b161624 100644
--- a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
@@ -7,8 +7,8 @@ target triple = "x86_64-grtev4-linux-gnu"
 ; Test a scenario when the address cannot be recreated in the current basic block
 
 declare ptr @get_ptr(i64)
-define void @address_terminator() personality ptr null {
-; CHECK-LABEL: define void @address_terminator() personality ptr null {
+define void @addr_from_invoke() personality ptr null {
+; CHECK-LABEL: define void @addr_from_invoke() personality ptr null {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
 ; CHECK-NEXT:    [[PTR:%.*]] = invoke ptr @get_ptr(i64 0)
 ; CHECK-NEXT:            to label %[[BODY_1:.*]] unwind label %[[EHCLEANUP:.*]]

>From a5b5b9abcb61e02901355d0dd33dee569c948506 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Fri, 13 Jun 2025 08:41:21 -0700
Subject: [PATCH 4/5] Add tests for args and globals

---
 .../CodeGenPrepare/X86/sink-addr-recreate.ll  | 68 ++++++++++++++++++-
 1 file changed, 66 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
index 3cd5a9b161624..3c87396168e0a 100644
--- a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
@@ -4,9 +4,11 @@
 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"
 target triple = "x86_64-grtev4-linux-gnu"
 
-; Test a scenario when the address cannot be recreated in the current basic block
-
+ at globalptr = external global ptr
 declare ptr @get_ptr(i64)
+
+; Can't recreate invoke instruction
+
 define void @addr_from_invoke() personality ptr null {
 ; CHECK-LABEL: define void @addr_from_invoke() personality ptr null {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
@@ -40,3 +42,65 @@ body.1:
   store <4 x i32> zeroinitializer, ptr %gep, align 4
   br label %body.2
 }
+
+define void @addr_from_arg(ptr %ptr, i1 %p) {
+; CHECK-LABEL: define void @addr_from_arg(
+; CHECK-SAME: ptr [[PTR:%.*]], i1 [[P:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br i1 [[P]], label %[[BODY_1:.*]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[BODY_1]]:
+; CHECK-NEXT:    [[SUNKADDR:%.*]] = bitcast ptr [[PTR]] to ptr
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[SUNKADDR]], align 4
+; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr [[PTR]], align 4
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[PTR]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 %p, label %body.1, label %exit
+
+body.2:
+  %unused = load <4 x i32>, ptr %gep, align 4
+  store <4 x i32> zeroinitializer, ptr %gep, align 4
+  ret void
+
+exit:
+  ret void
+
+body.1:
+  %gep = getelementptr { i32 }, ptr %ptr, i64 0, i32 0
+  store <4 x i32> zeroinitializer, ptr %gep, align 4
+  br label %body.2
+}
+
+define void @addr_from_global(i1 %p) {
+; CHECK-LABEL: define void @addr_from_global(
+; CHECK-SAME: i1 [[P:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    br i1 [[P]], label %[[BODY_1:.*]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+; CHECK:       [[BODY_1]]:
+; CHECK-NEXT:    [[GEP1:%.*]] = bitcast ptr @globalptr to ptr
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[GEP1]], align 4
+; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr @globalptr, align 4
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr @globalptr, align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  br i1 %p, label %body.1, label %exit
+
+body.2:
+  %unused = load <4 x i32>, ptr %gep, align 4
+  store <4 x i32> zeroinitializer, ptr %gep, align 4
+  ret void
+
+exit:
+  ret void
+
+body.1:
+  %gep = getelementptr { i32 }, ptr @globalptr, i64 0, i32 0
+  store <4 x i32> zeroinitializer, ptr %gep, align 4
+  br label %body.2
+}

>From 81ddd177f0723f9316030788309a8ac6b1bdbbcb Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Fri, 13 Jun 2025 08:48:01 -0700
Subject: [PATCH 5/5] Skip anything that is not an instruction from current
 basic block

---
 llvm/lib/CodeGen/CodeGenPrepare.cpp                    | 10 +++++-----
 .../CodeGenPrepare/X86/sink-addr-recreate.ll           |  9 +++++----
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index a3b7e09156b85..1a3a5bff984dc 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -6100,11 +6100,11 @@ bool CodeGenPrepare::optimizeMemoryInst(Instruction *MemoryInst, Value *Addr,
 
       if (!ResultIndex) {
         auto PtrInst = dyn_cast<Instruction>(ResultPtr);
-        // Here we know that we have just a pointer without any offsets.  If
-        // this pointer comes from a different from the current basic block we
-        // need to know how to recreate it in another basic block.
-        // Currently we don't support recreation of any of instruction.
-        if (PtrInst && PtrInst->getParent() != MemoryInst->getParent())
+        // We know that we have a pointer without any offsets. If this pointer
+        // originates from a different basic block than the current one, we
+        // must be able to recreate it in the current basic block.
+        // We do not support the recreation of any instructions yet.
+        if (!PtrInst || PtrInst->getParent() != MemoryInst->getParent())
           return Modified;
         SunkAddr = ResultPtr;
       } else {
diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
index 3c87396168e0a..af801a7a7a3f9 100644
--- a/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/sink-addr-recreate.ll
@@ -53,8 +53,9 @@ define void @addr_from_arg(ptr %ptr, i1 %p) {
 ; CHECK:       [[BODY_1]]:
 ; CHECK-NEXT:    [[SUNKADDR:%.*]] = bitcast ptr [[PTR]] to ptr
 ; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[SUNKADDR]], align 4
-; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr [[PTR]], align 4
-; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[PTR]], align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = bitcast ptr [[PTR]] to ptr
+; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr [[TMP0]], align 4
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[TMP0]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -84,8 +85,8 @@ define void @addr_from_global(i1 %p) {
 ; CHECK:       [[BODY_1]]:
 ; CHECK-NEXT:    [[GEP1:%.*]] = bitcast ptr @globalptr to ptr
 ; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[GEP1]], align 4
-; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr @globalptr, align 4
-; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr @globalptr, align 4
+; CHECK-NEXT:    [[UNUSED:%.*]] = load <4 x i32>, ptr [[GEP1]], align 4
+; CHECK-NEXT:    store <4 x i32> zeroinitializer, ptr [[GEP1]], align 4
 ; CHECK-NEXT:    ret void
 ;
 entry:



More information about the llvm-commits mailing list