[llvm] [AMDGPU] Fix v_mov_b16 pair merging when the second mov reads the first (PR #227502)
Guo Chen via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 11:48:05 PDT 2026
================
@@ -409,3 +409,96 @@ body: |
$vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr3_hi16, implicit $exec
S_ENDPGM 0, implicit $vgpr0
...
+
+---
+# Negative: the second mov reads the lo16 written by the first — must NOT merge.
+name: no_merge_second_src_is_first_dst_lo
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr1
+
+ ; CHECK-LABEL: name: no_merge_second_src_is_first_dst_lo
+ ; CHECK: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr1_lo16, implicit $exec
+ ; CHECK-NEXT: $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr0_lo16, implicit $exec
+ ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0
+ $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr1_lo16, implicit $exec
+ $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr0_lo16, implicit $exec
+ S_ENDPGM 0, implicit $vgpr0
+...
+
+---
+# Negative: the second mov reads the hi16 written by the first — must NOT merge.
+name: no_merge_second_src_is_first_dst_hi
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr1
+
+ ; CHECK-LABEL: name: no_merge_second_src_is_first_dst_hi
+ ; CHECK: liveins: $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr1_hi16, implicit $exec
+ ; CHECK-NEXT: $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr0_hi16, implicit $exec
+ ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0
+ $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr1_hi16, implicit $exec
+ $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr0_hi16, implicit $exec
+ S_ENDPGM 0, implicit $vgpr0
+...
+
+---
+# Negative: zero lo16, then copy it to hi16 — must NOT become v_lshlrev_b32.
+name: no_merge_second_src_is_first_dst_zero
+tracksRegLiveness: true
+body: |
+ bb.0:
+ ; CHECK-LABEL: name: no_merge_second_src_is_first_dst_zero
+ ; CHECK: $vgpr0_lo16 = V_MOV_B16_t16_e32 0, implicit $exec
+ ; CHECK-NEXT: $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr0_lo16, implicit $exec
+ ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0
+ $vgpr0_lo16 = V_MOV_B16_t16_e32 0, implicit $exec
+ $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr0_lo16, implicit $exec
+ S_ENDPGM 0, implicit $vgpr0
+...
+
+---
+# Positive: the first mov reads the half written by the second; the merged
+# instruction reads it before writing, so merging is still correct.
+name: merge_first_src_is_second_dst
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr0, $vgpr1
+
+ ; CHECK-LABEL: name: merge_first_src_is_second_dst
+ ; CHECK: liveins: $vgpr0, $vgpr1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $vgpr0 = V_PERM_B32_e64 $vgpr1, $vgpr0, 84148994, implicit $exec
+ ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0
+ $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr0_hi16, implicit $exec
+ $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr1_lo16, implicit $exec
+ S_ENDPGM 0, implicit $vgpr0
+...
+
+---
+# Negative: EXEC is written between the movs — must NOT merge.
+name: no_merge_exec_write_between
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $vgpr2, $vgpr3, $sgpr0
+
+ ; CHECK-LABEL: name: no_merge_exec_write_between
+ ; CHECK: liveins: $vgpr2, $vgpr3, $sgpr0
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr2_lo16, implicit $exec
+ ; CHECK-NEXT: $exec_lo = S_MOV_B32 $sgpr0
+ ; CHECK-NEXT: $vgpr0_hi16 = V_MOV_B16_t16_e32 $vgpr3_hi16, implicit $exec
+ ; CHECK-NEXT: S_ENDPGM 0, implicit $vgpr0
+ $vgpr0_lo16 = V_MOV_B16_t16_e32 $vgpr2_lo16, implicit $exec
+ $exec_lo = S_MOV_B32 $sgpr0
----------------
broxigarchen wrote:
I see. Referring to this discussion https://github.com/llvm/llvm-project/pull/208625#discussion_r4105067423 we think it's safe to assume no exec modifications in the middle of a basic block so only doing an assert here
https://github.com/llvm/llvm-project/pull/227502
More information about the llvm-commits
mailing list