[llvm] [AMDGPU] Improve codegen for copysign(x, fneg(y)) (PR #207178)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 2 06:03:12 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
Author: Madhur Kumar (MadhurKumar004)
<details>
<summary>Changes</summary>
Fixes: https://github.com/llvm/llvm-project/issues/174009
---
Full diff: https://github.com/llvm/llvm-project/pull/207178.diff
2 Files Affected:
- (modified) llvm/lib/Target/AMDGPU/SIISelLowering.cpp (+15-1)
- (added) llvm/test/CodeGen/AMDGPU/fcopysign-fneg.ll (+26)
``````````diff
diff --git a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
index e0b0fe46d44a6..7227ce73989e8 100644
--- a/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
+++ b/llvm/lib/Target/AMDGPU/SIISelLowering.cpp
@@ -14159,11 +14159,25 @@ SDValue SITargetLowering::performFCopySignCombine(SDNode *N,
SelectionDAG &DAG = DCI.DAG;
SDLoc DL(N);
EVT SignVT = SignOp.getValueType();
+ EVT MagVT = MagnitudeOp.getValueType();
+
+ // copysign(0.0, fneg(x)) for f32: fold to and(signmask, not(bitcast(x)))
+ // which AMDGPU ISel matches as V_BFI_B32(x, 0, signmask)
+ if (SignOp.getOpcode() == ISD::FNEG && MagVT == MVT::f32) {
+ SDValue StrippedSign = SignOp.getOperand(0);
+ ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(MagnitudeOp);
+ if (StrippedSign.getValueType() == MVT::f32 && C && C->isZero()) {
+ SDValue SignAsInt = DAG.getBitcast(MVT::i32, StrippedSign);
+ SDValue NotSign = DAG.getNOT(DL, SignAsInt, MVT::i32);
+ SDValue MaskC = DAG.getConstant(0x80000000, DL, MVT::i32);
+ SDValue And = DAG.getNode(ISD::AND, DL, MVT::i32, MaskC, NotSign);
+ return DAG.getBitcast(MVT::f32, And);
+ }
+ }
// f64 fcopysign is really an f32 copysign on the high bits, so replace the
// lower half with a copy.
// fcopysign f64:x, _:y -> x.lo32, (fcopysign (f32 x.hi32), _:y)
- EVT MagVT = MagnitudeOp.getValueType();
unsigned NumElts = MagVT.isVector() ? MagVT.getVectorNumElements() : 1;
diff --git a/llvm/test/CodeGen/AMDGPU/fcopysign-fneg.ll b/llvm/test/CodeGen/AMDGPU/fcopysign-fneg.ll
new file mode 100644
index 0000000000000..bcea2ff05af50
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/fcopysign-fneg.ll
@@ -0,0 +1,26 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=amdgcn -mcpu=gfx900 < %s | FileCheck -check-prefix=GFX9 %s
+
+define float @copysign_fneg_pos_zero(float %y) {
+; GFX9-LABEL: copysign_fneg_pos_zero:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_brev_b32 s4, 1
+; GFX9-NEXT: v_bfi_b32 v0, v0, 0, s4
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+ %fneg = fneg float %y
+ %b = call float @llvm.copysign.f32(float 0.0, float %fneg)
+ ret float %b
+}
+
+define float @copysign_fneg_neg_zero(float %y) {
+; GFX9-LABEL: copysign_fneg_neg_zero:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_brev_b32 s4, 1
+; GFX9-NEXT: v_bfi_b32 v0, v0, 0, s4
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+ %fneg = fneg float %y
+ %b = call float @llvm.copysign.f32(float -0.0, float %fneg)
+ ret float %b
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/207178
More information about the llvm-commits
mailing list