[llvm] [AMDGPU] Improve codegen for copysign(x, fneg(y)) (PR #207178)

Madhur Kumar via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 02:27:54 PDT 2026


https://github.com/MadhurKumar004 updated https://github.com/llvm/llvm-project/pull/207178

>From a48f41b463de741f7dfb21b15221b7f9ae031624 Mon Sep 17 00:00:00 2001
From: Madhur Kumar <madhurkumar004 at gmail.com>
Date: Thu, 16 Jul 2026 14:42:24 +0530
Subject: [PATCH 1/2] [AMDGPU] Test of codegen for copysign(x, fneg(y))

---
 llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll | 302 +++++++++++++++++++++
 llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll  | 183 +++++++++++++
 llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll  |  89 ++++++
 llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll  |  92 +++++++
 4 files changed, 666 insertions(+)

diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll
index 07d6db5bb3d27..d896b1888d6bf 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll
@@ -8063,4 +8063,306 @@ define <2 x bfloat> @v_copysign_v2bf16_0_v2bf64(<2 x double> %sign) {
   ret <2 x bfloat> %op
 }
 
+define amdgpu_ps bfloat @s_copysign_bf16_0_fneg(bfloat inreg %sign) {
+; SIVI-LABEL: s_copysign_bf16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; SIVI-NEXT:    s_and_b32 s0, 0x80000000, s0
+; SIVI-NEXT:    v_mov_b32_e32 v0, s0
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; SI-LABEL: s_copysign_bf16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_andn2_b32 s0, 0xffff8000, s0
+; SI-NEXT:    v_mov_b32_e32 v0, s0
+; SI-NEXT:    ; return to shader part epilog
+;
+; VI-LABEL: s_copysign_bf16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_xor_b32 s0, s0, 0x8000
+; VI-NEXT:    s_and_b32 s0, 0x8000, s0
+; VI-NEXT:    v_mov_b32_e32 v0, s0
+; VI-NEXT:    ; return to shader part epilog
+;
+; GCN-LABEL: s_copysign_bf16_0_fneg:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_andn2_b32 s0, 0xffff8000, s0
+; GCN-NEXT:    ; return to shader part epilog
+;
+; GFX7-LABEL: s_copysign_bf16_0_fneg:
+; GFX7:       ; %bb.0:
+; GFX7-NEXT:    s_andn2_b32 s0, 0xffff8000, s0
+; GFX7-NEXT:    ; return to shader part epilog
+;
+; GFX8-LABEL: s_copysign_bf16_0_fneg:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX8-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX8-NEXT:    v_mov_b32_e32 v0, s0
+; GFX8-NEXT:    ; return to shader part epilog
+;
+; GFX9-LABEL: s_copysign_bf16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX9-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX9-NEXT:    v_mov_b32_e32 v0, s0
+; GFX9-NEXT:    ; return to shader part epilog
+;
+; GFX10-LABEL: s_copysign_bf16_0_fneg:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX10-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX10-NEXT:    v_mov_b32_e32 v0, s0
+; GFX10-NEXT:    ; return to shader part epilog
+;
+; GFX11TRUE16-LABEL: s_copysign_bf16_0_fneg:
+; GFX11TRUE16:       ; %bb.0:
+; GFX11TRUE16-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX11TRUE16-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, s0
+; GFX11TRUE16-NEXT:    ; return to shader part epilog
+;
+; GFX11FAKE16-LABEL: s_copysign_bf16_0_fneg:
+; GFX11FAKE16:       ; %bb.0:
+; GFX11FAKE16-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX11FAKE16-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11FAKE16-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX11FAKE16-NEXT:    v_mov_b32_e32 v0, s0
+; GFX11FAKE16-NEXT:    ; return to shader part epilog
+; GFX11-TRUE16-LABEL: s_copysign_bf16_0_fneg:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX11-TRUE16-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, s0
+; GFX11-TRUE16-NEXT:    ; return to shader part epilog
+; GFX11-FAKE16-LABEL: s_copysign_bf16_0_fneg:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX11-FAKE16-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-FAKE16-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX11-FAKE16-NEXT:    v_mov_b32_e32 v0, s0
+; GFX11-FAKE16-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg bfloat %sign
+  %result = call bfloat @llvm.copysign.bf16(bfloat 0.0, bfloat %sign.ext)
+  ret bfloat %result
+}
+
+define bfloat @v_copysign_bf16_0_fneg(bfloat %sign) {
+; SIVI-LABEL: v_copysign_bf16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-LABEL: v_copysign_bf16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    s_movk_i32 s4, 0x8000
+; SI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-LABEL: v_copysign_bf16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-NEXT:    s_mov_b32 s4, 0x8000
+; VI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; VI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GCN-LABEL: v_copysign_bf16_0_fneg:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT:    s_movk_i32 s4, 0x8000
+; GCN-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; GCN-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: v_copysign_bf16_0_fneg:
+; GFX7:       ; %bb.0:
+; GFX7-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT:    s_movk_i32 s4, 0x8000
+; GFX7-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; GFX7-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_copysign_bf16_0_fneg:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; GFX8-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_copysign_bf16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; GFX9-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: v_copysign_bf16_0_fneg:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; GFX10-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11TRUE16-LABEL: v_copysign_bf16_0_fneg:
+; GFX11TRUE16:       ; %bb.0:
+; GFX11TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11TRUE16-NEXT:    v_xor_b16 v0.l, 0x8000, v0.l
+; GFX11TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, v0.l
+; GFX11TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11FAKE16-LABEL: v_copysign_bf16_0_fneg:
+; GFX11FAKE16:       ; %bb.0:
+; GFX11FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11FAKE16-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; GFX11FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11FAKE16-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX11FAKE16-NEXT:    s_setpc_b64 s[30:31]
+  %sign.ext = fneg bfloat %sign
+  %result = call bfloat @llvm.copysign.bf16(bfloat 0.0, bfloat %sign.ext)
+  ret bfloat %result
+}
+
+define amdgpu_ps <2 x bfloat> @s_copysign_v2bf16_0_fneg(<2 x bfloat> inreg %sign) {
+; SIVI-LABEL: s_copysign_v2bf16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s1, s1, 0x80000000
+; SIVI-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; SIVI-NEXT:    s_and_b32 s0, 0x80000000, s0
+; SIVI-NEXT:    s_and_b32 s1, 0x80000000, s1
+; SIVI-NEXT:    v_mov_b32_e32 v0, s0
+; SIVI-NEXT:    v_mov_b32_e32 v1, s1
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; SI-LABEL: s_copysign_v2bf16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_andn2_b32 s0, 0x80008000, s0
+; SI-NEXT:    v_mov_b32_e32 v0, s0
+; SI-NEXT:    ; return to shader part epilog
+;
+; VI-LABEL: s_copysign_v2bf16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; VI-NEXT:    s_mov_b32 s1, 0x7fff7fff
+; VI-NEXT:    v_mov_b32_e32 v0, s0
+; VI-NEXT:    v_bfi_b32 v0, s1, 0, v0
+; VI-NEXT:    ; return to shader part epilog
+;
+; GCN-LABEL: s_copysign_v2bf16_0_fneg:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_andn2_b32 s0, 0x80008000, s0
+; GCN-NEXT:    ; return to shader part epilog
+;
+; GFX7-LABEL: s_copysign_v2bf16_0_fneg:
+; GFX7:       ; %bb.0:
+; GFX7-NEXT:    s_andn2_b32 s0, 0x80008000, s0
+; GFX7-NEXT:    ; return to shader part epilog
+;
+; GFX8-LABEL: s_copysign_v2bf16_0_fneg:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; GFX8-NEXT:    s_mov_b32 s1, 0x7fff7fff
+; GFX8-NEXT:    v_mov_b32_e32 v0, s0
+; GFX8-NEXT:    v_bfi_b32 v0, s1, 0, v0
+; GFX8-NEXT:    ; return to shader part epilog
+;
+; GFX9-LABEL: s_copysign_v2bf16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; GFX9-NEXT:    s_and_b32 s0, 0x80008000, s0
+; GFX9-NEXT:    v_mov_b32_e32 v0, s0
+; GFX9-NEXT:    ; return to shader part epilog
+;
+; GFX10-LABEL: s_copysign_v2bf16_0_fneg:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; GFX10-NEXT:    s_and_b32 s0, 0x80008000, s0
+; GFX10-NEXT:    v_mov_b32_e32 v0, s0
+; GFX10-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_copysign_v2bf16_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; GFX11-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT:    s_and_b32 s0, 0x80008000, s0
+; GFX11-NEXT:    v_mov_b32_e32 v0, s0
+; GFX11-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg <2 x bfloat> %sign
+  %result = call <2 x bfloat> @llvm.copysign.v2bf16(<2 x bfloat> zeroinitializer, <2 x bfloat> %sign.ext)
+  ret <2 x bfloat> %result
+}
+
+define <2 x bfloat> @v_copysign_v2bf16_0_fneg(<2 x bfloat> %sign) {
+; SIVI-LABEL: v_copysign_v2bf16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SIVI-NEXT:    v_bfi_b32 v1, v1, 0, s4
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-LABEL: v_copysign_v2bf16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    s_mov_b32 s4, 0x80008000
+; SI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-LABEL: v_copysign_v2bf16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; VI-NEXT:    s_mov_b32 s4, 0x7fff7fff
+; VI-NEXT:    v_bfi_b32 v0, s4, 0, v0
+; VI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GCN-LABEL: v_copysign_v2bf16_0_fneg:
+; GCN:       ; %bb.0:
+; GCN-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GCN-NEXT:    s_mov_b32 s4, 0x80008000
+; GCN-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; GCN-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX7-LABEL: v_copysign_v2bf16_0_fneg:
+; GFX7:       ; %bb.0:
+; GFX7-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX7-NEXT:    s_mov_b32 s4, 0x80008000
+; GFX7-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; GFX7-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX8-LABEL: v_copysign_v2bf16_0_fneg:
+; GFX8:       ; %bb.0:
+; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX8-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; GFX8-NEXT:    s_mov_b32 s4, 0x7fff7fff
+; GFX8-NEXT:    v_bfi_b32 v0, s4, 0, v0
+; GFX8-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_copysign_v2bf16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; GFX9-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: v_copysign_v2bf16_0_fneg:
+; GFX10:       ; %bb.0:
+; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; GFX10-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX10-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_copysign_v2bf16_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %sign.ext = fneg <2 x bfloat> %sign
+  %result = call <2 x bfloat> @llvm.copysign.v2bf16(<2 x bfloat> zeroinitializer, <2 x bfloat> %sign.ext)
+  ret <2 x bfloat> %result
+}
+
 attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll
index 19916e6d10f67..842440b1ec6d6 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll
@@ -7254,4 +7254,187 @@ define <2 x half> @v_copysign_v2f16_0_v2bf64(<2 x double> %sign) {
   ret <2 x half> %op
 }
 
+define amdgpu_ps half @s_copysign_f16_0_fneg(half inreg %sign) {
+; SIVI-LABEL: s_copysign_f16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; SIVI-NEXT:    s_and_b32 s0, 0x80000000, s0
+; SIVI-NEXT:    v_mov_b32_e32 v0, s0
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; SI-LABEL: s_copysign_f16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_andn2_b32 s0, 0xffff8000, s0
+; SI-NEXT:    v_mov_b32_e32 v0, s0
+; SI-NEXT:    ; return to shader part epilog
+;
+; VI-LABEL: s_copysign_f16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_xor_b32 s0, s0, 0x8000
+; VI-NEXT:    s_and_b32 s0, 0x8000, s0
+; VI-NEXT:    v_mov_b32_e32 v0, s0
+; VI-NEXT:    ; return to shader part epilog
+;
+; GFX9-LABEL: s_copysign_f16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX9-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX9-NEXT:    v_mov_b32_e32 v0, s0
+; GFX9-NEXT:    ; return to shader part epilog
+;
+; GFX11-TRUE16-LABEL: s_copysign_f16_0_fneg:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX11-TRUE16-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, s0
+; GFX11-TRUE16-NEXT:    ; return to shader part epilog
+;
+; GFX11-FAKE16-LABEL: s_copysign_f16_0_fneg:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_xor_b32 s0, s0, 0x8000
+; GFX11-FAKE16-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-FAKE16-NEXT:    s_and_b32 s0, 0x8000, s0
+; GFX11-FAKE16-NEXT:    v_mov_b32_e32 v0, s0
+; GFX11-FAKE16-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg half %sign
+  %result = call half @llvm.copysign.f16(half 0.0, half %sign.ext)
+  ret half %result
+}
+
+define half @v_copysign_f16_0_fneg(half %sign) {
+; SIVI-LABEL: v_copysign_f16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-LABEL: v_copysign_f16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    s_movk_i32 s4, 0x8000
+; SI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-LABEL: v_copysign_f16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; VI-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; VI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_copysign_f16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; GFX9-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-TRUE16-LABEL: v_copysign_f16_0_fneg:
+; GFX11-TRUE16:       ; %bb.0:
+; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-TRUE16-NEXT:    v_xor_b16 v0.l, 0x8000, v0.l
+; GFX11-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, v0.l
+; GFX11-TRUE16-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-FAKE16-LABEL: v_copysign_f16_0_fneg:
+; GFX11-FAKE16:       ; %bb.0:
+; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-FAKE16-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
+; GFX11-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-FAKE16-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX11-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+  %sign.ext = fneg half %sign
+  %result = call half @llvm.copysign.f16(half 0.0, half %sign.ext)
+  ret half %result
+}
+
+define amdgpu_ps <2 x half> @s_copysign_v2f16_0_fneg(<2 x half> inreg %sign) {
+; SIVI-LABEL: s_copysign_v2f16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s1, s1, 0x80000000
+; SIVI-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; SIVI-NEXT:    s_and_b32 s0, 0x80000000, s0
+; SIVI-NEXT:    s_and_b32 s1, 0x80000000, s1
+; SIVI-NEXT:    v_mov_b32_e32 v0, s0
+; SIVI-NEXT:    v_mov_b32_e32 v1, s1
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; SI-LABEL: s_copysign_v2f16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_andn2_b32 s0, 0x80008000, s0
+; SI-NEXT:    v_mov_b32_e32 v0, s0
+; SI-NEXT:    ; return to shader part epilog
+;
+; VI-LABEL: s_copysign_v2f16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; VI-NEXT:    s_mov_b32 s1, 0x7fff7fff
+; VI-NEXT:    v_mov_b32_e32 v0, s0
+; VI-NEXT:    v_bfi_b32 v0, s1, 0, v0
+; VI-NEXT:    ; return to shader part epilog
+;
+; GFX9-LABEL: s_copysign_v2f16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; GFX9-NEXT:    s_and_b32 s0, 0x80008000, s0
+; GFX9-NEXT:    v_mov_b32_e32 v0, s0
+; GFX9-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_copysign_v2f16_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_xor_b32 s0, s0, 0x80008000
+; GFX11-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT:    s_and_b32 s0, 0x80008000, s0
+; GFX11-NEXT:    v_mov_b32_e32 v0, s0
+; GFX11-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg <2 x half> %sign
+  %result = call <2 x half> @llvm.copysign.v2f16(<2 x half> zeroinitializer, <2 x half> %sign.ext)
+  ret <2 x half> %result
+}
+
+define <2 x half> @v_copysign_v2f16_0_fneg(<2 x half> %sign) {
+; SIVI-LABEL: v_copysign_v2f16_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SIVI-NEXT:    v_bfi_b32 v1, v1, 0, s4
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; SI-LABEL: v_copysign_v2f16_0_fneg:
+; SI:       ; %bb.0:
+; SI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SI-NEXT:    s_mov_b32 s4, 0x80008000
+; SI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SI-NEXT:    s_setpc_b64 s[30:31]
+;
+; VI-LABEL: v_copysign_v2f16_0_fneg:
+; VI:       ; %bb.0:
+; VI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; VI-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; VI-NEXT:    s_mov_b32 s4, 0x7fff7fff
+; VI-NEXT:    v_bfi_b32 v0, s4, 0, v0
+; VI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX9-LABEL: v_copysign_v2f16_0_fneg:
+; GFX9:       ; %bb.0:
+; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; GFX9-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX9-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_copysign_v2f16_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %sign.ext = fneg <2 x half> %sign
+  %result = call <2 x half> @llvm.copysign.v2f16(<2 x half> zeroinitializer, <2 x half> %sign.ext)
+  ret <2 x half> %result
+}
+
 attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll
index e3eb35ad15eff..313331e72512e 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll
@@ -1223,6 +1223,95 @@ define float @v_copysign_f32_0_f16(half %sign) {
   ret float %result
 }
 
+define amdgpu_ps float @s_copysign_f32_0_fneg(float inreg %sign) {
+; SIVI-LABEL: s_copysign_f32_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; SIVI-NEXT:    s_and_b32 s0, 0x80000000, s0
+; SIVI-NEXT:    v_mov_b32_e32 v0, s0
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_copysign_f32_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; GFX11-NEXT:    s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT:    s_and_b32 s0, 0x80000000, s0
+; GFX11-NEXT:    v_mov_b32_e32 v0, s0
+; GFX11-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg float %sign
+  %result = call float @llvm.copysign.f32(float 0.0, float %sign.ext)
+  ret float %result
+}
+
+define float @v_copysign_f32_0_fneg(float %sign) {
+; SIVI-LABEL: v_copysign_f32_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
+; SIVI-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_copysign_f32_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %sign.ext = fneg float %sign
+  %result = call float @llvm.copysign.f32(float 0.0, float %sign.ext)
+  ret float %result
+}
+
+define amdgpu_ps <2 x float> @s_copysign_v2f32_0_fneg(<2 x float> inreg %sign) {
+; SIVI-LABEL: s_copysign_v2f32_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s1, s1, 0x80000000
+; SIVI-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; SIVI-NEXT:    s_and_b32 s0, 0x80000000, s0
+; SIVI-NEXT:    s_and_b32 s1, 0x80000000, s1
+; SIVI-NEXT:    v_mov_b32_e32 v0, s0
+; SIVI-NEXT:    v_mov_b32_e32 v1, s1
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_copysign_v2f32_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_xor_b32 s0, s0, 0x80000000
+; GFX11-NEXT:    s_xor_b32 s1, s1, 0x80000000
+; GFX11-NEXT:    s_and_b32 s0, 0x80000000, s0
+; GFX11-NEXT:    s_and_b32 s1, 0x80000000, s1
+; GFX11-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT:    v_dual_mov_b32 v0, s0 :: v_dual_mov_b32 v1, s1
+; GFX11-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg <2 x float> %sign
+  %result = call <2 x float> @llvm.copysign.v2f32(<2 x float> zeroinitializer, <2 x float> %sign.ext)
+  ret <2 x float> %result
+}
+
+define <2 x float> @v_copysign_v2f32_0_fneg(<2 x float> %sign) {
+; SIVI-LABEL: v_copysign_v2f32_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    v_xor_b32_e32 v1, 0x80000000, v1
+; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
+; SIVI-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
+; SIVI-NEXT:    v_and_b32_e32 v1, 0x80000000, v1
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_copysign_v2f32_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
+; GFX11-NEXT:    v_xor_b32_e32 v1, 0x80000000, v1
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
+; GFX11-NEXT:    v_and_b32_e32 v1, 0x80000000, v1
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %sign.ext = fneg <2 x float> %sign
+  %result = call <2 x float> @llvm.copysign.v2f32(<2 x float> zeroinitializer, <2 x float> %sign.ext)
+  ret <2 x float> %result
+}
+
 declare float @llvm.copysign.f32(float, float) #0
 declare <2 x float> @llvm.copysign.v2f32(<2 x float>, <2 x float>) #0
 declare <3 x float> @llvm.copysign.v3f32(<3 x float>, <3 x float>) #0
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll
index 819d4e289b4a9..7c182573d1ac7 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll
@@ -1188,4 +1188,96 @@ define double @v_copysign_f64_0_f16(half %sign) {
   ret double %result
 }
 
+define amdgpu_ps double @s_copysign_f64_0_fneg(double inreg %sign) {
+; SIVI-LABEL: s_copysign_f64_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s0, s1, 0x80000000
+; SIVI-NEXT:    s_and_b32 s1, s0, 0x80000000
+; SIVI-NEXT:    s_mov_b32 s0, 0
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_copysign_f64_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_xor_b32 s0, s1, 0x80000000
+; GFX11-NEXT:    s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT:    s_and_b32 s1, s0, 0x80000000
+; GFX11-NEXT:    s_mov_b32 s0, 0
+; GFX11-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg double %sign
+  %result = call double @llvm.copysign.f64(double 0.0, double %sign.ext)
+  ret double %result
+}
+
+define double @v_copysign_f64_0_fneg(double %sign) {
+; SIVI-LABEL: v_copysign_f64_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v1
+; SIVI-NEXT:    v_and_b32_e32 v1, 0x80000000, v0
+; SIVI-NEXT:    v_mov_b32_e32 v0, 0
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_copysign_f64_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v1
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT:    v_dual_mov_b32 v0, 0 :: v_dual_and_b32 v1, 0x80000000, v0
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %neg.sign = fneg double %sign
+  %result = call double @llvm.copysign.f64(double 0.0, double %neg.sign)
+  ret double %result
+}
+
+define amdgpu_ps <2 x double> @s_copysign_v2f64_0_fneg(<2 x double> inreg %sign) {
+; SIVI-LABEL: s_copysign_v2f64_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_xor_b32 s0, s1, 0x80000000
+; SIVI-NEXT:    s_xor_b32 s1, s3, 0x80000000
+; SIVI-NEXT:    s_and_b32 s3, s1, 0x80000000
+; SIVI-NEXT:    s_and_b32 s1, s0, 0x80000000
+; SIVI-NEXT:    s_mov_b32 s0, 0
+; SIVI-NEXT:    s_mov_b32 s2, 0
+; SIVI-NEXT:    ; return to shader part epilog
+;
+; GFX11-LABEL: s_copysign_v2f64_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_xor_b32 s0, s3, 0x80000000
+; GFX11-NEXT:    s_xor_b32 s1, s1, 0x80000000
+; GFX11-NEXT:    s_and_b32 s3, s0, 0x80000000
+; GFX11-NEXT:    s_and_b32 s1, s1, 0x80000000
+; GFX11-NEXT:    s_mov_b32 s0, 0
+; GFX11-NEXT:    s_mov_b32 s2, 0
+; GFX11-NEXT:    ; return to shader part epilog
+  %sign.ext = fneg <2 x double> %sign
+  %result = call <2 x double> @llvm.copysign.v2f64(<2 x double> zeroinitializer, <2 x double> %sign.ext)
+  ret <2 x double> %result
+}
+
+define <2 x double> @v_copysign_v2f64_0_fneg(<2 x double> %sign) {
+; SIVI-LABEL: v_copysign_v2f64_0_fneg:
+; SIVI:       ; %bb.0:
+; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v3
+; SIVI-NEXT:    v_xor_b32_e32 v1, 0x80000000, v1
+; SIVI-NEXT:    v_and_b32_e32 v1, 0x80000000, v1
+; SIVI-NEXT:    v_and_b32_e32 v3, 0x80000000, v0
+; SIVI-NEXT:    v_mov_b32_e32 v0, 0
+; SIVI-NEXT:    v_mov_b32_e32 v2, 0
+; SIVI-NEXT:    s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: v_copysign_v2f64_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v1
+; GFX11-NEXT:    v_xor_b32_e32 v2, 0x80000000, v3
+; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
+; GFX11-NEXT:    v_dual_mov_b32 v0, 0 :: v_dual_and_b32 v1, 0x80000000, v0
+; GFX11-NEXT:    v_dual_mov_b32 v2, 0 :: v_dual_and_b32 v3, 0x80000000, v2
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
+  %neg.sign = fneg <2 x double> %sign
+  %result = call <2 x double> @llvm.copysign.v2f64(<2 x double> zeroinitializer, <2 x double> %neg.sign)
+  ret <2 x double> %result
+}
+
 attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

>From 776c78f07545e86ff98a6027967f54b8cbb25476 Mon Sep 17 00:00:00 2001
From: Madhur Kumar <madhurkumar004 at gmail.com>
Date: Thu, 16 Jul 2026 14:57:26 +0530
Subject: [PATCH 2/2] [AMDGPU] Improve codegen for copysign(x, fneg(y))

---
 llvm/lib/Target/AMDGPU/SIInstructions.td   | 36 +++++++++++++++++++
 llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll | 42 ++++++++--------------
 llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll  | 36 +++++++------------
 llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll  | 22 +++++-------
 llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll  | 25 ++++++-------
 5 files changed, 81 insertions(+), 80 deletions(-)

diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index d978735a92db8..47610d3fab1b7 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -2420,6 +2420,11 @@ def : GCNPat <
   (S_AND_B32 (S_MOV_B32 (i32 0x00008000)), SReg_32:$src1)
 >;
 
+def : GCNPat <
+  (DivergentBinFrag<fcopysign> (fp16vt fpimm_zero), (fneg fp16vt:$src1)),
+  (V_BFI_B32_e64 VGPR_32:$src1, (i32 0), (S_MOV_B32 (i32 0x00008000)))
+>;
+
 def : GCNPat <
   (fcopysign (fp16vt fpimm_pos_zero), fp16vt:$src1),
   (V_AND_B32_e32 (S_MOV_B32 (i32 0x00008000)), VGPR_32:$src1)
@@ -2489,6 +2494,12 @@ def : GCNPat <
   (V_AND_B16_t16_e64 0, (S_MOV_B32 (i32 0x00008000)), 0, VGPR_16:$src1)
 >;
 
+def : GCNPat <
+  (DivergentBinFrag<fcopysign> (fp16vt fpimm_zero), (fneg fp16vt:$src1)),
+  (V_BFI_B32_e64 (REG_SEQUENCE VGPR_32, VGPR_16:$src1, lo16, (i16 (IMPLICIT_DEF)), hi16),
+    (i32 0), (S_MOV_B32 (i32 0x00008000)))
+>;
+
 // TODO: Handle 0 magnitude special case
 def : GCNPat <
   (fcopysign f32:$src0, fp16vt:$src1),
@@ -2553,6 +2564,11 @@ def : GCNPat <
   (V_AND_B32_e32 (S_MOV_B32 (i32 0x80008000)), VGPR_32:$src1)
 >;
 
+def : GCNPat <
+  (DivergentBinFrag<fcopysign> build_vector_fpimm_pos_zero_v2<fp16vt> , (fneg fp16vt:$src1)),
+  (V_BFI_B32_e64 VGPR_32:$src1, (i32 0), (S_MOV_B32 (i32 0x80008000)))
+>;
+
 }
 
 /********** ================== **********/
@@ -2938,11 +2954,31 @@ def : AMDGPUPat <
   (S_AND_B32 (S_MOV_B32 (i32 0x80000000)), $src1)
 >;
 
+def : AMDGPUPat <
+  (DivergentBinFrag<fcopysign> (f32 fpimm_zero), (fneg f32:$src1)),
+  (V_BFI_B32_e64 VGPR_32:$src1, (i32 0), (S_MOV_B32 (i32 0x80000000)))
+>;
+
 def : AMDGPUPat <
   (fcopysign (f32 fpimm_pos_zero), (f32 VGPR_32:$src1)),
   (V_AND_B32_e32 (S_MOV_B32 (i32 0x80000000)), $src1)
 >;
 
+def : AMDGPUPat <
+  (DivergentBinFrag<and> (extractelt (v2i32 (bitconvert (f64 (fneg f64:$src1)))), (i32 1)),
+       (i32 -2147483648)),
+  (V_BFI_B32_e64 (i32 (EXTRACT_SUBREG VReg_64:$src1, sub1)),
+                 (i32 0), (S_MOV_B32 (i32 0x80000000)))
+>;
+
+
+def : AMDGPUPat <
+  (DivergentBinFrag<and> (i32 (bitconvert (extractelt (v2f32 (bitconvert (fneg f64:$src1))), (i32 1)))),
+       (i32 -2147483648)),
+  (V_BFI_B32_e64 (i32 (EXTRACT_SUBREG VReg_64:$src1, sub1)),
+                 (i32 0), (S_MOV_B32 (i32 0x80000000)))
+>;
+
 def : AMDGPUPat <
   (fcopysign f32:$src0, f64:$src1),
   (V_BFI_B32_e64 (S_MOV_B32 (i32 0x7fffffff)), $src0,
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll
index d896b1888d6bf..d271604b3f6ec 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.bf16.ll
@@ -8186,39 +8186,28 @@ define bfloat @v_copysign_bf16_0_fneg(bfloat %sign) {
 ; GFX8-LABEL: v_copysign_bf16_0_fneg:
 ; GFX8:       ; %bb.0:
 ; GFX8-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX8-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; GFX8-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX8-NEXT:    s_mov_b32 s4, 0x8000
+; GFX8-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; GFX8-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: v_copysign_bf16_0_fneg:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; GFX9-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX9-NEXT:    s_mov_b32 s4, 0x8000
+; GFX9-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_copysign_bf16_0_fneg:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; GFX10-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX10-NEXT:    v_bfi_b32 v0, v0, 0, 0x8000
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX11TRUE16-LABEL: v_copysign_bf16_0_fneg:
-; GFX11TRUE16:       ; %bb.0:
-; GFX11TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11TRUE16-NEXT:    v_xor_b16 v0.l, 0x8000, v0.l
-; GFX11TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, v0.l
-; GFX11TRUE16-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX11FAKE16-LABEL: v_copysign_bf16_0_fneg:
-; GFX11FAKE16:       ; %bb.0:
-; GFX11FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11FAKE16-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; GFX11FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11FAKE16-NEXT:    v_and_b32_e32 v0, 0x8000, v0
-; GFX11FAKE16-NEXT:    s_setpc_b64 s[30:31]
+; GFX11-LABEL: v_copysign_bf16_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_bfi_b32 v0, v0, 0, 0x8000
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %sign.ext = fneg bfloat %sign
   %result = call bfloat @llvm.copysign.bf16(bfloat 0.0, bfloat %sign.ext)
   ret bfloat %result
@@ -8342,23 +8331,20 @@ define <2 x bfloat> @v_copysign_v2bf16_0_fneg(<2 x bfloat> %sign) {
 ; GFX9-LABEL: v_copysign_v2bf16_0_fneg:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
-; GFX9-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX9-NEXT:    s_mov_b32 s4, 0x80008000
+; GFX9-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX10-LABEL: v_copysign_v2bf16_0_fneg:
 ; GFX10:       ; %bb.0:
 ; GFX10-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX10-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
-; GFX10-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX10-NEXT:    v_bfi_b32 v0, v0, 0, 0x80008000
 ; GFX10-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: v_copysign_v2bf16_0_fneg:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
-; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX11-NEXT:    v_bfi_b32 v0, v0, 0, 0x80008000
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %sign.ext = fneg <2 x bfloat> %sign
   %result = call <2 x bfloat> @llvm.copysign.v2bf16(<2 x bfloat> zeroinitializer, <2 x bfloat> %sign.ext)
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll
index 842440b1ec6d6..cede71cba20e9 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.f16.ll
@@ -7319,32 +7319,22 @@ define half @v_copysign_f16_0_fneg(half %sign) {
 ; VI-LABEL: v_copysign_f16_0_fneg:
 ; VI:       ; %bb.0:
 ; VI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; VI-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; VI-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; VI-NEXT:    s_mov_b32 s4, 0x8000
+; VI-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; VI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX9-LABEL: v_copysign_f16_0_fneg:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; GFX9-NEXT:    v_and_b32_e32 v0, 0x8000, v0
+; GFX9-NEXT:    s_mov_b32 s4, 0x8000
+; GFX9-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
-; GFX11-TRUE16-LABEL: v_copysign_f16_0_fneg:
-; GFX11-TRUE16:       ; %bb.0:
-; GFX11-TRUE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-TRUE16-NEXT:    v_xor_b16 v0.l, 0x8000, v0.l
-; GFX11-TRUE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-TRUE16-NEXT:    v_and_b16 v0.l, 0x8000, v0.l
-; GFX11-TRUE16-NEXT:    s_setpc_b64 s[30:31]
-;
-; GFX11-FAKE16-LABEL: v_copysign_f16_0_fneg:
-; GFX11-FAKE16:       ; %bb.0:
-; GFX11-FAKE16-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-FAKE16-NEXT:    v_xor_b32_e32 v0, 0x8000, v0
-; GFX11-FAKE16-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-FAKE16-NEXT:    v_and_b32_e32 v0, 0x8000, v0
-; GFX11-FAKE16-NEXT:    s_setpc_b64 s[30:31]
+; GFX11-LABEL: v_copysign_f16_0_fneg:
+; GFX11:       ; %bb.0:
+; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT:    v_bfi_b32 v0, v0, 0, 0x8000
+; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %sign.ext = fneg half %sign
   %result = call half @llvm.copysign.f16(half 0.0, half %sign.ext)
   ret half %result
@@ -7421,16 +7411,14 @@ define <2 x half> @v_copysign_v2f16_0_fneg(<2 x half> %sign) {
 ; GFX9-LABEL: v_copysign_v2f16_0_fneg:
 ; GFX9:       ; %bb.0:
 ; GFX9-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX9-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
-; GFX9-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX9-NEXT:    s_mov_b32 s4, 0x80008000
+; GFX9-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; GFX9-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: v_copysign_v2f16_0_fneg:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80008000, v0
-; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-NEXT:    v_and_b32_e32 v0, 0x80008000, v0
+; GFX11-NEXT:    v_bfi_b32 v0, v0, 0, 0x80008000
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %sign.ext = fneg <2 x half> %sign
   %result = call <2 x half> @llvm.copysign.v2f16(<2 x half> zeroinitializer, <2 x half> %sign.ext)
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll
index 313331e72512e..a47faca0fa968 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.f32.ll
@@ -1247,16 +1247,14 @@ define float @v_copysign_f32_0_fneg(float %sign) {
 ; SIVI-LABEL: v_copysign_f32_0_fneg:
 ; SIVI:       ; %bb.0:
 ; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
-; SIVI-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v0, v0, 0, s4
 ; SIVI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: v_copysign_f32_0_fneg:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
-; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
+; GFX11-NEXT:    v_bfi_b32 v0, v0, 0, 0x80000000
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %sign.ext = fneg float %sign
   %result = call float @llvm.copysign.f32(float 0.0, float %sign.ext)
@@ -1292,20 +1290,16 @@ define <2 x float> @v_copysign_v2f32_0_fneg(<2 x float> %sign) {
 ; SIVI-LABEL: v_copysign_v2f32_0_fneg:
 ; SIVI:       ; %bb.0:
 ; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SIVI-NEXT:    v_xor_b32_e32 v1, 0x80000000, v1
-; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
-; SIVI-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
-; SIVI-NEXT:    v_and_b32_e32 v1, 0x80000000, v1
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v0, v0, 0, s4
+; SIVI-NEXT:    v_bfi_b32 v1, v1, 0, s4
 ; SIVI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: v_copysign_v2f32_0_fneg:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v0
-; GFX11-NEXT:    v_xor_b32_e32 v1, 0x80000000, v1
-; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
-; GFX11-NEXT:    v_and_b32_e32 v0, 0x80000000, v0
-; GFX11-NEXT:    v_and_b32_e32 v1, 0x80000000, v1
+; GFX11-NEXT:    v_bfi_b32 v0, v0, 0, 0x80000000
+; GFX11-NEXT:    v_bfi_b32 v1, v1, 0, 0x80000000
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %sign.ext = fneg <2 x float> %sign
   %result = call <2 x float> @llvm.copysign.v2f32(<2 x float> zeroinitializer, <2 x float> %sign.ext)
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll b/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll
index 7c182573d1ac7..1bc83ba35874a 100644
--- a/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign.f64.ll
@@ -1212,17 +1212,16 @@ define double @v_copysign_f64_0_fneg(double %sign) {
 ; SIVI-LABEL: v_copysign_f64_0_fneg:
 ; SIVI:       ; %bb.0:
 ; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v1
-; SIVI-NEXT:    v_and_b32_e32 v1, 0x80000000, v0
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v1, v1, 0, s4
 ; SIVI-NEXT:    v_mov_b32_e32 v0, 0
 ; SIVI-NEXT:    s_setpc_b64 s[30:31]
 ;
 ; GFX11-LABEL: v_copysign_f64_0_fneg:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v1
-; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_1)
-; GFX11-NEXT:    v_dual_mov_b32 v0, 0 :: v_dual_and_b32 v1, 0x80000000, v0
+; GFX11-NEXT:    v_bfi_b32 v1, v1, 0, 0x80000000
+; GFX11-NEXT:    v_mov_b32_e32 v0, 0
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %neg.sign = fneg double %sign
   %result = call double @llvm.copysign.f64(double 0.0, double %neg.sign)
@@ -1258,10 +1257,9 @@ define <2 x double> @v_copysign_v2f64_0_fneg(<2 x double> %sign) {
 ; SIVI-LABEL: v_copysign_v2f64_0_fneg:
 ; SIVI:       ; %bb.0:
 ; SIVI-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; SIVI-NEXT:    v_xor_b32_e32 v0, 0x80000000, v3
-; SIVI-NEXT:    v_xor_b32_e32 v1, 0x80000000, v1
-; SIVI-NEXT:    v_and_b32_e32 v1, 0x80000000, v1
-; SIVI-NEXT:    v_and_b32_e32 v3, 0x80000000, v0
+; SIVI-NEXT:    s_brev_b32 s4, 1
+; SIVI-NEXT:    v_bfi_b32 v1, v1, 0, s4
+; SIVI-NEXT:    v_bfi_b32 v3, v3, 0, s4
 ; SIVI-NEXT:    v_mov_b32_e32 v0, 0
 ; SIVI-NEXT:    v_mov_b32_e32 v2, 0
 ; SIVI-NEXT:    s_setpc_b64 s[30:31]
@@ -1269,11 +1267,10 @@ define <2 x double> @v_copysign_v2f64_0_fneg(<2 x double> %sign) {
 ; GFX11-LABEL: v_copysign_v2f64_0_fneg:
 ; GFX11:       ; %bb.0:
 ; GFX11-NEXT:    s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
-; GFX11-NEXT:    v_xor_b32_e32 v0, 0x80000000, v1
-; GFX11-NEXT:    v_xor_b32_e32 v2, 0x80000000, v3
-; GFX11-NEXT:    s_delay_alu instid0(VALU_DEP_2) | instskip(NEXT) | instid1(VALU_DEP_2)
-; GFX11-NEXT:    v_dual_mov_b32 v0, 0 :: v_dual_and_b32 v1, 0x80000000, v0
-; GFX11-NEXT:    v_dual_mov_b32 v2, 0 :: v_dual_and_b32 v3, 0x80000000, v2
+; GFX11-NEXT:    v_bfi_b32 v1, v1, 0, 0x80000000
+; GFX11-NEXT:    v_bfi_b32 v3, v3, 0, 0x80000000
+; GFX11-NEXT:    v_mov_b32_e32 v0, 0
+; GFX11-NEXT:    v_mov_b32_e32 v2, 0
 ; GFX11-NEXT:    s_setpc_b64 s[30:31]
   %neg.sign = fneg <2 x double> %sign
   %result = call <2 x double> @llvm.copysign.v2f64(<2 x double> zeroinitializer, <2 x double> %neg.sign)



More information about the llvm-commits mailing list