[llvm] [AMDGPU] Fix uniform fcopysign pattern (PR #218644)

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 25 02:25:17 PDT 2026


https://github.com/Shoreshen created https://github.com/llvm/llvm-project/pull/218644

None

>From 8c89b2f3f36e4ebd24ca6b131c89abaf3dc8a8f7 Mon Sep 17 00:00:00 2001
From: shore <shorshen at amd.com>
Date: Tue, 25 Aug 2026 17:24:12 +0800
Subject: [PATCH] fix uniform fcopysign pattern

---
 llvm/lib/Target/AMDGPU/SIInstructions.td      |  15 +++
 .../AMDGPU/fcopysign-f16-uniform-true16.ll    | 120 ++++++++++++++++++
 2 files changed, 135 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/fcopysign-f16-uniform-true16.ll

diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index 441098168f450..7ce0680e6d41e 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -2476,6 +2476,21 @@ def : GCNPat <
 >;
 }
 let True16Predicate = UseRealTrue16Insts in {
+// Uniform true16 values use SReg_32. Copy them to VGPR_16 before packing so
+// subregister liveness tracks the source lane in the correct coordinates.
+let AddedComplexity = 1 in
+def : GCNPat <
+  (UniformBinFrag<fcopysign> (fp16vt SReg_32:$src0),
+                             (fp16vt SReg_32:$src1)),
+  (EXTRACT_SUBREG (V_BFI_B32_e64 (S_MOV_B32 (i32 0x00007fff)),
+    (REG_SEQUENCE VGPR_32,
+      (fp16vt (COPY_TO_REGCLASS SReg_32:$src0, VGPR_16)), lo16,
+      (i16 (IMPLICIT_DEF)), hi16),
+    (REG_SEQUENCE VGPR_32,
+      (fp16vt (COPY_TO_REGCLASS SReg_32:$src1, VGPR_16)), lo16,
+      (i16 (IMPLICIT_DEF)), hi16)), lo16)
+>;
+
 def : GCNPat <
   (fcopysign fp16vt:$src0, fp16vt:$src1),
   (EXTRACT_SUBREG (V_BFI_B32_e64 (S_MOV_B32 (i32 0x00007fff)),
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign-f16-uniform-true16.ll b/llvm/test/CodeGen/AMDGPU/fcopysign-f16-uniform-true16.ll
new file mode 100644
index 0000000000000..3688a6ae9e7ad
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign-f16-uniform-true16.ll
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1101 -stop-before=dead-mi-elimination,3 -o - %s | FileCheck %s
+; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx1101 -verify-machineinstrs -o - %s | FileCheck --check-prefix=ASM %s
+
+define void @uniform_fcopysign(ptr addrspace(1) inreg %out, ptr addrspace(1) inreg %in) {
+; ASM-LABEL: uniform_fcopysign:
+; ASM:       ; %bb.0: ; %entry
+; ASM-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; ASM-NEXT:    v_mov_b32_e32 v0, 0
+; ASM-NEXT:    global_load_d16_b16 v0, v0, s[2:3]
+; ASM-NEXT:    s_waitcnt vmcnt(0)
+; ASM-NEXT:    v_cmp_ge_f16_e32 vcc_lo, 0, v0.l
+; ASM-NEXT:    s_cbranch_vccz .LBB0_2
+; ASM-NEXT:  ; %bb.1: ; %negative
+; ASM-NEXT:    v_mul_f16_e32 v1.l, 0x4200, v0.l
+; ASM-NEXT:    s_mov_b32 s2, 0
+; ASM-NEXT:    s_branch .LBB0_3
+; ASM-NEXT:  .LBB0_2:
+; ASM-NEXT:    s_mov_b32 s2, -1
+; ASM-NEXT:    ; implicit-def: $vgpr1
+; ASM-NEXT:  .LBB0_3: ; %Flow
+; ASM-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(SKIP_1) | instid1(SALU_CYCLE_1)
+; ASM-NEXT:    s_and_b32 s2, s2, exec_lo
+; ASM-NEXT:    s_cselect_b32 s2, 1, 0
+; ASM-NEXT:    s_cmp_lg_u32 s2, 1
+; ASM-NEXT:    s_cbranch_scc1 .LBB0_5
+; ASM-NEXT:  ; %bb.4: ; %positive
+; ASM-NEXT:    v_add_f16_e32 v1.l, v0.l, v0.l
+; ASM-NEXT:  .LBB0_5: ; %exit
+; ASM-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; ASM-NEXT:    v_bfi_b32 v0, 0x7fff, v1, v0
+; ASM-NEXT:    v_mov_b32_e32 v1, 0
+; ASM-NEXT:    global_store_b16 v1, v0, s[0:1]
+; ASM-NEXT:    s_setpc_b64 s[30:31]
+; CHECK-LABEL: name: uniform_fcopysign
+; CHECK: bb.0.entry:
+; CHECK-NEXT:   successors: %bb.3(0x40000000), %bb.5(0x40000000)
+; CHECK-NEXT:   liveins: $sgpr0, $sgpr1, $sgpr2, $sgpr3
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT:   [[COPY:%[0-9]+]]:sgpr_32 = COPY $sgpr3
+; CHECK-NEXT:   [[COPY1:%[0-9]+]]:sgpr_32 = COPY $sgpr2
+; CHECK-NEXT:   [[COPY2:%[0-9]+]]:sgpr_32 = COPY $sgpr1
+; CHECK-NEXT:   [[COPY3:%[0-9]+]]:sgpr_32 = COPY $sgpr0
+; CHECK-NEXT:   [[REG_SEQUENCE:%[0-9]+]]:sgpr_64 = REG_SEQUENCE [[COPY3]], %subreg.sub0, [[COPY2]], %subreg.sub1
+; CHECK-NEXT:   [[REG_SEQUENCE1:%[0-9]+]]:sgpr_64 = REG_SEQUENCE [[COPY1]], %subreg.sub0, [[COPY]], %subreg.sub1
+; CHECK-NEXT:   [[V_MOV_B32_e32_:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+; CHECK-NEXT:   [[GLOBAL_LOAD_SHORT_D16_SADDR_t16_:%[0-9]+]]:vgpr_16 = GLOBAL_LOAD_SHORT_D16_SADDR_t16 killed [[REG_SEQUENCE1]], killed [[V_MOV_B32_e32_]], 0, 0, implicit $exec :: (load (s16) from %ir.in, addrspace 1)
+; CHECK-NEXT:   [[DEF:%[0-9]+]]:vgpr_16 = IMPLICIT_DEF
+; CHECK-NEXT:   [[REG_SEQUENCE2:%[0-9]+]]:vgpr_32 = REG_SEQUENCE [[GLOBAL_LOAD_SHORT_D16_SADDR_t16_]], %subreg.lo16, undef [[DEF]], %subreg.hi16
+; CHECK-NEXT:   [[V_CMP_GE_F16_t16_e64_:%[0-9]+]]:sreg_32 = nofpexcept V_CMP_GE_F16_t16_e64 0, 0, 0, [[GLOBAL_LOAD_SHORT_D16_SADDR_t16_]], 0, 0, implicit $mode, implicit $exec
+; CHECK-NEXT:   [[S_AND_B32_:%[0-9]+]]:sreg_32 = S_AND_B32 $exec_lo, killed [[V_CMP_GE_F16_t16_e64_]], implicit-def dead $scc
+; CHECK-NEXT:   $vcc_lo = COPY [[S_AND_B32_]]
+; CHECK-NEXT:   S_CBRANCH_VCCNZ %bb.3, implicit $vcc_lo
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT: bb.5:
+; CHECK-NEXT:   successors: %bb.1(0x80000000)
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT:   [[S_MOV_B32_:%[0-9]+]]:sreg_32 = S_MOV_B32 -1
+; CHECK-NEXT:   [[DEF1:%[0-9]+]]:sreg_32 = IMPLICIT_DEF
+; CHECK-NEXT:   [[COPY4:%[0-9]+]]:vgpr_32 = COPY undef [[DEF1]]
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT: bb.1.Flow:
+; CHECK-NEXT:   successors: %bb.2(0x40000000), %bb.4(0x40000000)
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT:   [[PHI:%[0-9]+]]:vgpr_32 = PHI [[COPY4]], %bb.5, %47, %bb.3
+; CHECK-NEXT:   [[PHI1:%[0-9]+]]:sreg_32 = PHI [[S_MOV_B32_]], %bb.5, %28, %bb.3
+; CHECK-NEXT:   dead [[S_AND_B32_1:%[0-9]+]]:sreg_32 = S_AND_B32 [[PHI1]], $exec_lo, implicit-def $scc
+; CHECK-NEXT:   [[S_CSELECT_B32_:%[0-9]+]]:sreg_32 = S_CSELECT_B32 1, 0, implicit $scc
+; CHECK-NEXT:   S_CMP_LG_U32 killed [[S_CSELECT_B32_]], 1, implicit-def $scc
+; CHECK-NEXT:   S_CBRANCH_SCC1 %bb.4, implicit $scc
+; CHECK-NEXT:   S_BRANCH %bb.2
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT: bb.2.positive:
+; CHECK-NEXT:   successors: %bb.4(0x80000000)
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT:   [[V_ADD_F16_t16_e64_:%[0-9]+]]:vgpr_16 = nofpexcept V_ADD_F16_t16_e64 0, [[REG_SEQUENCE2]].lo16, 0, [[REG_SEQUENCE2]].lo16, 0, 0, 0, implicit $mode, implicit $exec
+; CHECK-NEXT:   [[DEF2:%[0-9]+]]:vgpr_16 = IMPLICIT_DEF
+; CHECK-NEXT:   [[REG_SEQUENCE3:%[0-9]+]]:vgpr_32 = REG_SEQUENCE [[V_ADD_F16_t16_e64_]], %subreg.lo16, undef [[DEF2]], %subreg.hi16
+; CHECK-NEXT:   S_BRANCH %bb.4
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT: bb.3.negative:
+; CHECK-NEXT:   successors: %bb.1(0x80000000)
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT:   [[V_MUL_F16_t16_e64_:%[0-9]+]]:vgpr_16 = nofpexcept V_MUL_F16_t16_e64 0, 16896, 0, [[REG_SEQUENCE2]].lo16, 0, 0, 0, implicit $mode, implicit $exec
+; CHECK-NEXT:   [[S_MOV_B32_1:%[0-9]+]]:sreg_32 = S_MOV_B32 0
+; CHECK-NEXT:   [[DEF3:%[0-9]+]]:vgpr_16 = IMPLICIT_DEF
+; CHECK-NEXT:   [[REG_SEQUENCE4:%[0-9]+]]:vgpr_32 = REG_SEQUENCE [[V_MUL_F16_t16_e64_]], %subreg.lo16, undef [[DEF3]], %subreg.hi16
+; CHECK-NEXT:   S_BRANCH %bb.1
+; CHECK-NEXT: {{  $}}
+; CHECK-NEXT: bb.4.exit:
+; CHECK-NEXT:   [[PHI2:%[0-9]+]]:vgpr_32 = PHI [[PHI]], %bb.1, [[REG_SEQUENCE3]], %bb.2
+; CHECK-NEXT:   [[COPY5:%[0-9]+]]:vgpr_16 = COPY [[REG_SEQUENCE2]]
+; CHECK-NEXT:   [[DEF4:%[0-9]+]]:sreg_32 = IMPLICIT_DEF
+; CHECK-NEXT:   [[REG_SEQUENCE5:%[0-9]+]]:vgpr_32 = REG_SEQUENCE killed [[COPY5]], %subreg.lo16, undef [[DEF4]], %subreg.hi16
+; CHECK-NEXT:   [[COPY6:%[0-9]+]]:vgpr_16 = COPY [[PHI2]]
+; CHECK-NEXT:   [[DEF5:%[0-9]+]]:sreg_32 = IMPLICIT_DEF
+; CHECK-NEXT:   [[REG_SEQUENCE6:%[0-9]+]]:vgpr_32 = REG_SEQUENCE killed [[COPY6]], %subreg.lo16, undef [[DEF5]], %subreg.hi16
+; CHECK-NEXT:   [[V_BFI_B32_e64_:%[0-9]+]]:vgpr_32 = V_BFI_B32_e64 32767, killed [[REG_SEQUENCE6]], killed [[REG_SEQUENCE5]], implicit $exec
+; CHECK-NEXT:   [[V_MOV_B32_e32_1:%[0-9]+]]:vgpr_32 = V_MOV_B32_e32 0, implicit $exec
+; CHECK-NEXT:   GLOBAL_STORE_SHORT_SADDR_t16 killed [[V_MOV_B32_e32_1]], [[V_BFI_B32_e64_]].lo16, [[REG_SEQUENCE]], 0, 0, implicit $exec :: (store (s16) into %ir.out, addrspace 1)
+; CHECK-NEXT:   SI_RETURN
+entry:
+  %x = load half, ptr addrspace(1) %in, align 2
+  %cond = fcmp ugt half %x, 0.000000e+00
+  br i1 %cond, label %positive, label %negative
+
+positive:
+  %pos = fmul half %x, 2.000000e+00
+  br label %exit
+
+negative:
+  %neg = fmul half %x, 3.000000e+00
+  br label %exit
+
+exit:
+  %magnitude = phi half [ %pos, %positive ], [ %neg, %negative ]
+  %result = call half @llvm.copysign.f16(half %magnitude, half %x)
+  store half %result, ptr addrspace(1) %out, align 2
+  ret void
+}



More information about the llvm-commits mailing list