Skip to content

Commit

Permalink
[RISCV] Fix lowering of negative zero with Zdinx 32-bit (#71869)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nemanjai committed Nov 13, 2023
1 parent 858453d commit 563720c
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 18 deletions.
15 changes: 10 additions & 5 deletions llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
Expand All @@ -937,9 +938,13 @@ 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),
SDValue(Res, 0));
if (NegZeroF64) {
Opc = RISCV::FSGNJN_D;
if (HasZdinx)
Opc = Is64Bit ? RISCV::FSGNJN_D_INX : RISCV::FSGNJN_D_IN32X;
Res =
CurDAG->getMachineNode(Opc, DL, VT, SDValue(Res, 0), SDValue(Res, 0));
}

ReplaceNode(Node, Res);
return;
Expand Down
119 changes: 106 additions & 13 deletions llvm/test/CodeGen/RISCV/double-imm.ll
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
}

0 comments on commit 563720c

Please sign in to comment.