[llvm] [AMDGPU] Pre-commit tests for folding SGPR->VGPR copies escaping a divergent loop (NFC) (PR #203502)

Arseniy Obolenskiy via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 12 03:56:12 PDT 2026


https://github.com/aobolensk created https://github.com/llvm/llvm-project/pull/203502

pre-commit for https://github.com/llvm/llvm-project/pull/203256 

>From 13e6c6cccb2972b5ebc46edf02bd73aee9bad7fd Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Fri, 12 Jun 2026 12:54:50 +0200
Subject: [PATCH] [AMDGPU][NFC] Pre-commit tests for folding SGPR->VGPR copies
 escaping a divergent loop

---
 llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir | 128 ++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir b/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir
index 5c206da8c544f..2beaf9a2bb2e4 100644
--- a/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir
+++ b/llvm/test/CodeGen/AMDGPU/do-not-fold-copy.mir
@@ -54,3 +54,131 @@ body:             |
     %11:vgpr_32 = V_SET_INACTIVE_B32 0, %9, 0, 0, killed %10, implicit $exec
     S_ENDPGM 0
 ...
+
+# An SGPR->VGPR copy with no implicit $exec read, inserted in a divergent loop
+# to latch a per-lane value, is read after the loop. SIFoldOperands currently
+# folds the scalar source into that exit use, dropping the per-lane snapshot;
+# this is wrong because the value escapes the loop. FIXME: should not fold.
+---
+name:            do_not_fold_sgpr_to_vgpr_copy_escaping_loop
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: do_not_fold_sgpr_to_vgpr_copy_escaping_loop
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr0, $vgpr0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+  ; CHECK-NEXT:   [[S_MOV_B64_:%[0-9]+]]:sreg_64 = S_MOV_B64 0
+  ; CHECK-NEXT:   [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x04000000), %bb.1(0x7c000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:sreg_64 = PHI [[S_MOV_B64_]], %bb.0, %5, %bb.1
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:sreg_32 = PHI [[S_MOV_B32_]], %bb.0, %7, %bb.1
+  ; CHECK-NEXT:   [[S_XOR_B32_:%[0-9]+]]:sreg_32 = S_XOR_B32 [[COPY]], [[PHI1]], implicit-def dead $scc
+  ; CHECK-NEXT:   [[S_ADD_I32_:%[0-9]+]]:sreg_32 = S_ADD_I32 [[PHI1]], 1, implicit-def dead $scc
+  ; CHECK-NEXT:   [[V_CMP_EQ_U32_e64_:%[0-9]+]]:sreg_64 = V_CMP_EQ_U32_e64 [[COPY1]], [[S_ADD_I32_]], implicit $exec
+  ; CHECK-NEXT:   [[SI_IF_BREAK:%[0-9]+]]:sreg_64 = SI_IF_BREAK [[V_CMP_EQ_U32_e64_]], [[PHI]], implicit-def dead $scc
+  ; CHECK-NEXT:   SI_LOOP [[SI_IF_BREAK]], %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   SI_END_CF [[SI_IF_BREAK]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[S_XOR_B32_]], 1, 0, implicit $exec
+  ; CHECK-NEXT:   $vgpr0 = COPY [[V_ADD_U32_e64_]]
+  ; CHECK-NEXT:   SI_RETURN implicit $vgpr0
+  bb.0:
+    successors: %bb.1
+    liveins: $sgpr0, $vgpr0
+
+    %0:sreg_32 = COPY $sgpr0
+    %1:vgpr_32 = COPY $vgpr0
+    %2:sreg_64 = S_MOV_B64 0
+    %3:sreg_32 = S_MOV_B32 0
+
+  bb.1:
+    successors: %bb.2(0x04000000), %bb.1(0x7c000000)
+
+    %4:sreg_64 = PHI %2, %bb.0, %5, %bb.1
+    %6:sreg_32 = PHI %3, %bb.0, %7, %bb.1
+    %8:sreg_32 = S_XOR_B32 %0, %6, implicit-def dead $scc
+    %9:vgpr_32 = COPY %8
+    %7:sreg_32 = S_ADD_I32 %6, 1, implicit-def dead $scc
+    %10:sreg_64 = V_CMP_EQ_U32_e64 %1, %7, implicit $exec
+    %5:sreg_64 = SI_IF_BREAK %10, %4, implicit-def dead $scc
+    SI_LOOP %5, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.2
+
+  bb.2:
+    SI_END_CF %5, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    %11:vgpr_32 = V_ADD_U32_e64 %9, 1, 0, implicit $exec
+    $vgpr0 = COPY %11
+    SI_RETURN implicit $vgpr0
+...
+
+# Same latch, but the loop-exit use is itself a COPY. The scalar source is
+# currently propagated through that exit copy too (separate fold path).
+# FIXME: should not fold.
+---
+name:            do_not_fold_sgpr_to_vgpr_copy_escaping_loop_via_copy_use
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: do_not_fold_sgpr_to_vgpr_copy_escaping_loop_via_copy_use
+  ; CHECK: bb.0:
+  ; CHECK-NEXT:   successors: %bb.1(0x80000000)
+  ; CHECK-NEXT:   liveins: $sgpr0, $vgpr0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[COPY:%[0-9]+]]:sreg_32 = COPY $sgpr0
+  ; CHECK-NEXT:   [[COPY1:%[0-9]+]]:vgpr_32 = COPY $vgpr0
+  ; CHECK-NEXT:   [[S_MOV_B64_:%[0-9]+]]:sreg_64 = S_MOV_B64 0
+  ; CHECK-NEXT:   [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.1:
+  ; CHECK-NEXT:   successors: %bb.2(0x04000000), %bb.1(0x7c000000)
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT:   [[PHI:%[0-9]+]]:sreg_64 = PHI [[S_MOV_B64_]], %bb.0, %5, %bb.1
+  ; CHECK-NEXT:   [[PHI1:%[0-9]+]]:sreg_32 = PHI [[S_MOV_B32_]], %bb.0, %7, %bb.1
+  ; CHECK-NEXT:   [[S_XOR_B32_:%[0-9]+]]:sreg_32 = S_XOR_B32 [[COPY]], [[PHI1]], implicit-def dead $scc
+  ; CHECK-NEXT:   [[S_ADD_I32_:%[0-9]+]]:sreg_32 = S_ADD_I32 [[PHI1]], 1, implicit-def dead $scc
+  ; CHECK-NEXT:   [[V_CMP_EQ_U32_e64_:%[0-9]+]]:sreg_64 = V_CMP_EQ_U32_e64 [[COPY1]], [[S_ADD_I32_]], implicit $exec
+  ; CHECK-NEXT:   [[SI_IF_BREAK:%[0-9]+]]:sreg_64 = SI_IF_BREAK [[V_CMP_EQ_U32_e64_]], [[PHI]], implicit-def dead $scc
+  ; CHECK-NEXT:   SI_LOOP [[SI_IF_BREAK]], %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   S_BRANCH %bb.2
+  ; CHECK-NEXT: {{  $}}
+  ; CHECK-NEXT: bb.2:
+  ; CHECK-NEXT:   SI_END_CF [[SI_IF_BREAK]], implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+  ; CHECK-NEXT:   [[V_ADD_U32_e64_:%[0-9]+]]:vgpr_32 = V_ADD_U32_e64 [[S_XOR_B32_]], 1, 0, implicit $exec
+  ; CHECK-NEXT:   $vgpr0 = COPY [[V_ADD_U32_e64_]]
+  ; CHECK-NEXT:   SI_RETURN implicit $vgpr0
+  bb.0:
+    successors: %bb.1
+    liveins: $sgpr0, $vgpr0
+
+    %0:sreg_32 = COPY $sgpr0
+    %1:vgpr_32 = COPY $vgpr0
+    %2:sreg_64 = S_MOV_B64 0
+    %3:sreg_32 = S_MOV_B32 0
+
+  bb.1:
+    successors: %bb.2(0x04000000), %bb.1(0x7c000000)
+
+    %4:sreg_64 = PHI %2, %bb.0, %5, %bb.1
+    %6:sreg_32 = PHI %3, %bb.0, %7, %bb.1
+    %8:sreg_32 = S_XOR_B32 %0, %6, implicit-def dead $scc
+    %9:vgpr_32 = COPY %8
+    %7:sreg_32 = S_ADD_I32 %6, 1, implicit-def dead $scc
+    %10:sreg_64 = V_CMP_EQ_U32_e64 %1, %7, implicit $exec
+    %5:sreg_64 = SI_IF_BREAK %10, %4, implicit-def dead $scc
+    SI_LOOP %5, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    S_BRANCH %bb.2
+
+  bb.2:
+    SI_END_CF %5, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+    %11:vgpr_32 = COPY %9
+    %12:vgpr_32 = V_ADD_U32_e64 %11, 1, 0, implicit $exec
+    $vgpr0 = COPY %12
+    SI_RETURN implicit $vgpr0
+...



More information about the llvm-commits mailing list