Skip to content

Commit 5778116

Browse files
committed
Optimize Zicond lowering for FP selects with +0.0
When lowering a floating-point SELECT to integer Zicond operations on RV64, converting an f32 +0.0 results in a RISCVISD::FMV_X_ANYEXTW_RV64 node. This target-specific node implies a register move somehow obscures the underlying constant zero value from the instruction selector, preventing the backend from pattern-matching a single `czero` instruction. For the following example: ```asm define dso_local noundef float @select_i1_f32_0(i1 %cond, float %t) nounwind { entry: %sel = select i1 %cond, float %t, float 0.000000e+00 ret float %sel } ``` On RV64 (e.g., +zicond +zdinx), this previously resulted in: ```asm czero.nez a2, zero, a0 czero.eqz a0, a1, a0 or a0, a2, a0 ret ``` Since the "else" value is zero, we can utilize the mechanism that czero like instruction will store zero into rd based on cond reg and optimized this scenario in to a single instruction. By explicitly detecting `+0.0` and lowering it to a constant integer 0, this commit enables the generation of: ```asm czero.eqz a0, a1, a0 ret ```
1 parent e1009fa commit 5778116

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9570,6 +9570,13 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
95709570
MVT XLenIntVT = Subtarget.getXLenVT();
95719571

95729572
auto CastToInt = [&](SDValue V) -> SDValue {
9573+
// Treat +0.0 as integer 0 to enable single 'czero' instruction
9574+
// generation.
9575+
if (auto *CFP = dyn_cast<ConstantFPSDNode>(V)) {
9576+
if (CFP->isZero() && !CFP->isNegative())
9577+
return DAG.getConstant(0, DL, XLenIntVT);
9578+
}
9579+
95739580
if (VT == MVT::f16)
95749581
return DAG.getNode(RISCVISD::FMV_X_ANYEXTH, DL, XLenIntVT, V);
95759582

llvm/test/CodeGen/RISCV/zicond-fp-select-zfinx.ll

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,3 +467,86 @@ entry:
467467
%sel = select i1 %cond, half %a, half %b
468468
ret half %sel
469469
}
470+
471+
; -----------------------------------------------------------------------------
472+
; Test select with i1 condition and zero ret val (cond ? a : 0), Zfinx
473+
; -----------------------------------------------------------------------------
474+
define dso_local noundef float @select_i1_f32_0(i1 %cond, float %t) nounwind {
475+
; RV64ZDINX_ZICOND-LABEL: select_i1_f32_0:
476+
; RV64ZDINX_ZICOND: # %bb.0: # %entry
477+
; RV64ZDINX_ZICOND-NEXT: # kill: def $x11_w killed $x11_w def $x11
478+
; RV64ZDINX_ZICOND-NEXT: andi a0, a0, 1
479+
; RV64ZDINX_ZICOND-NEXT: czero.nez a2, zero, a0
480+
; RV64ZDINX_ZICOND-NEXT: czero.eqz a0, a1, a0
481+
; RV64ZDINX_ZICOND-NEXT: or a0, a0, a2
482+
; RV64ZDINX_ZICOND-NEXT: # kill: def $x10_w killed $x10_w killed $x10
483+
; RV64ZDINX_ZICOND-NEXT: ret
484+
;
485+
; RV64ZDINX_NOZICOND-LABEL: select_i1_f32_0:
486+
; RV64ZDINX_NOZICOND: # %bb.0: # %entry
487+
; RV64ZDINX_NOZICOND-NEXT: andi a2, a0, 1
488+
; RV64ZDINX_NOZICOND-NEXT: mv a0, a1
489+
; RV64ZDINX_NOZICOND-NEXT: bnez a2, .LBB4_2
490+
; RV64ZDINX_NOZICOND-NEXT: # %bb.1: # %entry
491+
; RV64ZDINX_NOZICOND-NEXT: li a0, 0
492+
; RV64ZDINX_NOZICOND-NEXT: .LBB4_2: # %entry
493+
; RV64ZDINX_NOZICOND-NEXT: ret
494+
;
495+
; RV64ZHINX_ZICOND-LABEL: select_i1_f32_0:
496+
; RV64ZHINX_ZICOND: # %bb.0: # %entry
497+
; RV64ZHINX_ZICOND-NEXT: # kill: def $x11_w killed $x11_w def $x11
498+
; RV64ZHINX_ZICOND-NEXT: andi a0, a0, 1
499+
; RV64ZHINX_ZICOND-NEXT: czero.nez a2, zero, a0
500+
; RV64ZHINX_ZICOND-NEXT: czero.eqz a0, a1, a0
501+
; RV64ZHINX_ZICOND-NEXT: or a0, a0, a2
502+
; RV64ZHINX_ZICOND-NEXT: # kill: def $x10_w killed $x10_w killed $x10
503+
; RV64ZHINX_ZICOND-NEXT: ret
504+
;
505+
; RV64FD-LABEL: select_i1_f32_0:
506+
; RV64FD: # %bb.0: # %entry
507+
; RV64FD-NEXT: andi a0, a0, 1
508+
; RV64FD-NEXT: bnez a0, .LBB4_2
509+
; RV64FD-NEXT: # %bb.1: # %entry
510+
; RV64FD-NEXT: fmv.w.x fa0, zero
511+
; RV64FD-NEXT: .LBB4_2: # %entry
512+
; RV64FD-NEXT: ret
513+
;
514+
; RV32ZFINX_ZICOND-LABEL: select_i1_f32_0:
515+
; RV32ZFINX_ZICOND: # %bb.0: # %entry
516+
; RV32ZFINX_ZICOND-NEXT: # kill: def $x11_w killed $x11_w def $x11
517+
; RV32ZFINX_ZICOND-NEXT: andi a0, a0, 1
518+
; RV32ZFINX_ZICOND-NEXT: czero.eqz a0, a1, a0
519+
; RV32ZFINX_ZICOND-NEXT: # kill: def $x10_w killed $x10_w killed $x10
520+
; RV32ZFINX_ZICOND-NEXT: ret
521+
;
522+
; RV32ZFINX_NOZICOND-LABEL: select_i1_f32_0:
523+
; RV32ZFINX_NOZICOND: # %bb.0: # %entry
524+
; RV32ZFINX_NOZICOND-NEXT: andi a2, a0, 1
525+
; RV32ZFINX_NOZICOND-NEXT: mv a0, a1
526+
; RV32ZFINX_NOZICOND-NEXT: bnez a2, .LBB4_2
527+
; RV32ZFINX_NOZICOND-NEXT: # %bb.1: # %entry
528+
; RV32ZFINX_NOZICOND-NEXT: li a0, 0
529+
; RV32ZFINX_NOZICOND-NEXT: .LBB4_2: # %entry
530+
; RV32ZFINX_NOZICOND-NEXT: ret
531+
;
532+
; RV32ZDINX_ZICOND-LABEL: select_i1_f32_0:
533+
; RV32ZDINX_ZICOND: # %bb.0: # %entry
534+
; RV32ZDINX_ZICOND-NEXT: # kill: def $x11_w killed $x11_w def $x11
535+
; RV32ZDINX_ZICOND-NEXT: andi a0, a0, 1
536+
; RV32ZDINX_ZICOND-NEXT: czero.eqz a0, a1, a0
537+
; RV32ZDINX_ZICOND-NEXT: # kill: def $x10_w killed $x10_w killed $x10
538+
; RV32ZDINX_ZICOND-NEXT: ret
539+
;
540+
; RV32ZDINX_NOZICOND-LABEL: select_i1_f32_0:
541+
; RV32ZDINX_NOZICOND: # %bb.0: # %entry
542+
; RV32ZDINX_NOZICOND-NEXT: andi a2, a0, 1
543+
; RV32ZDINX_NOZICOND-NEXT: mv a0, a1
544+
; RV32ZDINX_NOZICOND-NEXT: bnez a2, .LBB4_2
545+
; RV32ZDINX_NOZICOND-NEXT: # %bb.1: # %entry
546+
; RV32ZDINX_NOZICOND-NEXT: li a0, 0
547+
; RV32ZDINX_NOZICOND-NEXT: .LBB4_2: # %entry
548+
; RV32ZDINX_NOZICOND-NEXT: ret
549+
entry:
550+
%sel = select i1 %cond, float %t, float 0.000000e+00
551+
ret float %sel
552+
}

0 commit comments

Comments
 (0)