[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