[llvm] [AMDGPU] Fix SIFoldOperands miscompiling values that leave a divergent loop (PR #203256)
Matt Arsenault via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 11 08:58:42 PDT 2026
================
@@ -54,3 +54,132 @@ 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 must not
+# fold the scalar source into that exit use: it escapes the loop, so the fold
+# would drop the per-lane snapshot.
+---
+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: [[COPY2:%[0-9]+]]:vgpr_32 = COPY [[S_XOR_B32_]]
+ ; 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 [[COPY2]], 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
+ %7:vgpr_32 = COPY $vgpr0
+ %8:sreg_64 = S_MOV_B64 0
+ %9:sreg_32 = S_MOV_B32 0
+
+ bb.1:
+ successors: %bb.2(0x04000000), %bb.1(0x7c000000)
+
+ %1:sreg_64 = PHI %8, %bb.0, %4, %bb.1
+ %2:sreg_32 = PHI %9, %bb.0, %6, %bb.1
+ %3:sreg_32 = S_XOR_B32 %0, %2, implicit-def dead $scc
+ %5:vgpr_32 = COPY %3
+ %6:sreg_32 = S_ADD_I32 %2, 1, implicit-def dead $scc
+ %10:sreg_64 = V_CMP_EQ_U32_e64 %7, %6, implicit $exec
+ %4:sreg_64 = SI_IF_BREAK %10, %1, implicit-def dead $scc
+ SI_LOOP %4, %bb.1, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+ S_BRANCH %bb.2
+
+ bb.2:
+ SI_END_CF %4, implicit-def dead $exec, implicit-def dead $scc, implicit $exec
+ %13:vgpr_32 = V_ADD_U32_e64 %5, 1, 0, implicit $exec
+ $vgpr0 = COPY %13
+ SI_RETURN implicit $vgpr0
+...
+
+# Same latch, but the loop-exit use is itself a COPY. The scalar source must
+# not be propagated through that exit copy either (separate fold path).
+---
+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: [[COPY2:%[0-9]+]]:vgpr_32 = COPY [[S_XOR_B32_]]
+ ; 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 [[COPY2]], 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
+ %7:vgpr_32 = COPY $vgpr0
----------------
arsenm wrote:
Can you compact the register numbers with -run-pass=none
https://github.com/llvm/llvm-project/pull/203256
More information about the llvm-commits
mailing list