Files
clang-p2996/llvm/test/CodeGen/RISCV/double-maximum-minimum.ll
Craig Topper 49429783b0 [RISCV] Add lowering for scalar fmaximum/fminimum.
Unlike fmaxnum and fminnum, these operations propagate nan and
consider -0.0 to be less than +0.0.

Without Zfa, we don't have a single instruction for this. The
lowering I've used forces the other input to nan if one input
is a nan. If both inputs are nan, they get swapped. Then use
the fmax or fmin instruction.

New ISD nodes are needed because fmaxnum/fminnum to not define
the order of -0.0 and +0.0.

This lowering ensures the snans are quieted though that is probably not
required in default environment). Also ensures non-canonical nans
are canonicalized, though I'm also not sure that's needed.

Another option could be to use fmax/fmin and then overwrite the
result based on the inputs being nan, but I'm not sure we can do
that with any less code.

Future work will handle nonans FMF, and handling the case where
we can prove the input isn't nan.

This does fix the crash in #64022, but we need to do more work
to avoid scalarization.

Reviewed By: fakepaper56

Differential Revision: https://reviews.llvm.org/D156069
2023-07-24 13:46:35 -07:00

165 lines
6.0 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+d \
; RUN: -verify-machineinstrs -target-abi=ilp32d \
; RUN: | FileCheck -check-prefixes=CHECKIFD,RV32IFD %s
; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+d \
; RUN: -verify-machineinstrs -target-abi=lp64d \
; RUN: | FileCheck -check-prefixes=CHECKIFD,RV64IFD %s
; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zdinx \
; RUN: -verify-machineinstrs -target-abi=ilp32 \
; RUN: | FileCheck -check-prefix=RV32IZFINXZDINX %s
; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zdinx \
; RUN: -verify-machineinstrs -target-abi=lp64 \
; RUN: | FileCheck -check-prefix=RV64IZFINXZDINX %s
declare double @llvm.minimum.f64(double, double)
define double @fminimum_f64(double %a, double %b) nounwind {
; CHECKIFD-LABEL: fminimum_f64:
; CHECKIFD: # %bb.0:
; CHECKIFD-NEXT: feq.d a0, fa0, fa0
; CHECKIFD-NEXT: fmv.d fa5, fa1
; CHECKIFD-NEXT: beqz a0, .LBB0_3
; CHECKIFD-NEXT: # %bb.1:
; CHECKIFD-NEXT: feq.d a0, fa1, fa1
; CHECKIFD-NEXT: beqz a0, .LBB0_4
; CHECKIFD-NEXT: .LBB0_2:
; CHECKIFD-NEXT: fmin.d fa0, fa0, fa5
; CHECKIFD-NEXT: ret
; CHECKIFD-NEXT: .LBB0_3:
; CHECKIFD-NEXT: fmv.d fa5, fa0
; CHECKIFD-NEXT: feq.d a0, fa1, fa1
; CHECKIFD-NEXT: bnez a0, .LBB0_2
; CHECKIFD-NEXT: .LBB0_4:
; CHECKIFD-NEXT: fmin.d fa0, fa1, fa5
; CHECKIFD-NEXT: ret
;
; RV32IZFINXZDINX-LABEL: fminimum_f64:
; RV32IZFINXZDINX: # %bb.0:
; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
; RV32IZFINXZDINX-NEXT: sw a2, 8(sp)
; RV32IZFINXZDINX-NEXT: sw a3, 12(sp)
; RV32IZFINXZDINX-NEXT: lw a2, 8(sp)
; RV32IZFINXZDINX-NEXT: lw a3, 12(sp)
; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: feq.d a6, a0, a0
; RV32IZFINXZDINX-NEXT: mv a4, a2
; RV32IZFINXZDINX-NEXT: bnez a6, .LBB0_2
; RV32IZFINXZDINX-NEXT: # %bb.1:
; RV32IZFINXZDINX-NEXT: mv a4, a0
; RV32IZFINXZDINX-NEXT: .LBB0_2:
; RV32IZFINXZDINX-NEXT: feq.d a6, a2, a2
; RV32IZFINXZDINX-NEXT: bnez a6, .LBB0_4
; RV32IZFINXZDINX-NEXT: # %bb.3:
; RV32IZFINXZDINX-NEXT: mv a0, a2
; RV32IZFINXZDINX-NEXT: .LBB0_4:
; RV32IZFINXZDINX-NEXT: fmin.d a0, a0, a4
; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
; RV32IZFINXZDINX-NEXT: ret
;
; RV64IZFINXZDINX-LABEL: fminimum_f64:
; RV64IZFINXZDINX: # %bb.0:
; RV64IZFINXZDINX-NEXT: feq.d a3, a0, a0
; RV64IZFINXZDINX-NEXT: mv a2, a1
; RV64IZFINXZDINX-NEXT: beqz a3, .LBB0_3
; RV64IZFINXZDINX-NEXT: # %bb.1:
; RV64IZFINXZDINX-NEXT: feq.d a3, a1, a1
; RV64IZFINXZDINX-NEXT: beqz a3, .LBB0_4
; RV64IZFINXZDINX-NEXT: .LBB0_2:
; RV64IZFINXZDINX-NEXT: fmin.d a0, a0, a2
; RV64IZFINXZDINX-NEXT: ret
; RV64IZFINXZDINX-NEXT: .LBB0_3:
; RV64IZFINXZDINX-NEXT: mv a2, a0
; RV64IZFINXZDINX-NEXT: feq.d a3, a1, a1
; RV64IZFINXZDINX-NEXT: bnez a3, .LBB0_2
; RV64IZFINXZDINX-NEXT: .LBB0_4:
; RV64IZFINXZDINX-NEXT: fmin.d a0, a1, a2
; RV64IZFINXZDINX-NEXT: ret
%1 = call double @llvm.minimum.f64(double %a, double %b)
ret double %1
}
declare double @llvm.maximum.f64(double, double)
define double @fmaximum_f64(double %a, double %b) nounwind {
; CHECKIFD-LABEL: fmaximum_f64:
; CHECKIFD: # %bb.0:
; CHECKIFD-NEXT: feq.d a0, fa0, fa0
; CHECKIFD-NEXT: fmv.d fa5, fa1
; CHECKIFD-NEXT: beqz a0, .LBB1_3
; CHECKIFD-NEXT: # %bb.1:
; CHECKIFD-NEXT: feq.d a0, fa1, fa1
; CHECKIFD-NEXT: beqz a0, .LBB1_4
; CHECKIFD-NEXT: .LBB1_2:
; CHECKIFD-NEXT: fmax.d fa0, fa0, fa5
; CHECKIFD-NEXT: ret
; CHECKIFD-NEXT: .LBB1_3:
; CHECKIFD-NEXT: fmv.d fa5, fa0
; CHECKIFD-NEXT: feq.d a0, fa1, fa1
; CHECKIFD-NEXT: bnez a0, .LBB1_2
; CHECKIFD-NEXT: .LBB1_4:
; CHECKIFD-NEXT: fmax.d fa0, fa1, fa5
; CHECKIFD-NEXT: ret
;
; RV32IZFINXZDINX-LABEL: fmaximum_f64:
; RV32IZFINXZDINX: # %bb.0:
; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
; RV32IZFINXZDINX-NEXT: sw a2, 8(sp)
; RV32IZFINXZDINX-NEXT: sw a3, 12(sp)
; RV32IZFINXZDINX-NEXT: lw a2, 8(sp)
; RV32IZFINXZDINX-NEXT: lw a3, 12(sp)
; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: feq.d a6, a0, a0
; RV32IZFINXZDINX-NEXT: mv a4, a2
; RV32IZFINXZDINX-NEXT: bnez a6, .LBB1_2
; RV32IZFINXZDINX-NEXT: # %bb.1:
; RV32IZFINXZDINX-NEXT: mv a4, a0
; RV32IZFINXZDINX-NEXT: .LBB1_2:
; RV32IZFINXZDINX-NEXT: feq.d a6, a2, a2
; RV32IZFINXZDINX-NEXT: bnez a6, .LBB1_4
; RV32IZFINXZDINX-NEXT: # %bb.3:
; RV32IZFINXZDINX-NEXT: mv a0, a2
; RV32IZFINXZDINX-NEXT: .LBB1_4:
; RV32IZFINXZDINX-NEXT: fmax.d a0, a0, a4
; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
; RV32IZFINXZDINX-NEXT: ret
;
; RV64IZFINXZDINX-LABEL: fmaximum_f64:
; RV64IZFINXZDINX: # %bb.0:
; RV64IZFINXZDINX-NEXT: feq.d a3, a0, a0
; RV64IZFINXZDINX-NEXT: mv a2, a1
; RV64IZFINXZDINX-NEXT: beqz a3, .LBB1_3
; RV64IZFINXZDINX-NEXT: # %bb.1:
; RV64IZFINXZDINX-NEXT: feq.d a3, a1, a1
; RV64IZFINXZDINX-NEXT: beqz a3, .LBB1_4
; RV64IZFINXZDINX-NEXT: .LBB1_2:
; RV64IZFINXZDINX-NEXT: fmax.d a0, a0, a2
; RV64IZFINXZDINX-NEXT: ret
; RV64IZFINXZDINX-NEXT: .LBB1_3:
; RV64IZFINXZDINX-NEXT: mv a2, a0
; RV64IZFINXZDINX-NEXT: feq.d a3, a1, a1
; RV64IZFINXZDINX-NEXT: bnez a3, .LBB1_2
; RV64IZFINXZDINX-NEXT: .LBB1_4:
; RV64IZFINXZDINX-NEXT: fmax.d a0, a1, a2
; RV64IZFINXZDINX-NEXT: ret
%1 = call double @llvm.maximum.f64(double %a, double %b)
ret double %1
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; RV32IFD: {{.*}}
; RV64IFD: {{.*}}