[llvm] [RISCV] Fix lowering of negative zero with Zdinx 32-bit (PR #71869)
Nemanja Ivanovic via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 9 13:25:02 PST 2023
https://github.com/nemanjai created https://github.com/llvm/llvm-project/pull/71869
The compiler currently abends with an impossible reg-to-reg copy when producing a negative zero FP immediate on RV32 with -Zdinx. This is because we emit a negation that uses FP registers. Emit the right node to produce correct code.
>From ba87be48adc45d309c87d81e47746f85f895ccda Mon Sep 17 00:00:00 2001
From: Nemanja Ivanovic <nemanja.i.ibm at gmail.com>
Date: Thu, 9 Nov 2023 22:23:37 +0100
Subject: [PATCH] [RISCV] Fix lowering of negative zero with Zdinx 32-bit
The compiler currently abends with an impossible reg-to-reg
copy when producing a negative zero FP immediate on RV32
with -Zdinx. This is because we emit a negation that uses
FP registers. Emit the right node to produce correct code.
---
llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp | 14 ++-
llvm/test/CodeGen/RISCV/double-imm.ll | 119 +++++++++++++++++---
2 files changed, 116 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 1266c370cddeb5e..3f796f8d170e08a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -901,6 +901,8 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
Imm = selectImm(CurDAG, DL, XLenVT, APF.bitcastToAPInt().getSExtValue(),
*Subtarget);
+ bool HasZdinx = Subtarget->hasStdExtZdinx();
+ bool Is64Bit = Subtarget->is64Bit();
unsigned Opc;
switch (VT.SimpleTy) {
default:
@@ -920,8 +922,7 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
// For RV32, we can't move from a GPR, we need to convert instead. This
// should only happen for +0.0 and -0.0.
assert((Subtarget->is64Bit() || APF.isZero()) && "Unexpected constant");
- bool HasZdinx = Subtarget->hasStdExtZdinx();
- if (Subtarget->is64Bit())
+ if (Is64Bit)
Opc = HasZdinx ? RISCV::COPY : RISCV::FMV_D_X;
else
Opc = HasZdinx ? RISCV::FCVT_D_W_IN32X : RISCV::FCVT_D_W;
@@ -937,9 +938,14 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
Res = CurDAG->getMachineNode(Opc, DL, VT, Imm);
// For f64 -0.0, we need to insert a fneg.d idiom.
- if (NegZeroF64)
- Res = CurDAG->getMachineNode(RISCV::FSGNJN_D, DL, VT, SDValue(Res, 0),
+ if (NegZeroF64) {
+ if (Is64Bit)
+ Opc = HasZdinx ? RISCV::FSGNJN_D_INX : RISCV::FSGNJN_D;
+ else
+ Opc = HasZdinx ? RISCV::FSGNJN_D_IN32X : RISCV::FSGNJN_D;
+ Res = CurDAG->getMachineNode(Opc, DL, VT, SDValue(Res, 0),
SDValue(Res, 0));
+ }
ReplaceNode(Node, Res);
return;
diff --git a/llvm/test/CodeGen/RISCV/double-imm.ll b/llvm/test/CodeGen/RISCV/double-imm.ll
index dd554a8ce0dcf74..9254369baf19f3d 100644
--- a/llvm/test/CodeGen/RISCV/double-imm.ll
+++ b/llvm/test/CodeGen/RISCV/double-imm.ll
@@ -1,19 +1,25 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
-; RUN: -target-abi=ilp32d | FileCheck %s
+; RUN: -target-abi=ilp32d | FileCheck %s --check-prefix=CHECK32D
; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
-; RUN: -target-abi=lp64d | FileCheck %s
+; RUN: -target-abi=lp64d | FileCheck %s --check-prefix=CHECK64D
; RUN: llc -mtriple=riscv32 -mattr=+zdinx -verify-machineinstrs < %s \
; RUN: -target-abi=ilp32 | FileCheck --check-prefix=CHECKRV32ZDINX %s
; RUN: llc -mtriple=riscv64 -mattr=+zdinx -verify-machineinstrs < %s \
; RUN: -target-abi=lp64 | FileCheck --check-prefix=CHECKRV64ZDINX %s
define double @double_imm() nounwind {
-; CHECK-LABEL: double_imm:
-; CHECK: # %bb.0:
-; CHECK-NEXT: lui a0, %hi(.LCPI0_0)
-; CHECK-NEXT: fld fa0, %lo(.LCPI0_0)(a0)
-; CHECK-NEXT: ret
+; CHECK32D-LABEL: double_imm:
+; CHECK32D: # %bb.0:
+; CHECK32D-NEXT: lui a0, %hi(.LCPI0_0)
+; CHECK32D-NEXT: fld fa0, %lo(.LCPI0_0)(a0)
+; CHECK32D-NEXT: ret
+;
+; CHECK64D-LABEL: double_imm:
+; CHECK64D: # %bb.0:
+; CHECK64D-NEXT: lui a0, %hi(.LCPI0_0)
+; CHECK64D-NEXT: fld fa0, %lo(.LCPI0_0)(a0)
+; CHECK64D-NEXT: ret
;
; CHECKRV32ZDINX-LABEL: double_imm:
; CHECKRV32ZDINX: # %bb.0:
@@ -32,12 +38,19 @@ define double @double_imm() nounwind {
}
define double @double_imm_op(double %a) nounwind {
-; CHECK-LABEL: double_imm_op:
-; CHECK: # %bb.0:
-; CHECK-NEXT: lui a0, %hi(.LCPI1_0)
-; CHECK-NEXT: fld fa5, %lo(.LCPI1_0)(a0)
-; CHECK-NEXT: fadd.d fa0, fa0, fa5
-; CHECK-NEXT: ret
+; CHECK32D-LABEL: double_imm_op:
+; CHECK32D: # %bb.0:
+; CHECK32D-NEXT: lui a0, %hi(.LCPI1_0)
+; CHECK32D-NEXT: fld fa5, %lo(.LCPI1_0)(a0)
+; CHECK32D-NEXT: fadd.d fa0, fa0, fa5
+; CHECK32D-NEXT: ret
+;
+; CHECK64D-LABEL: double_imm_op:
+; CHECK64D: # %bb.0:
+; CHECK64D-NEXT: lui a0, %hi(.LCPI1_0)
+; CHECK64D-NEXT: fld fa5, %lo(.LCPI1_0)(a0)
+; CHECK64D-NEXT: fadd.d fa0, fa0, fa5
+; CHECK64D-NEXT: ret
;
; CHECKRV32ZDINX-LABEL: double_imm_op:
; CHECKRV32ZDINX: # %bb.0:
@@ -68,6 +81,16 @@ define double @double_imm_op(double %a) nounwind {
}
define double @double_positive_zero(ptr %pd) nounwind {
+; CHECK32D-LABEL: double_positive_zero:
+; CHECK32D: # %bb.0:
+; CHECK32D-NEXT: fcvt.d.w fa0, zero
+; CHECK32D-NEXT: ret
+;
+; CHECK64D-LABEL: double_positive_zero:
+; CHECK64D: # %bb.0:
+; CHECK64D-NEXT: fmv.d.x fa0, zero
+; CHECK64D-NEXT: ret
+;
; CHECKRV32ZDINX-LABEL: double_positive_zero:
; CHECKRV32ZDINX: # %bb.0:
; CHECKRV32ZDINX-NEXT: li a0, 0
@@ -82,6 +105,18 @@ define double @double_positive_zero(ptr %pd) nounwind {
}
define double @double_negative_zero(ptr %pd) nounwind {
+; CHECK32D-LABEL: double_negative_zero:
+; CHECK32D: # %bb.0:
+; CHECK32D-NEXT: fcvt.d.w fa5, zero
+; CHECK32D-NEXT: fneg.d fa0, fa5
+; CHECK32D-NEXT: ret
+;
+; CHECK64D-LABEL: double_negative_zero:
+; CHECK64D: # %bb.0:
+; CHECK64D-NEXT: fmv.d.x fa5, zero
+; CHECK64D-NEXT: fneg.d fa0, fa5
+; CHECK64D-NEXT: ret
+;
; CHECKRV32ZDINX-LABEL: double_negative_zero:
; CHECKRV32ZDINX: # %bb.0:
; CHECKRV32ZDINX-NEXT: lui a1, 524288
@@ -95,3 +130,61 @@ define double @double_negative_zero(ptr %pd) nounwind {
; CHECKRV64ZDINX-NEXT: ret
ret double -0.0
}
+define dso_local double @negzero_sel(i16 noundef %a, double noundef %d) nounwind {
+; CHECK32D-LABEL: negzero_sel:
+; CHECK32D: # %bb.0: # %entry
+; CHECK32D-NEXT: slli a0, a0, 16
+; CHECK32D-NEXT: fcvt.d.w fa5, zero
+; CHECK32D-NEXT: beqz a0, .LBB4_2
+; CHECK32D-NEXT: # %bb.1: # %entry
+; CHECK32D-NEXT: fneg.d fa0, fa5
+; CHECK32D-NEXT: .LBB4_2: # %entry
+; CHECK32D-NEXT: ret
+;
+; CHECK64D-LABEL: negzero_sel:
+; CHECK64D: # %bb.0: # %entry
+; CHECK64D-NEXT: slli a0, a0, 48
+; CHECK64D-NEXT: beqz a0, .LBB4_2
+; CHECK64D-NEXT: # %bb.1: # %entry
+; CHECK64D-NEXT: fmv.d.x fa5, zero
+; CHECK64D-NEXT: fneg.d fa0, fa5
+; CHECK64D-NEXT: .LBB4_2: # %entry
+; CHECK64D-NEXT: ret
+;
+; CHECKRV32ZDINX-LABEL: negzero_sel:
+; CHECKRV32ZDINX: # %bb.0: # %entry
+; CHECKRV32ZDINX-NEXT: addi sp, sp, -16
+; CHECKRV32ZDINX-NEXT: sw a1, 8(sp)
+; CHECKRV32ZDINX-NEXT: sw a2, 12(sp)
+; CHECKRV32ZDINX-NEXT: slli a2, a0, 16
+; CHECKRV32ZDINX-NEXT: fcvt.d.w a0, zero
+; CHECKRV32ZDINX-NEXT: beqz a2, .LBB4_2
+; CHECKRV32ZDINX-NEXT: # %bb.1: # %entry
+; CHECKRV32ZDINX-NEXT: fneg.d a0, a0
+; CHECKRV32ZDINX-NEXT: j .LBB4_3
+; CHECKRV32ZDINX-NEXT: .LBB4_2:
+; CHECKRV32ZDINX-NEXT: lw a0, 8(sp)
+; CHECKRV32ZDINX-NEXT: lw a1, 12(sp)
+; CHECKRV32ZDINX-NEXT: .LBB4_3: # %entry
+; CHECKRV32ZDINX-NEXT: sw a0, 8(sp)
+; CHECKRV32ZDINX-NEXT: sw a1, 12(sp)
+; CHECKRV32ZDINX-NEXT: lw a0, 8(sp)
+; CHECKRV32ZDINX-NEXT: lw a1, 12(sp)
+; CHECKRV32ZDINX-NEXT: addi sp, sp, 16
+; CHECKRV32ZDINX-NEXT: ret
+;
+; CHECKRV64ZDINX-LABEL: negzero_sel:
+; CHECKRV64ZDINX: # %bb.0: # %entry
+; CHECKRV64ZDINX-NEXT: slli a2, a0, 48
+; CHECKRV64ZDINX-NEXT: beqz a2, .LBB4_2
+; CHECKRV64ZDINX-NEXT: # %bb.1: # %entry
+; CHECKRV64ZDINX-NEXT: fneg.d a0, zero
+; CHECKRV64ZDINX-NEXT: ret
+; CHECKRV64ZDINX-NEXT: .LBB4_2:
+; CHECKRV64ZDINX-NEXT: mv a0, a1
+; CHECKRV64ZDINX-NEXT: ret
+entry:
+ %tobool.not = icmp eq i16 %a, 0
+ %d. = select i1 %tobool.not, double %d, double -0.000000e+00
+ ret double %d.
+}
More information about the llvm-commits
mailing list