[llvm] [LoongArch] Introduce PseudoAddUpperImm to deduplicate stack-frame base address materialization (PR #217250)

via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 19 02:27:01 PDT 2026


https://github.com/lrzlin updated https://github.com/llvm/llvm-project/pull/217250

>From 8e414afe218d38ffcee2d14f0a87e641b60a2277 Mon Sep 17 00:00:00 2001
From: Lin Runze <linrunze at loongson.cn>
Date: Tue, 18 Aug 2026 12:04:28 +0800
Subject: [PATCH 1/2] [LoongArch][NFC] Add tests for large stack-frame base
 address materialization

---
 .../LoongArch/frame-base-dedup-la32.mir       |  98 ++++++
 .../LoongArch/frame-base-dedup-la64.mir       | 291 ++++++++++++++++++
 2 files changed, 389 insertions(+)
 create mode 100644 llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir
 create mode 100644 llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir

diff --git a/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir
new file mode 100644
index 0000000000000..5ec561aa754cc
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir
@@ -0,0 +1,98 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=loongarch32 \
+# RUN:   -run-pass=prolog-epilog -run-pass=machine-latecleanup -o - %s \
+# RUN:   | FileCheck -check-prefix=LA32 %s
+# RUN: llc -mtriple=loongarch32 \
+# RUN:   -run-pass=prolog-epilog -run-pass=machine-latecleanup \
+# RUN:   -run-pass=loongarch-expand-pseudo -o - %s \
+# RUN:   | FileCheck -check-prefix=LA32-EXPAND %s
+#
+# Test that identical large stack-frame base address materializations are
+# deduplicated by MachineLateInstrsCleanup via PseudoAddUpperImm.
+
+--- |
+  define void @test_la32() nounwind { ret void }
+...
+---
+# LA32 -- verify with 32-bit loads/stores, and that the pseudo expands to
+# LU12I_W + ADD_W rather than ADD_D.
+#
+# Frame: 4 + 4 + 16384 + 4 (spill slot) = 16396 -> 16400.
+#   %stack.0 -> 16400 - 4 = 16396 = (4 << 12) + 12
+#   %stack.1 -> 16400 - 8 = 16392 = (4 << 12) +  8
+name: test_la32
+alignment: 4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment: 4
+  hasCalls: false
+  maxCallFrameSize: 0
+stack:
+  - { id: 0, size: 4, alignment: 4 }
+  - { id: 1, size: 4, alignment: 4 }
+  - { id: 2, size: 16384, alignment: 4 }
+body: |
+  bb.0:
+    liveins: $r4, $r5
+    ; LA32-LABEL: name: test_la32
+    ; LA32: liveins: $r4, $r5
+    ; LA32-NEXT: {{  $}}
+    ; LA32-NEXT: $r6 = frame-setup LU12I_W 4
+    ; LA32-NEXT: $r6 = frame-setup ORI killed $r6, 16
+    ; LA32-NEXT: $r3 = frame-setup SUB_W $r3, killed $r6
+    ; LA32-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16400
+    ; LA32-NEXT: $r6 = LU12I_W 4
+    ; LA32-NEXT: $r6 = ORI killed $r6, 12
+    ; LA32-NEXT: $r6 = ADD_W $r3, killed $r6
+    ; LA32-NEXT: ST_W $r4, killed $r6, 0 :: (store (s32))
+    ; LA32-NEXT: $r4 = LU12I_W 4
+    ; LA32-NEXT: $r4 = ORI killed $r4, 8
+    ; LA32-NEXT: $r4 = ADD_W $r3, killed $r4
+    ; LA32-NEXT: ST_W $r5, killed $r4, 0 :: (store (s32))
+    ; LA32-NEXT: $r4 = LU12I_W 4
+    ; LA32-NEXT: $r4 = ORI killed $r4, 12
+    ; LA32-NEXT: $r4 = ADD_W $r3, killed $r4
+    ; LA32-NEXT: $r6 = LD_W killed $r4, 0 :: (load (s32))
+    ; LA32-NEXT: $r4 = LU12I_W 4
+    ; LA32-NEXT: $r4 = ORI killed $r4, 8
+    ; LA32-NEXT: $r4 = ADD_W $r3, killed $r4
+    ; LA32-NEXT: $r7 = LD_W killed $r4, 0 :: (load (s32))
+    ; LA32-NEXT: $r4 = frame-destroy LU12I_W 4
+    ; LA32-NEXT: $r4 = frame-destroy ORI killed $r4, 16
+    ; LA32-NEXT: $r3 = frame-destroy ADD_W $r3, killed $r4
+    ; LA32-NEXT: PseudoRET
+    ;
+    ; LA32-EXPAND-LABEL: name: test_la32
+    ; LA32-EXPAND: liveins: $r4, $r5
+    ; LA32-EXPAND-NEXT: {{  $}}
+    ; LA32-EXPAND-NEXT: $r6 = frame-setup LU12I_W 4
+    ; LA32-EXPAND-NEXT: $r6 = frame-setup ORI killed $r6, 16
+    ; LA32-EXPAND-NEXT: $r3 = frame-setup SUB_W $r3, killed $r6
+    ; LA32-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16400
+    ; LA32-EXPAND-NEXT: $r6 = LU12I_W 4
+    ; LA32-EXPAND-NEXT: $r6 = ORI killed $r6, 12
+    ; LA32-EXPAND-NEXT: $r6 = ADD_W $r3, killed $r6
+    ; LA32-EXPAND-NEXT: ST_W $r4, killed $r6, 0 :: (store (s32))
+    ; LA32-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA32-EXPAND-NEXT: $r4 = ORI killed $r4, 8
+    ; LA32-EXPAND-NEXT: $r4 = ADD_W $r3, killed $r4
+    ; LA32-EXPAND-NEXT: ST_W $r5, killed $r4, 0 :: (store (s32))
+    ; LA32-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA32-EXPAND-NEXT: $r4 = ORI killed $r4, 12
+    ; LA32-EXPAND-NEXT: $r4 = ADD_W $r3, killed $r4
+    ; LA32-EXPAND-NEXT: $r6 = LD_W killed $r4, 0 :: (load (s32))
+    ; LA32-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA32-EXPAND-NEXT: $r4 = ORI killed $r4, 8
+    ; LA32-EXPAND-NEXT: $r4 = ADD_W $r3, killed $r4
+    ; LA32-EXPAND-NEXT: $r7 = LD_W killed $r4, 0 :: (load (s32))
+    ; LA32-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 4
+    ; LA32-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 16
+    ; LA32-EXPAND-NEXT: $r3 = frame-destroy ADD_W $r3, killed $r4
+    ; LA32-EXPAND-NEXT: PseudoRET
+    ST_W $r4, %stack.0, 0 :: (store (s32))
+    ST_W $r5, %stack.1, 0 :: (store (s32))
+    $r6 = LD_W %stack.0, 0 :: (load (s32))
+    $r7 = LD_W %stack.1, 0 :: (load (s32))
+    PseudoRET
+...
+
diff --git a/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir
new file mode 100644
index 0000000000000..09e1447137f27
--- /dev/null
+++ b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir
@@ -0,0 +1,291 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+# RUN: llc -mtriple=loongarch64 \
+# RUN:   -run-pass=prolog-epilog -run-pass=machine-latecleanup -o - %s \
+# RUN:   | FileCheck -check-prefix=LA64 %s
+# RUN: llc -mtriple=loongarch64 \
+# RUN:   -run-pass=prolog-epilog -run-pass=machine-latecleanup \
+# RUN:   -run-pass=loongarch-expand-pseudo -o - %s \
+# RUN:   | FileCheck -check-prefix=LA64-EXPAND %s
+#
+# Test that identical large stack-frame base address materializations are
+# deduplicated by MachineLateInstrsCleanup via PseudoAddUpperImm.
+
+--- |
+  define void @test_same_region() nounwind { ret void }
+  define void @test_different_regions() nounwind { ret void }
+  define void @test_negative_lo12() nounwind { ret void }
+  define void @test_small_offset_no_pseudo() nounwind { ret void }
+...
+---
+# Multiple accesses to stack slots in the same 4096-aligned region.
+# PEI emits 4 PseudoAddUpperImm, MachineLateInstrsCleanup CSEs to 2.
+# After expansion, only 2 LU12I_W + ADD_D pairs remain instead of 4.
+#
+# Frame: 8 + 8 + 16384 + 8 (emergency spill slot) = 16408, rounded up to the
+# 16-byte stack alignment -> 16416.
+#   %stack.0 -> 16416 -  8 = 16408 = (4 << 12) + 24
+#   %stack.1 -> 16416 - 16 = 16400 = (4 << 12) + 16
+name: test_same_region
+alignment: 4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment: 8
+  hasCalls: false
+  maxCallFrameSize: 0
+stack:
+  - { id: 0, size: 8, alignment: 8 }
+  - { id: 1, size: 8, alignment: 8 }
+  - { id: 2, size: 16384, alignment: 8 }
+body: |
+  bb.0:
+    liveins: $r4, $r5
+    ; LA64-LABEL: name: test_same_region
+    ; LA64: liveins: $r4, $r5
+    ; LA64-NEXT: {{  $}}
+    ; LA64-NEXT: $r6 = frame-setup LU12I_W 4
+    ; LA64-NEXT: $r6 = frame-setup ORI killed $r6, 32
+    ; LA64-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
+    ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16416
+    ; LA64-NEXT: $r6 = LU12I_W 4
+    ; LA64-NEXT: $r6 = ORI killed $r6, 24
+    ; LA64-NEXT: $r6 = ADD_D $r3, killed $r6
+    ; LA64-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 16
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 24
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 16
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-NEXT: $r4 = frame-destroy LU12I_W 4
+    ; LA64-NEXT: $r4 = frame-destroy ORI killed $r4, 32
+    ; LA64-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
+    ; LA64-NEXT: PseudoRET
+    ;
+    ; LA64-EXPAND-LABEL: name: test_same_region
+    ; LA64-EXPAND: liveins: $r4, $r5
+    ; LA64-EXPAND-NEXT: {{  $}}
+    ; LA64-EXPAND-NEXT: $r6 = frame-setup LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r6 = frame-setup ORI killed $r6, 32
+    ; LA64-EXPAND-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
+    ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16416
+    ; LA64-EXPAND-NEXT: $r6 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r6 = ORI killed $r6, 24
+    ; LA64-EXPAND-NEXT: $r6 = ADD_D $r3, killed $r6
+    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 16
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 24
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 16
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 32
+    ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: PseudoRET
+    ST_D $r4, %stack.0, 0 :: (store (s64))
+    ST_D $r5, %stack.1, 0 :: (store (s64))
+    $r6 = LD_D %stack.0, 0 :: (load (s64))
+    $r7 = LD_D %stack.1, 0 :: (load (s64))
+    PseudoRET
+...
+---
+# Accesses to stack slots in different 4096-aligned regions.
+# Different base anchors cannot be CSE'd with each other.
+#
+# Frame: 8 + 4096 + 8 + 16384 + 8 (spill slot) = 20504 -> 20512.
+#   %stack.0 -> 20512 -    8 = 20504 = (5 << 12) + 24
+#   %stack.2 -> 20512 - 4112 = 16400 = (4 << 12) + 16
+name: test_different_regions
+alignment: 4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment: 8
+  hasCalls: false
+  maxCallFrameSize: 0
+stack:
+  - { id: 0, size: 8, alignment: 8 }
+  - { id: 1, size: 4096, alignment: 8 }
+  - { id: 2, size: 8, alignment: 8 }
+  - { id: 3, size: 16384, alignment: 8 }
+body: |
+  bb.0:
+    liveins: $r4, $r5
+    ; LA64-LABEL: name: test_different_regions
+    ; LA64: liveins: $r4, $r5
+    ; LA64-NEXT: {{  $}}
+    ; LA64-NEXT: $r6 = frame-setup LU12I_W 5
+    ; LA64-NEXT: $r6 = frame-setup ORI killed $r6, 32
+    ; LA64-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
+    ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 20512
+    ; LA64-NEXT: $r6 = LU12I_W 5
+    ; LA64-NEXT: $r6 = ORI killed $r6, 24
+    ; LA64-NEXT: $r6 = ADD_D $r3, killed $r6
+    ; LA64-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 16
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-NEXT: $r4 = frame-destroy LU12I_W 5
+    ; LA64-NEXT: $r4 = frame-destroy ORI killed $r4, 32
+    ; LA64-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
+    ; LA64-NEXT: PseudoRET
+    ;
+    ; LA64-EXPAND-LABEL: name: test_different_regions
+    ; LA64-EXPAND: liveins: $r4, $r5
+    ; LA64-EXPAND-NEXT: {{  $}}
+    ; LA64-EXPAND-NEXT: $r6 = frame-setup LU12I_W 5
+    ; LA64-EXPAND-NEXT: $r6 = frame-setup ORI killed $r6, 32
+    ; LA64-EXPAND-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
+    ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 20512
+    ; LA64-EXPAND-NEXT: $r6 = LU12I_W 5
+    ; LA64-EXPAND-NEXT: $r6 = ORI killed $r6, 24
+    ; LA64-EXPAND-NEXT: $r6 = ADD_D $r3, killed $r6
+    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 16
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 5
+    ; LA64-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 32
+    ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: PseudoRET
+    ST_D $r4, %stack.0, 0 :: (store (s64))
+    ST_D $r5, %stack.2, 0 :: (store (s64))
+    PseudoRET
+...
+---
+# The lower 12 bits are folded into the ld/st with a negative si12, so the
+# upper immediate must carry a +1 with respect to a plain arithmetic shift
+# of the full offset. This is the case that a `Val >> 12` (instead of
+# `(Val - Lo12) >> 12`) gets wrong by exactly 4096 bytes.
+#
+# Frame: 8 + 8 + 18432 + 8 (spill slot) = 18456 -> 18464.
+#   %stack.0 -> 18464 -  8 = 18456 = (5 << 12) - 2024
+#   %stack.1 -> 18464 - 16 = 18448 = (5 << 12) - 2032
+name: test_negative_lo12
+alignment: 4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment: 8
+  hasCalls: false
+  maxCallFrameSize: 0
+stack:
+  - { id: 0, size: 8, alignment: 8 }
+  - { id: 1, size: 8, alignment: 8 }
+  - { id: 2, size: 18432, alignment: 8 }
+body: |
+  bb.0:
+    liveins: $r4, $r5
+    ; LA64-LABEL: name: test_negative_lo12
+    ; LA64: liveins: $r4, $r5
+    ; LA64-NEXT: {{  $}}
+    ; LA64-NEXT: $r6 = frame-setup LU12I_W 4
+    ; LA64-NEXT: $r6 = frame-setup ORI killed $r6, 2080
+    ; LA64-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
+    ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 18464
+    ; LA64-NEXT: $r6 = LU12I_W 4
+    ; LA64-NEXT: $r6 = ORI killed $r6, 2072
+    ; LA64-NEXT: $r6 = ADD_D $r3, killed $r6
+    ; LA64-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 2064
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 2072
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-NEXT: $r4 = LU12I_W 4
+    ; LA64-NEXT: $r4 = ORI killed $r4, 2064
+    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-NEXT: $r4 = frame-destroy LU12I_W 4
+    ; LA64-NEXT: $r4 = frame-destroy ORI killed $r4, 2080
+    ; LA64-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
+    ; LA64-NEXT: PseudoRET
+    ;
+    ; LA64-EXPAND-LABEL: name: test_negative_lo12
+    ; LA64-EXPAND: liveins: $r4, $r5
+    ; LA64-EXPAND-NEXT: {{  $}}
+    ; LA64-EXPAND-NEXT: $r6 = frame-setup LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r6 = frame-setup ORI killed $r6, 2080
+    ; LA64-EXPAND-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
+    ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 18464
+    ; LA64-EXPAND-NEXT: $r6 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r6 = ORI killed $r6, 2072
+    ; LA64-EXPAND-NEXT: $r6 = ADD_D $r3, killed $r6
+    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 2064
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 2072
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 2064
+    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 4
+    ; LA64-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 2080
+    ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
+    ; LA64-EXPAND-NEXT: PseudoRET
+    ST_D $r4, %stack.0, 0 :: (store (s64))
+    ST_D $r5, %stack.1, 0 :: (store (s64))
+    $r6 = LD_D %stack.0, 0 :: (load (s64))
+    $r7 = LD_D %stack.1, 0 :: (load (s64))
+    PseudoRET
+...
+---
+# Small stack frame -- offsets fit in 12-bit signed immediate.
+# No PseudoAddUpperImm generated (and no emergency spill slot either).
+name: test_small_offset_no_pseudo
+alignment: 4
+tracksRegLiveness: true
+frameInfo:
+  maxAlignment: 8
+  hasCalls: false
+  maxCallFrameSize: 0
+stack:
+  - { id: 0, size: 8, alignment: 8 }
+  - { id: 1, size: 8, alignment: 8 }
+body: |
+  bb.0:
+    liveins: $r4, $r5
+    ; LA64-LABEL: name: test_small_offset_no_pseudo
+    ; LA64: liveins: $r4, $r5
+    ; LA64-NEXT: {{  $}}
+    ; LA64-NEXT: $r3 = frame-setup ADDI_D $r3, -16
+    ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+    ; LA64-NEXT: ST_D $r4, $r3, 8 :: (store (s64))
+    ; LA64-NEXT: ST_D $r5, $r3, 0 :: (store (s64))
+    ; LA64-NEXT: $r3 = frame-destroy ADDI_D $r3, 16
+    ; LA64-NEXT: PseudoRET
+    ;
+    ; LA64-EXPAND-LABEL: name: test_small_offset_no_pseudo
+    ; LA64-EXPAND: liveins: $r4, $r5
+    ; LA64-EXPAND-NEXT: {{  $}}
+    ; LA64-EXPAND-NEXT: $r3 = frame-setup ADDI_D $r3, -16
+    ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+    ; LA64-EXPAND-NEXT: ST_D $r4, $r3, 8 :: (store (s64))
+    ; LA64-EXPAND-NEXT: ST_D $r5, $r3, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADDI_D $r3, 16
+    ; LA64-EXPAND-NEXT: PseudoRET
+    ST_D $r4, %stack.0, 0 :: (store (s64))
+    ST_D $r5, %stack.1, 0 :: (store (s64))
+    PseudoRET
+...
+

>From 21ce9ca39dbe2cd774196a5d0595278f8b771784 Mon Sep 17 00:00:00 2001
From: Lin Runze <lrzlin at 163.com>
Date: Wed, 12 Aug 2026 17:00:50 +0800
Subject: [PATCH 2/2] [LoongArch] Introduce PseudoAddUpperImm to deduplicate
 stack-frame base address materialization

---
 .../LoongArch/LoongArchExpandPseudoInsts.cpp  | 31 ++++++
 .../Target/LoongArch/LoongArchInstrInfo.td    |  7 ++
 .../LoongArch/LoongArchRegisterInfo.cpp       | 58 +++++++++--
 .../CodeGen/LoongArch/emergency-spill-slot.ll |  3 +-
 .../LoongArch/frame-base-dedup-la32.mir       | 38 ++-----
 .../LoongArch/frame-base-dedup-la64.mir       | 98 ++++++-------------
 .../CodeGen/LoongArch/stack-clash-prologue.ll |  8 +-
 7 files changed, 130 insertions(+), 113 deletions(-)

diff --git a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
index b3167174454a3..0e18669b56e64 100644
--- a/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchExpandPseudoInsts.cpp
@@ -772,6 +772,8 @@ class LoongArchExpandPseudo : public MachineFunctionPass {
                           MachineBasicBlock::iterator MBBI,
                           MachineBasicBlock::iterator &NextMBBI,
                           bool IsTailCall);
+  bool expandAddUpperImm(MachineBasicBlock &MBB,
+                         MachineBasicBlock::iterator MBBI);
 };
 
 char LoongArchExpandPseudo::ID = 0;
@@ -810,6 +812,8 @@ bool LoongArchExpandPseudo::expandMI(MachineBasicBlock &MBB,
     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/false);
   case LoongArch::PseudoTAIL_MEDIUM:
     return expandFunctionCALL(MBB, MBBI, NextMBBI, /*IsTailCall=*/true);
+  case LoongArch::PseudoAddUpperImm:
+    return expandAddUpperImm(MBB, MBBI);
   }
 
   return false;
@@ -927,6 +931,33 @@ bool LoongArchExpandPseudo::expandFunctionCALL(
   return true;
 }
 
+bool LoongArchExpandPseudo::expandAddUpperImm(
+    MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI) {
+  DebugLoc DL = MBBI->getDebugLoc();
+  MachineFunction *MF = MBB.getParent();
+  const auto &STI = MF->getSubtarget<LoongArchSubtarget>();
+
+  Register DstReg = MBBI->getOperand(0).getReg();
+  bool DstIsDead = MBBI->getOperand(0).isDead();
+  bool Renamable = MBBI->getOperand(0).isRenamable();
+  Register BaseReg = MBBI->getOperand(1).getReg();
+  int64_t Hi = MBBI->getOperand(2).getImm();
+  bool IsLA64 = STI.is64Bit();
+
+  // Expand to LU12I_W + ADD_W/D: the immediate is upper 20-bit.
+  BuildMI(MBB, MBBI, DL, TII->get(LoongArch::LU12I_W))
+      .addReg(DstReg, RegState::Define | getRenamableRegState(Renamable))
+      .addImm(Hi);
+  BuildMI(MBB, MBBI, DL, TII->get(IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W))
+      .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead) |
+                          getRenamableRegState(Renamable))
+      .addReg(BaseReg)
+      .addReg(DstReg, RegState::Kill | getRenamableRegState(Renamable));
+
+  MBBI->eraseFromParent();
+  return true;
+}
+
 } // end namespace
 
 INITIALIZE_PASS(LoongArchPreRAExpandPseudo, "loongarch-prera-expand-pseudo",
diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
index 6aacfd8138ff5..2d123e68015f1 100644
--- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
+++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
@@ -1891,6 +1891,13 @@ def : InstAlias<"la.local $dst, $tmp, $src",
                 (PseudoLA_ABS_LARGE GPR:$dst, GPR:$tmp, bare_symbol:$src)>;
 } // Predicates = [HasLaLocalWithAbs]
 
+// Materializes "$base + (imm << 12)" as a single pseudo so that
+// MachineLateInstrsCleanup can CSE identical upper-immediate additions.
+// Expanded to LU12I_W + ADD by LoongArchExpandPseudo.
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Size = 8 in
+def PseudoAddUpperImm
+    : Pseudo<(outs GPR:$dst), (ins GPR:$base, simm20_lu12iw:$hi), []>;
+
 /// BSTRINS and BSTRPICK
 
 let Predicates = [IsLA32, Has32S] in {
diff --git a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
index 0161979618412..1be43c2571bf8 100644
--- a/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
@@ -151,6 +151,33 @@ bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
 
   int FixedOffset = Offset.getFixed();
   bool OffsetLegal = true;
+  // True only when the instruction's immediate field is si12.
+  bool HasSimm12Field = false;
+  switch (MIOpc) {
+  case LoongArch::LD_B:
+  case LoongArch::LD_H:
+  case LoongArch::LD_W:
+  case LoongArch::LD_D:
+  case LoongArch::LD_BU:
+  case LoongArch::LD_HU:
+  case LoongArch::LD_WU:
+  case LoongArch::ST_B:
+  case LoongArch::ST_H:
+  case LoongArch::ST_W:
+  case LoongArch::ST_D:
+  case LoongArch::FLD_S:
+  case LoongArch::FLD_D:
+  case LoongArch::FST_S:
+  case LoongArch::FST_D:
+  case LoongArch::VLD:
+  case LoongArch::VST:
+  case LoongArch::XVLD:
+  case LoongArch::XVST:
+  case LoongArch::VLDREPL_B:
+  case LoongArch::XVLDREPL_B:
+    HasSimm12Field = true;
+    break;
+  }
 
   // Handle offsets that exceed the immediate range of the instruction.
   switch (MIOpc) {
@@ -189,22 +216,35 @@ bool LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
   if (!isInt<12>(FixedOffset)) {
     unsigned Addi = IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W;
     unsigned Add = IsLA64 ? LoongArch::ADD_D : LoongArch::ADD_W;
+    int64_t Val = Offset.getFixed();
+    // Keep the old behaviour of materializing the whole offset for instructions
+    // do not have simm12 field or ADDI due to it will be replaced.
+    int64_t Lo12 = !HasSimm12Field ? 0 : SignExtend64<12>(Val);
+    uint64_t HiVal = (uint64_t)Val - (uint64_t)Lo12;
 
     // The offset won't fit in an immediate, so use a scratch register instead.
     // Modify Offset and FrameReg appropriately.
     Register ScratchReg = MRI.createVirtualRegister(&LoongArch::GPRRegClass);
-    TII->movImm(MBB, II, DL, ScratchReg, Offset.getFixed());
-    if (MIOpc == Addi) {
-      BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg())
+    // Move lower 12-bit of offset into original instruction.
+    Offset = StackOffset::getFixed(Lo12);
+
+    if (HasSimm12Field && isShiftedInt<20, 12>(HiVal)) {
+      BuildMI(MBB, II, DL, TII->get(LoongArch::PseudoAddUpperImm), ScratchReg)
+          .addReg(FrameReg)
+          .addImm(static_cast<uint32_t>(HiVal) >> 12);
+    } else {
+      TII->movImm(MBB, II, DL, ScratchReg, HiVal);
+      if (MIOpc == Addi) {
+        BuildMI(MBB, II, DL, TII->get(Add), MI.getOperand(0).getReg())
+            .addReg(FrameReg)
+            .addReg(ScratchReg, RegState::Kill);
+        MI.eraseFromParent();
+        return true;
+      }
+      BuildMI(MBB, II, DL, TII->get(Add), ScratchReg)
           .addReg(FrameReg)
           .addReg(ScratchReg, RegState::Kill);
-      MI.eraseFromParent();
-      return true;
     }
-    BuildMI(MBB, II, DL, TII->get(Add), ScratchReg)
-        .addReg(FrameReg)
-        .addReg(ScratchReg, RegState::Kill);
-    Offset = StackOffset::getFixed(0);
     FrameReg = ScratchReg;
     FrameRegIsKill = true;
   }
diff --git a/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll b/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll
index 15ac95dfc6c55..158f98df38c21 100644
--- a/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll
+++ b/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll
@@ -30,9 +30,8 @@ define void @func() {
 ; CHECK-NEXT:    ld.w $a0, $a1, 0
 ; CHECK-NEXT:    st.d $fp, $sp, 0 # 8-byte Folded Spill
 ; CHECK-NEXT:    lu12i.w $fp, 1
-; CHECK-NEXT:    ori $fp, $fp, 12
 ; CHECK-NEXT:    add.d $fp, $sp, $fp
-; CHECK-NEXT:    st.w $t8, $fp, 0
+; CHECK-NEXT:    st.w $t8, $fp, 12
 ; CHECK-NEXT:    ld.d $fp, $sp, 0 # 8-byte Folded Reload
 ; CHECK-NEXT:    st.w $t8, $a1, 0
 ; CHECK-NEXT:    st.w $t7, $a1, 0
diff --git a/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir
index 5ec561aa754cc..d36c5a54788b9 100644
--- a/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir
+++ b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la32.mir
@@ -41,22 +41,12 @@ body: |
     ; LA32-NEXT: $r6 = frame-setup ORI killed $r6, 16
     ; LA32-NEXT: $r3 = frame-setup SUB_W $r3, killed $r6
     ; LA32-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16400
-    ; LA32-NEXT: $r6 = LU12I_W 4
-    ; LA32-NEXT: $r6 = ORI killed $r6, 12
-    ; LA32-NEXT: $r6 = ADD_W $r3, killed $r6
-    ; LA32-NEXT: ST_W $r4, killed $r6, 0 :: (store (s32))
-    ; LA32-NEXT: $r4 = LU12I_W 4
-    ; LA32-NEXT: $r4 = ORI killed $r4, 8
-    ; LA32-NEXT: $r4 = ADD_W $r3, killed $r4
-    ; LA32-NEXT: ST_W $r5, killed $r4, 0 :: (store (s32))
-    ; LA32-NEXT: $r4 = LU12I_W 4
-    ; LA32-NEXT: $r4 = ORI killed $r4, 12
-    ; LA32-NEXT: $r4 = ADD_W $r3, killed $r4
-    ; LA32-NEXT: $r6 = LD_W killed $r4, 0 :: (load (s32))
-    ; LA32-NEXT: $r4 = LU12I_W 4
-    ; LA32-NEXT: $r4 = ORI killed $r4, 8
-    ; LA32-NEXT: $r4 = ADD_W $r3, killed $r4
-    ; LA32-NEXT: $r7 = LD_W killed $r4, 0 :: (load (s32))
+    ; LA32-NEXT: $r6 = PseudoAddUpperImm $r3, 4
+    ; LA32-NEXT: ST_W $r4, killed $r6, 12 :: (store (s32))
+    ; LA32-NEXT: $r4 = PseudoAddUpperImm $r3, 4
+    ; LA32-NEXT: ST_W $r5, $r4, 8 :: (store (s32))
+    ; LA32-NEXT: $r6 = LD_W $r4, 12 :: (load (s32))
+    ; LA32-NEXT: $r7 = LD_W killed $r4, 8 :: (load (s32))
     ; LA32-NEXT: $r4 = frame-destroy LU12I_W 4
     ; LA32-NEXT: $r4 = frame-destroy ORI killed $r4, 16
     ; LA32-NEXT: $r3 = frame-destroy ADD_W $r3, killed $r4
@@ -70,21 +60,13 @@ body: |
     ; LA32-EXPAND-NEXT: $r3 = frame-setup SUB_W $r3, killed $r6
     ; LA32-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16400
     ; LA32-EXPAND-NEXT: $r6 = LU12I_W 4
-    ; LA32-EXPAND-NEXT: $r6 = ORI killed $r6, 12
     ; LA32-EXPAND-NEXT: $r6 = ADD_W $r3, killed $r6
-    ; LA32-EXPAND-NEXT: ST_W $r4, killed $r6, 0 :: (store (s32))
+    ; LA32-EXPAND-NEXT: ST_W $r4, killed $r6, 12 :: (store (s32))
     ; LA32-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA32-EXPAND-NEXT: $r4 = ORI killed $r4, 8
     ; LA32-EXPAND-NEXT: $r4 = ADD_W $r3, killed $r4
-    ; LA32-EXPAND-NEXT: ST_W $r5, killed $r4, 0 :: (store (s32))
-    ; LA32-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA32-EXPAND-NEXT: $r4 = ORI killed $r4, 12
-    ; LA32-EXPAND-NEXT: $r4 = ADD_W $r3, killed $r4
-    ; LA32-EXPAND-NEXT: $r6 = LD_W killed $r4, 0 :: (load (s32))
-    ; LA32-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA32-EXPAND-NEXT: $r4 = ORI killed $r4, 8
-    ; LA32-EXPAND-NEXT: $r4 = ADD_W $r3, killed $r4
-    ; LA32-EXPAND-NEXT: $r7 = LD_W killed $r4, 0 :: (load (s32))
+    ; LA32-EXPAND-NEXT: ST_W $r5, $r4, 8 :: (store (s32))
+    ; LA32-EXPAND-NEXT: $r6 = LD_W $r4, 12 :: (load (s32))
+    ; LA32-EXPAND-NEXT: $r7 = LD_W killed $r4, 8 :: (load (s32))
     ; LA32-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 4
     ; LA32-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 16
     ; LA32-EXPAND-NEXT: $r3 = frame-destroy ADD_W $r3, killed $r4
diff --git a/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir
index 09e1447137f27..9a9ae3e9c697d 100644
--- a/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir
+++ b/llvm/test/CodeGen/LoongArch/frame-base-dedup-la64.mir
@@ -46,22 +46,12 @@ body: |
     ; LA64-NEXT: $r6 = frame-setup ORI killed $r6, 32
     ; LA64-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
     ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16416
-    ; LA64-NEXT: $r6 = LU12I_W 4
-    ; LA64-NEXT: $r6 = ORI killed $r6, 24
-    ; LA64-NEXT: $r6 = ADD_D $r3, killed $r6
-    ; LA64-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 16
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 24
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 16
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-NEXT: $r6 = PseudoAddUpperImm $r3, 4
+    ; LA64-NEXT: ST_D $r4, killed $r6, 24 :: (store (s64))
+    ; LA64-NEXT: $r4 = PseudoAddUpperImm $r3, 4
+    ; LA64-NEXT: ST_D $r5, $r4, 16 :: (store (s64))
+    ; LA64-NEXT: $r6 = LD_D $r4, 24 :: (load (s64))
+    ; LA64-NEXT: $r7 = LD_D killed $r4, 16 :: (load (s64))
     ; LA64-NEXT: $r4 = frame-destroy LU12I_W 4
     ; LA64-NEXT: $r4 = frame-destroy ORI killed $r4, 32
     ; LA64-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
@@ -75,21 +65,13 @@ body: |
     ; LA64-EXPAND-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
     ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16416
     ; LA64-EXPAND-NEXT: $r6 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r6 = ORI killed $r6, 24
     ; LA64-EXPAND-NEXT: $r6 = ADD_D $r3, killed $r6
-    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 24 :: (store (s64))
     ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 16
     ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
-    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 24
-    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
-    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 16
-    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-EXPAND-NEXT: ST_D $r5, $r4, 16 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r6 = LD_D $r4, 24 :: (load (s64))
+    ; LA64-EXPAND-NEXT: $r7 = LD_D killed $r4, 16 :: (load (s64))
     ; LA64-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 4
     ; LA64-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 32
     ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
@@ -129,14 +111,10 @@ body: |
     ; LA64-NEXT: $r6 = frame-setup ORI killed $r6, 32
     ; LA64-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
     ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 20512
-    ; LA64-NEXT: $r6 = LU12I_W 5
-    ; LA64-NEXT: $r6 = ORI killed $r6, 24
-    ; LA64-NEXT: $r6 = ADD_D $r3, killed $r6
-    ; LA64-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 16
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-NEXT: $r6 = PseudoAddUpperImm $r3, 5
+    ; LA64-NEXT: ST_D $r4, killed $r6, 24 :: (store (s64))
+    ; LA64-NEXT: $r4 = PseudoAddUpperImm $r3, 4
+    ; LA64-NEXT: ST_D $r5, killed $r4, 16 :: (store (s64))
     ; LA64-NEXT: $r4 = frame-destroy LU12I_W 5
     ; LA64-NEXT: $r4 = frame-destroy ORI killed $r4, 32
     ; LA64-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
@@ -150,13 +128,11 @@ body: |
     ; LA64-EXPAND-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
     ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 20512
     ; LA64-EXPAND-NEXT: $r6 = LU12I_W 5
-    ; LA64-EXPAND-NEXT: $r6 = ORI killed $r6, 24
     ; LA64-EXPAND-NEXT: $r6 = ADD_D $r3, killed $r6
-    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 24 :: (store (s64))
     ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 16
     ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
+    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 16 :: (store (s64))
     ; LA64-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 5
     ; LA64-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 32
     ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
@@ -195,22 +171,12 @@ body: |
     ; LA64-NEXT: $r6 = frame-setup ORI killed $r6, 2080
     ; LA64-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
     ; LA64-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 18464
-    ; LA64-NEXT: $r6 = LU12I_W 4
-    ; LA64-NEXT: $r6 = ORI killed $r6, 2072
-    ; LA64-NEXT: $r6 = ADD_D $r3, killed $r6
-    ; LA64-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 2064
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 2072
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
-    ; LA64-NEXT: $r4 = LU12I_W 4
-    ; LA64-NEXT: $r4 = ORI killed $r4, 2064
-    ; LA64-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-NEXT: $r6 = PseudoAddUpperImm $r3, 5
+    ; LA64-NEXT: ST_D $r4, killed $r6, -2024 :: (store (s64))
+    ; LA64-NEXT: $r4 = PseudoAddUpperImm $r3, 5
+    ; LA64-NEXT: ST_D $r5, $r4, -2032 :: (store (s64))
+    ; LA64-NEXT: $r6 = LD_D $r4, -2024 :: (load (s64))
+    ; LA64-NEXT: $r7 = LD_D killed $r4, -2032 :: (load (s64))
     ; LA64-NEXT: $r4 = frame-destroy LU12I_W 4
     ; LA64-NEXT: $r4 = frame-destroy ORI killed $r4, 2080
     ; LA64-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
@@ -223,22 +189,14 @@ body: |
     ; LA64-EXPAND-NEXT: $r6 = frame-setup ORI killed $r6, 2080
     ; LA64-EXPAND-NEXT: $r3 = frame-setup SUB_D $r3, killed $r6
     ; LA64-EXPAND-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 18464
-    ; LA64-EXPAND-NEXT: $r6 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r6 = ORI killed $r6, 2072
+    ; LA64-EXPAND-NEXT: $r6 = LU12I_W 5
     ; LA64-EXPAND-NEXT: $r6 = ADD_D $r3, killed $r6
-    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, 0 :: (store (s64))
-    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 2064
-    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: ST_D $r5, killed $r4, 0 :: (store (s64))
-    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 2072
-    ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: $r6 = LD_D killed $r4, 0 :: (load (s64))
-    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 4
-    ; LA64-EXPAND-NEXT: $r4 = ORI killed $r4, 2064
+    ; LA64-EXPAND-NEXT: ST_D $r4, killed $r6, -2024 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r4 = LU12I_W 5
     ; LA64-EXPAND-NEXT: $r4 = ADD_D $r3, killed $r4
-    ; LA64-EXPAND-NEXT: $r7 = LD_D killed $r4, 0 :: (load (s64))
+    ; LA64-EXPAND-NEXT: ST_D $r5, $r4, -2032 :: (store (s64))
+    ; LA64-EXPAND-NEXT: $r6 = LD_D $r4, -2024 :: (load (s64))
+    ; LA64-EXPAND-NEXT: $r7 = LD_D killed $r4, -2032 :: (load (s64))
     ; LA64-EXPAND-NEXT: $r4 = frame-destroy LU12I_W 4
     ; LA64-EXPAND-NEXT: $r4 = frame-destroy ORI killed $r4, 2080
     ; LA64-EXPAND-NEXT: $r3 = frame-destroy ADD_D $r3, killed $r4
diff --git a/llvm/test/CodeGen/LoongArch/stack-clash-prologue.ll b/llvm/test/CodeGen/LoongArch/stack-clash-prologue.ll
index 4e814baf05d51..dfb468e93c04e 100644
--- a/llvm/test/CodeGen/LoongArch/stack-clash-prologue.ll
+++ b/llvm/test/CodeGen/LoongArch/stack-clash-prologue.ll
@@ -465,9 +465,9 @@ define i32 @f9(i64 %i) local_unnamed_addr #0 {
 ; LA64-NEXT:    add.d $a1, $sp, $a1
 ; LA64-NEXT:    ori $a2, $zero, 1
 ; LA64-NEXT:    stx.w $a2, $a0, $a1
-; LA64-NEXT:    ori $a0, $zero, 2048
+; LA64-NEXT:    lu12i.w $a0, 1
 ; LA64-NEXT:    add.d $a0, $sp, $a0
-; LA64-NEXT:    ld.w $a0, $a0, 0
+; LA64-NEXT:    ld.w $a0, $a0, -2048
 ; LA64-NEXT:    lu12i.w $a1, 2
 ; LA64-NEXT:    ori $a1, $a1, 2048
 ; LA64-NEXT:    sub.d $sp, $fp, $a1
@@ -502,9 +502,9 @@ define i32 @f9(i64 %i) local_unnamed_addr #0 {
 ; LA32-NEXT:    add.w $a0, $a1, $a0
 ; LA32-NEXT:    ori $a1, $zero, 1
 ; LA32-NEXT:    st.w $a1, $a0, 0
-; LA32-NEXT:    ori $a0, $zero, 2048
+; LA32-NEXT:    lu12i.w $a0, 1
 ; LA32-NEXT:    add.w $a0, $sp, $a0
-; LA32-NEXT:    ld.w $a0, $a0, 0
+; LA32-NEXT:    ld.w $a0, $a0, -2048
 ; LA32-NEXT:    lu12i.w $a1, 2
 ; LA32-NEXT:    ori $a1, $a1, 2048
 ; LA32-NEXT:    sub.w $sp, $fp, $a1



More information about the llvm-commits mailing list