LocVT = XLenVT;
LocInfo = CCValAssign::BCvt;
}
+ if (XLen == 64 && ValVT == MVT::f64) {
+ LocVT = MVT::i64;
+ LocInfo = CCValAssign::BCvt;
+ }
// Any return value split in to more than two values can't be returned
// directly.
return false;
}
- if (ValVT == MVT::f32) {
- LocVT = MVT::f32;
+ // When an f32 or f64 is passed on the stack, no bit-conversion is needed.
+ if (ValVT == MVT::f32 || ValVT == MVT::f64) {
+ LocVT = ValVT;
LocInfo = CCValAssign::Full;
}
State.addLoc(CCValAssign::getMem(ValNo, ValVT, StackOffset, LocVT, LocInfo));
ExtType = ISD::NON_EXTLOAD;
break;
}
- if (ValVT == MVT::f32)
- LocVT = MVT::f32;
Val = DAG.getExtLoad(
ExtType, DL, LocVT, Chain, FIN,
MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT);
def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_W GPR:$rs1)>;
def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_WU GPR:$rs1)>;
} // Predicates = [HasStdExtD, IsRV32]
+
+let Predicates = [HasStdExtD, IsRV64] in {
+def : Pat<(bitconvert GPR:$rs1), (FMV_D_X GPR:$rs1)>;
+def : Pat<(bitconvert FPR64:$rs1), (FMV_X_D FPR64:$rs1)>;
+
+// FP->[u]int32 is mostly handled by the FP->[u]int64 patterns. This is safe
+// because fpto[u|s]i produce poison if the value can't fit into the target.
+// We match the single case below because fcvt.wu.d sign-extends its result so
+// is cheaper than fcvt.lu.d+sext.w.
+def : Pat<(sext_inreg (zexti32 (fp_to_uint FPR64:$rs1)), i32),
+ (FCVT_WU_D $rs1, 0b001)>;
+
+// [u]int32->fp
+def : Pat<(sint_to_fp (sext_inreg GPR:$rs1, i32)), (FCVT_D_W $rs1)>;
+def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_D_WU $rs1)>;
+
+def : Pat<(fp_to_sint FPR64:$rs1), (FCVT_L_D FPR64:$rs1, 0b001)>;
+def : Pat<(fp_to_uint FPR64:$rs1), (FCVT_LU_D FPR64:$rs1, 0b001)>;
+
+// [u]int64->fp. Match GCC and default to using dynamic rounding mode.
+def : Pat<(sint_to_fp GPR:$rs1), (FCVT_D_L GPR:$rs1, 0b111)>;
+def : Pat<(uint_to_fp GPR:$rs1), (FCVT_D_LU GPR:$rs1, 0b111)>;
+} // Predicates = [HasStdExtD, IsRV64]
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
; These tests are each targeted at a particular RISC-V FPU instruction. Most
; other files in this folder exercise LLVM IR instructions that don't directly
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fadd_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fadd double %a, %b
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsub_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fsub.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fsub double %a, %b
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmul_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fmul.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fmul double %a, %b
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fdiv_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fdiv.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fdiv double %a, %b
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsqrt_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fsqrt.d ft0, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.sqrt.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsgnj_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fsgnj.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.copysign.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: feq.d a0, ft0, ft1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fneg_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft0
+; RV64IFD-NEXT: fneg.d ft1, ft0
+; RV64IFD-NEXT: feq.d a0, ft0, ft1
+; RV64IFD-NEXT: ret
%1 = fadd double %a, %a
%2 = fneg double %1
%3 = fcmp oeq double %1, %2
}
define double @fsgnjn_d(double %a, double %b) nounwind {
+; TODO: fsgnjn.s isn't selected on RV64 because DAGCombiner::visitBITCAST will
+; convert (bitconvert (fneg x)) to a xor.
+;
; RV32IFD-LABEL: fsgnjn_d:
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: addi sp, sp, -16
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsgnjn_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi a2, zero, -1
+; RV64IFD-NEXT: slli a2, a2, 63
+; RV64IFD-NEXT: xor a1, a1, a2
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fsgnj.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fsub double -0.0, %b
%2 = call double @llvm.copysign.f64(double %a, double %1)
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fabs_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fabs.d ft1, ft0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fadd double %a, %b
%2 = call double @llvm.fabs.f64(double %1)
%3 = fadd double %2, %1
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmin_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fmin.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.minnum.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmax_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fmax.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.maxnum.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: feq.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: feq_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp oeq double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: flt.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: flt_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp olt double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: fle.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fle_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ole double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmadd_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a2
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft2, a0
+; RV64IFD-NEXT: fmadd.d ft0, ft2, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.fma.f64(double %a, double %b, double %c)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmsub_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a2
+; RV64IFD-NEXT: lui a2, %hi(.LCPI15_0)
+; RV64IFD-NEXT: addi a2, a2, %lo(.LCPI15_0)
+; RV64IFD-NEXT: fld ft1, 0(a2)
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft2, a0
+; RV64IFD-NEXT: fmsub.d ft0, ft2, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%c_ = fadd double 0.0, %c ; avoid negation using xor
%negc = fsub double -0.0, %c_
%1 = call double @llvm.fma.f64(double %a, double %b, double %negc)
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fnmadd_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a2
+; RV64IFD-NEXT: lui a2, %hi(.LCPI16_0)
+; RV64IFD-NEXT: addi a2, a2, %lo(.LCPI16_0)
+; RV64IFD-NEXT: fld ft1, 0(a2)
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: fmv.d.x ft2, a0
+; RV64IFD-NEXT: fadd.d ft1, ft2, ft1
+; RV64IFD-NEXT: fmv.d.x ft2, a1
+; RV64IFD-NEXT: fnmadd.d ft0, ft1, ft2, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%a_ = fadd double 0.0, %a
%c_ = fadd double 0.0, %c
%nega = fsub double -0.0, %a_
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fnmsub_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: lui a0, %hi(.LCPI17_0)
+; RV64IFD-NEXT: addi a0, a0, %lo(.LCPI17_0)
+; RV64IFD-NEXT: fld ft1, 0(a0)
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: fmv.d.x ft1, a2
+; RV64IFD-NEXT: fmv.d.x ft2, a1
+; RV64IFD-NEXT: fnmsub.d ft0, ft0, ft2, ft1
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%a_ = fadd double 0.0, %a
%nega = fsub double -0.0, %a_
%1 = call double @llvm.fma.f64(double %nega, double %b, double %c)
; RUN: | FileCheck -check-prefix=RV32IFD %s
; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV64I %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
;
; This file tests cases where simple floating point operations can be
; profitably handled though bit manipulation if a soft-float ABI is being used
; RV64I-NEXT: slli a1, a1, 63
; RV64I-NEXT: xor a0, a0, a1
; RV64I-NEXT: ret
+;
+; RV64IFD-LABEL: fneg:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi a1, zero, -1
+; RV64IFD-NEXT: slli a1, a1, 63
+; RV64IFD-NEXT: xor a0, a0, a1
+; RV64IFD-NEXT: ret
%1 = fneg double %a
ret double %1
}
; RV64I-NEXT: addi a1, a1, -1
; RV64I-NEXT: and a0, a0, a1
; RV64I-NEXT: ret
+;
+; RV64IFD-LABEL: fabs:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi a1, zero, -1
+; RV64IFD-NEXT: slli a1, a1, 63
+; RV64IFD-NEXT: addi a1, a1, -1
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: ret
%1 = call double @llvm.fabs.f64(double %a)
ret double %1
}
; RV64I-NEXT: and a0, a0, a2
; RV64I-NEXT: or a0, a0, a1
; RV64I-NEXT: ret
+;
+; RV64IFD-LABEL: fcopysign_fneg:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi a2, zero, -1
+; RV64IFD-NEXT: slli a2, a2, 63
+; RV64IFD-NEXT: xor a1, a1, a2
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fsgnj.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fneg double %b
%2 = call double @llvm.copysign.f64(double %a, double %1)
ret double %2
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
declare void @abort()
declare void @exit(i32)
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB0_2: # %if.else
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_false:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: addi a0, zero, 1
+; RV64IFD-NEXT: bnez a0, .LBB0_2
+; RV64IFD-NEXT: # %bb.1: # %if.then
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB0_2: # %if.else
+; RV64IFD-NEXT: call abort
%1 = fcmp false double %a, %b
br i1 %1, label %if.then, label %if.else
if.then:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB1_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_oeq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB1_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB1_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp oeq double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB2_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_oeq_alt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: beqz a0, .LBB2_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB2_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp oeq double %a, %b
br i1 %1, label %if.then, label %if.else
if.then:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB3_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ogt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB3_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB3_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ogt double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB4_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_oge:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB4_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB4_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp oge double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB5_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_olt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB5_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB5_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp olt double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB6_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ole:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB6_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB6_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ole double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB7_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_one:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: feq.d a0, ft1, ft1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: feq.d a1, ft0, ft1
+; RV64IFD-NEXT: not a1, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: bnez a0, .LBB7_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB7_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp one double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB8_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ord:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: feq.d a0, ft0, ft0
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB8_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB8_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ord double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB9_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ueq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: feq.d a2, ft1, ft1
+; RV64IFD-NEXT: and a1, a2, a1
+; RV64IFD-NEXT: seqz a1, a1
+; RV64IFD-NEXT: or a0, a0, a1
+; RV64IFD-NEXT: bnez a0, .LBB9_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB9_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ueq double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB10_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ugt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB10_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB10_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ugt double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB11_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_uge:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB11_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB11_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp uge double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB12_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ult:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB12_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB12_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ult double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB13_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_ule:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB13_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB13_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp ule double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB14_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_une:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB14_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB14_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp une double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB15_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_uno:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: feq.d a0, ft0, ft0
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: bnez a0, .LBB15_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB15_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp uno double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; RV32IFD-NEXT: ret
; RV32IFD-NEXT: .LBB16_2: # %if.then
; RV32IFD-NEXT: call abort
+;
+; RV64IFD-LABEL: br_fcmp_true:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: addi a0, zero, 1
+; RV64IFD-NEXT: bnez a0, .LBB16_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
+; RV64IFD-NEXT: .LBB16_2: # %if.then
+; RV64IFD-NEXT: call abort
%1 = fcmp true double %a, %b
br i1 %1, label %if.then, label %if.else
if.else:
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
define float @fcvt_s_d(double %a) nounwind {
; RV32IFD-LABEL: fcvt_s_d:
; RV32IFD-NEXT: fmv.x.w a0, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_s_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fcvt.s.d ft0, ft0
+; RV64IFD-NEXT: fmv.x.w a0, ft0
+; RV64IFD-NEXT: ret
%1 = fptrunc double %a to float
ret float %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_s:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.w.x ft0, a0
+; RV64IFD-NEXT: fcvt.d.s ft0, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fpext float %a to double
ret double %1
}
+; For RV64D, fcvt.l.d is semantically equivalent to fcvt.w.d in this case
+; because fptosi will produce poison if the result doesn't fit into an i32.
define i32 @fcvt_w_d(double %a) nounwind {
; RV32IFD-LABEL: fcvt_w_d:
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: fcvt.w.d a0, ft0, rtz
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_w_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fcvt.l.d a0, ft0, rtz
+; RV64IFD-NEXT: ret
%1 = fptosi double %a to i32
ret i32 %1
}
+; For RV64D, fcvt.lu.d is semantically equivalent to fcvt.wu.d in this case
+; because fptosi will produce poison if the result doesn't fit into an i32.
define i32 @fcvt_wu_d(double %a) nounwind {
; RV32IFD-LABEL: fcvt_wu_d:
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: fcvt.wu.d a0, ft0, rtz
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_wu_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fcvt.lu.d a0, ft0, rtz
+; RV64IFD-NEXT: ret
%1 = fptoui double %a to i32
ret i32 %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_w:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.d.w ft0, a0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = sitofp i32 %a to double
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_wu:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.d.wu ft0, a0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = uitofp i32 %a to double
ret double %1
}
+
+define i64 @fcvt_l_d(double %a) nounwind {
+; RV32IFD-LABEL: fcvt_l_d:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp)
+; RV32IFD-NEXT: call __fixdfdi
+; RV32IFD-NEXT: lw ra, 12(sp)
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_l_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fcvt.l.d a0, ft0, rtz
+; RV64IFD-NEXT: ret
+ %1 = fptosi double %a to i64
+ ret i64 %1
+}
+
+define i64 @fcvt_lu_d(double %a) nounwind {
+; RV32IFD-LABEL: fcvt_lu_d:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp)
+; RV32IFD-NEXT: call __fixunsdfdi
+; RV32IFD-NEXT: lw ra, 12(sp)
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_lu_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fcvt.lu.d a0, ft0, rtz
+; RV64IFD-NEXT: ret
+ %1 = fptoui double %a to i64
+ ret i64 %1
+}
+
+define i64 @fmv_x_d(double %a, double %b) nounwind {
+; RV32IFD-LABEL: fmv_x_d:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw a2, 0(sp)
+; RV32IFD-NEXT: sw a3, 4(sp)
+; RV32IFD-NEXT: fld ft0, 0(sp)
+; RV32IFD-NEXT: sw a0, 0(sp)
+; RV32IFD-NEXT: sw a1, 4(sp)
+; RV32IFD-NEXT: fld ft1, 0(sp)
+; RV32IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV32IFD-NEXT: fsd ft0, 8(sp)
+; RV32IFD-NEXT: lw a0, 8(sp)
+; RV32IFD-NEXT: lw a1, 12(sp)
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmv_x_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
+ %1 = fadd double %a, %b
+ %2 = bitcast double %1 to i64
+ ret i64 %2
+}
+
+define double @fcvt_d_l(i64 %a) nounwind {
+; RV32IFD-LABEL: fcvt_d_l:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp)
+; RV32IFD-NEXT: call __floatdidf
+; RV32IFD-NEXT: lw ra, 12(sp)
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_l:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.d.l ft0, a0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
+ %1 = sitofp i64 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_lu(i64 %a) nounwind {
+; RV32IFD-LABEL: fcvt_d_lu:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp)
+; RV32IFD-NEXT: call __floatundidf
+; RV32IFD-NEXT: lw ra, 12(sp)
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_lu:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.d.lu ft0, a0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
+ %1 = uitofp i64 %a to double
+ ret double %1
+}
+
+define double @fmv_d_x(i64 %a, i64 %b) nounwind {
+; Ensure fmv.w.x is generated even for a soft double calling convention
+; RV32IFD-LABEL: fmv_d_x:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -32
+; RV32IFD-NEXT: sw a3, 20(sp)
+; RV32IFD-NEXT: sw a2, 16(sp)
+; RV32IFD-NEXT: sw a1, 28(sp)
+; RV32IFD-NEXT: sw a0, 24(sp)
+; RV32IFD-NEXT: fld ft0, 16(sp)
+; RV32IFD-NEXT: fld ft1, 24(sp)
+; RV32IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV32IFD-NEXT: fsd ft0, 8(sp)
+; RV32IFD-NEXT: lw a0, 8(sp)
+; RV32IFD-NEXT: lw a1, 12(sp)
+; RV32IFD-NEXT: addi sp, sp, 32
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmv_d_x:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
+ %1 = bitcast i64 %a to double
+ %2 = bitcast i64 %b to double
+ %3 = fadd double %1, %2
+ ret double %3
+}
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
define i32 @fcmp_false(double %a, double %b) nounwind {
; RV32IFD-LABEL: fcmp_false:
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: mv a0, zero
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_false:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: mv a0, zero
+; RV64IFD-NEXT: ret
%1 = fcmp false double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: feq.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_oeq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp oeq double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: flt.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ogt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ogt double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: fle.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_oge:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp oge double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: flt.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_olt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp olt double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: fle.d a0, ft1, ft0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ole:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ole double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: and a0, a1, a0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_one:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: feq.d a0, ft1, ft1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: feq.d a1, ft0, ft1
+; RV64IFD-NEXT: not a1, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: ret
%1 = fcmp one double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: xori a0, a0, 1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ord:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: feq.d a0, ft0, ft0
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: ret
%1 = fcmp ord double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: or a0, a0, a1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ueq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: feq.d a2, ft1, ft1
+; RV64IFD-NEXT: and a1, a2, a1
+; RV64IFD-NEXT: seqz a1, a1
+; RV64IFD-NEXT: or a0, a0, a1
+; RV64IFD-NEXT: ret
%1 = fcmp ueq double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: xori a0, a0, 1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ugt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: ret
%1 = fcmp ugt double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: xori a0, a0, 1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_uge:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: ret
%1 = fcmp uge double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: xori a0, a0, 1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ult:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: ret
%1 = fcmp ult double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: xori a0, a0, 1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_ule:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: ret
%1 = fcmp ule double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: xori a0, a0, 1
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_une:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: ret
%1 = fcmp une double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD-NEXT: seqz a0, a0
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_uno:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: feq.d a0, ft0, ft0
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: ret
%1 = fcmp uno double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: addi a0, zero, 1
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcmp_true:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi a0, zero, 1
+; RV64IFD-NEXT: ret
%1 = fcmp true double %a, %b
%2 = zext i1 %1 to i32
ret i32 %2
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
define double @double_imm() nounwind {
+; TODO: Should probably prefer fld or ld on RV64 rather than materialising an
+; expensive constant.
+;
; RV32IFD-LABEL: double_imm:
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: addi sp, sp, -16
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: double_imm:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: lui a0, 512
+; RV64IFD-NEXT: addiw a0, a0, 1169
+; RV64IFD-NEXT: slli a0, a0, 15
+; RV64IFD-NEXT: addi a0, a0, -299
+; RV64IFD-NEXT: slli a0, a0, 14
+; RV64IFD-NEXT: addi a0, a0, 1091
+; RV64IFD-NEXT: slli a0, a0, 12
+; RV64IFD-NEXT: addi a0, a0, -744
+; RV64IFD-NEXT: ret
ret double 3.1415926535897931159979634685441851615905761718750
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: double_imm_op:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: lui a0, %hi(.LCPI1_0)
+; RV64IFD-NEXT: addi a0, a0, %lo(.LCPI1_0)
+; RV64IFD-NEXT: fld ft1, 0(a0)
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fadd double %a, 1.0
ret double %1
}
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
declare double @llvm.sqrt.f64(double)
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: sqrt_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fsqrt.d ft0, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.sqrt.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: powi_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: sext.w a1, a1
+; RV64IFD-NEXT: call __powidf2
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.powi.f64(double %a, i32 %b)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: sin_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call sin
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.sin.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: cos_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call cos
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.cos.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 28(sp)
; RV32IFD-NEXT: addi sp, sp, 32
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: sincos_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -32
+; RV64IFD-NEXT: sd ra, 24(sp)
+; RV64IFD-NEXT: sd s1, 16(sp)
+; RV64IFD-NEXT: sd s2, 8(sp)
+; RV64IFD-NEXT: mv s1, a0
+; RV64IFD-NEXT: call sin
+; RV64IFD-NEXT: mv s2, a0
+; RV64IFD-NEXT: mv a0, s1
+; RV64IFD-NEXT: call cos
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, s2
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ld s2, 8(sp)
+; RV64IFD-NEXT: ld s1, 16(sp)
+; RV64IFD-NEXT: ld ra, 24(sp)
+; RV64IFD-NEXT: addi sp, sp, 32
+; RV64IFD-NEXT: ret
%1 = call double @llvm.sin.f64(double %a)
%2 = call double @llvm.cos.f64(double %a)
%3 = fadd double %1, %2
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: pow_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call pow
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.pow.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call exp
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.exp.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: exp2_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call exp2
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.exp2.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: log_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call log
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.log.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: log10_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call log10
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.log10.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: log2_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call log2
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.log2.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fma_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a2
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft2, a0
+; RV64IFD-NEXT: fmadd.d ft0, ft2, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.fma.f64(double %a, double %b, double %c)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmuladd_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fmul.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.d.x ft1, a2
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.fmuladd.f64(double %a, double %b, double %c)
ret double %1
}
; RV32IFD-NEXT: addi a2, a2, -1
; RV32IFD-NEXT: and a1, a1, a2
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fabs_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi a1, zero, -1
+; RV64IFD-NEXT: slli a1, a1, 63
+; RV64IFD-NEXT: addi a1, a1, -1
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: ret
%1 = call double @llvm.fabs.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: minnum_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fmin.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.minnum.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: maxnum_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fmax.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.maxnum.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: copysign_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fsgnj.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = call double @llvm.copysign.f64(double %a, double %b)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: floor_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call floor
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.floor.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: ceil_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call ceil
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.ceil.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: trunc_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call trunc
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.trunc.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: rint_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call rint
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.rint.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: nearbyint_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call nearbyint
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.nearbyint.f64(double %a)
ret double %1
}
; RV32IFD-NEXT: lw ra, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: round_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: call round
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = call double @llvm.round.f64(double %a)
ret double %1
}
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
define double @fld(double *%a) nounwind {
; RV32IFD-LABEL: fld:
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fld:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fld ft0, 24(a0)
+; RV64IFD-NEXT: fld ft1, 0(a0)
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = load double, double* %a
%2 = getelementptr double, double* %a, i32 3
%3 = load double, double* %2
; RV32IFD-NEXT: fsd ft0, 0(a0)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsd:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a2
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fsd ft0, 64(a0)
+; RV64IFD-NEXT: fsd ft0, 0(a0)
+; RV64IFD-NEXT: ret
; Use %b and %c in an FP op to ensure floating point registers are used, even
; for the soft float ABI
%1 = fadd double %b, %c
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fld_fsd_global:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: lui a0, %hi(G)
+; RV64IFD-NEXT: fld ft1, %lo(G)(a0)
+; RV64IFD-NEXT: fsd ft0, %lo(G)(a0)
+; RV64IFD-NEXT: addi a0, a0, %lo(G)
+; RV64IFD-NEXT: fld ft1, 72(a0)
+; RV64IFD-NEXT: fsd ft0, 72(a0)
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
; Use %a and %b in an FP op to ensure floating point registers are used, even
; for the soft float ABI
%1 = fadd double %a, %b
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fld_fsd_constant:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: lui a0, 56
+; RV64IFD-NEXT: addiw a0, a0, -1353
+; RV64IFD-NEXT: slli a0, a0, 14
+; RV64IFD-NEXT: fld ft1, -273(a0)
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: fsd ft0, -273(a0)
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = inttoptr i32 3735928559 to double*
%2 = load volatile double, double* %1
%3 = fadd double %a, %2
; RV32IFD-NEXT: lw ra, 28(sp)
; RV32IFD-NEXT: addi sp, sp, 32
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fld_stack:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -32
+; RV64IFD-NEXT: sd ra, 24(sp)
+; RV64IFD-NEXT: sd s1, 16(sp)
+; RV64IFD-NEXT: mv s1, a0
+; RV64IFD-NEXT: addi a0, sp, 8
+; RV64IFD-NEXT: call notdead
+; RV64IFD-NEXT: fmv.d.x ft0, s1
+; RV64IFD-NEXT: fld ft1, 8(sp)
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ld s1, 16(sp)
+; RV64IFD-NEXT: ld ra, 24(sp)
+; RV64IFD-NEXT: addi sp, sp, 32
+; RV64IFD-NEXT: ret
%1 = alloca double, align 8
%2 = bitcast double* %1 to i8*
call void @notdead(i8* %2)
; RV32IFD-NEXT: lw ra, 28(sp)
; RV32IFD-NEXT: addi sp, sp, 32
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsd_stack:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
+; RV64IFD-NEXT: fsd ft0, 0(sp)
+; RV64IFD-NEXT: mv a0, sp
+; RV64IFD-NEXT: call notdead
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
%1 = fadd double %a, %b ; force store from FPR64
%2 = alloca double, align 8
store double %1, double* %2
; RV32IFD-NEXT: fsw ft0, 0(a0)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fsd_trunc:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fcvt.s.d ft0, ft0
+; RV64IFD-NEXT: fsw ft0, 0(a0)
+; RV64IFD-NEXT: ret
%1 = fptrunc double %b to float
store float %1, float* %a, align 4
ret void
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
define double @select_fcmp_false(double %a, double %b) nounwind {
; RV32IFD-LABEL: select_fcmp_false:
; RV32IFD-NEXT: mv a1, a3
; RV32IFD-NEXT: mv a0, a2
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_false:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: mv a0, a1
+; RV64IFD-NEXT: ret
%1 = fcmp false double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_oeq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: feq.d a0, ft0, ft1
+; RV64IFD-NEXT: bnez a0, .LBB1_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB1_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp oeq double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ogt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB2_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB2_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ogt double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_oge:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB3_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB3_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp oge double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_olt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: flt.d a0, ft0, ft1
+; RV64IFD-NEXT: bnez a0, .LBB4_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB4_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp olt double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ole:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fle.d a0, ft0, ft1
+; RV64IFD-NEXT: bnez a0, .LBB5_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB5_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ole double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_one:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: feq.d a0, ft1, ft1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: feq.d a1, ft0, ft1
+; RV64IFD-NEXT: not a1, a1
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: bnez a0, .LBB6_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB6_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp one double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ord:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: feq.d a0, ft1, ft1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB7_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB7_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ord double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ueq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: feq.d a0, ft1, ft1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: feq.d a1, ft0, ft1
+; RV64IFD-NEXT: or a0, a1, a0
+; RV64IFD-NEXT: bnez a0, .LBB8_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB8_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ueq double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ugt:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fle.d a0, ft0, ft1
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB9_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB9_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ugt double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_uge:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: flt.d a0, ft0, ft1
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB10_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB10_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp uge double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ult:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fle.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB11_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB11_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ult double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_ule:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: flt.d a0, ft1, ft0
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB12_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB12_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp ule double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_une:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: feq.d a0, ft0, ft1
+; RV64IFD-NEXT: xori a0, a0, 1
+; RV64IFD-NEXT: bnez a0, .LBB13_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB13_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp une double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: lw a1, 12(sp)
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_uno:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fmv.d.x ft1, a1
+; RV64IFD-NEXT: feq.d a0, ft1, ft1
+; RV64IFD-NEXT: feq.d a1, ft0, ft0
+; RV64IFD-NEXT: and a0, a1, a0
+; RV64IFD-NEXT: seqz a0, a0
+; RV64IFD-NEXT: bnez a0, .LBB14_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: fmv.d ft0, ft1
+; RV64IFD-NEXT: .LBB14_2:
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ret
%1 = fcmp uno double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-LABEL: select_fcmp_true:
; RV32IFD: # %bb.0:
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: select_fcmp_true:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: ret
%1 = fcmp true double %a, %b
%2 = select i1 %1, double %a, double %b
ret double %2
; RV32IFD-NEXT: mv a0, a4
; RV32IFD-NEXT: addi sp, sp, 16
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: i32_select_fcmp_oeq:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x ft0, a1
+; RV64IFD-NEXT: fmv.d.x ft1, a0
+; RV64IFD-NEXT: feq.d a0, ft1, ft0
+; RV64IFD-NEXT: bnez a0, .LBB16_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: mv a2, a3
+; RV64IFD-NEXT: .LBB16_2:
+; RV64IFD-NEXT: mv a0, a2
+; RV64IFD-NEXT: ret
%1 = fcmp oeq double %a, %b
%2 = select i1 %1, i32 %c, i32 %d
ret i32 %2
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV64IFD %s
define double @func(double %d, i32 %n) nounwind {
; RV32IFD-LABEL: func:
; RV32IFD-NEXT: lw ra, 28(sp)
; RV32IFD-NEXT: addi sp, sp, 32
; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: func:
+; RV64IFD: # %bb.0: # %entry
+; RV64IFD-NEXT: addi sp, sp, -16
+; RV64IFD-NEXT: sd ra, 8(sp)
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: slli a0, a1, 32
+; RV64IFD-NEXT: srli a0, a0, 32
+; RV64IFD-NEXT: beqz a0, .LBB0_2
+; RV64IFD-NEXT: # %bb.1: # %if.else
+; RV64IFD-NEXT: addi a1, a1, -1
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: fsd ft0, 0(sp)
+; RV64IFD-NEXT: call func
+; RV64IFD-NEXT: fmv.d.x ft0, a0
+; RV64IFD-NEXT: fld ft1, 0(sp)
+; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
+; RV64IFD-NEXT: .LBB0_2: # %return
+; RV64IFD-NEXT: fmv.x.d a0, ft0
+; RV64IFD-NEXT: ld ra, 8(sp)
+; RV64IFD-NEXT: addi sp, sp, 16
+; RV64IFD-NEXT: ret
entry:
%cmp = icmp eq i32 %n, 0
br i1 %cmp, label %return, label %if.else
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=RV64ID
+
+; This file exhaustively checks double<->i32 conversions. In general,
+; fcvt.l[u].d can be selected instead of fcvt.w[u].d because poison is
+; generated for an fpto[s|u]i conversion if the result doesn't fit in the
+; target type.
+
+define i32 @aext_fptosi(double %a) nounwind {
+; RV64ID-LABEL: aext_fptosi:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fmv.d.x ft0, a0
+; RV64ID-NEXT: fcvt.l.d a0, ft0, rtz
+; RV64ID-NEXT: ret
+ %1 = fptosi double %a to i32
+ ret i32 %1
+}
+
+define signext i32 @sext_fptosi(double %a) nounwind {
+; RV64ID-LABEL: sext_fptosi:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fmv.d.x ft0, a0
+; RV64ID-NEXT: fcvt.l.d a0, ft0, rtz
+; RV64ID-NEXT: ret
+ %1 = fptosi double %a to i32
+ ret i32 %1
+}
+
+define zeroext i32 @zext_fptosi(double %a) nounwind {
+; RV64ID-LABEL: zext_fptosi:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fmv.d.x ft0, a0
+; RV64ID-NEXT: fcvt.l.d a0, ft0, rtz
+; RV64ID-NEXT: slli a0, a0, 32
+; RV64ID-NEXT: srli a0, a0, 32
+; RV64ID-NEXT: ret
+ %1 = fptosi double %a to i32
+ ret i32 %1
+}
+
+define i32 @aext_fptoui(double %a) nounwind {
+; RV64ID-LABEL: aext_fptoui:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fmv.d.x ft0, a0
+; RV64ID-NEXT: fcvt.lu.d a0, ft0, rtz
+; RV64ID-NEXT: ret
+ %1 = fptoui double %a to i32
+ ret i32 %1
+}
+
+define signext i32 @sext_fptoui(double %a) nounwind {
+; RV64ID-LABEL: sext_fptoui:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fmv.d.x ft0, a0
+; RV64ID-NEXT: fcvt.wu.d a0, ft0, rtz
+; RV64ID-NEXT: ret
+ %1 = fptoui double %a to i32
+ ret i32 %1
+}
+
+define zeroext i32 @zext_fptoui(double %a) nounwind {
+; RV64ID-LABEL: zext_fptoui:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fmv.d.x ft0, a0
+; RV64ID-NEXT: fcvt.lu.d a0, ft0, rtz
+; RV64ID-NEXT: ret
+ %1 = fptoui double %a to i32
+ ret i32 %1
+}
+
+define double @uitofp_aext_i32_to_f64(i32 %a) nounwind {
+; RV64ID-LABEL: uitofp_aext_i32_to_f64:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fcvt.d.wu ft0, a0
+; RV64ID-NEXT: fmv.x.d a0, ft0
+; RV64ID-NEXT: ret
+ %1 = uitofp i32 %a to double
+ ret double %1
+}
+
+define double @uitofp_sext_i32_to_f64(i32 signext %a) nounwind {
+; RV64ID-LABEL: uitofp_sext_i32_to_f64:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fcvt.d.wu ft0, a0
+; RV64ID-NEXT: fmv.x.d a0, ft0
+; RV64ID-NEXT: ret
+ %1 = uitofp i32 %a to double
+ ret double %1
+}
+
+define double @uitofp_zext_i32_to_f64(i32 zeroext %a) nounwind {
+; RV64ID-LABEL: uitofp_zext_i32_to_f64:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fcvt.d.wu ft0, a0
+; RV64ID-NEXT: fmv.x.d a0, ft0
+; RV64ID-NEXT: ret
+ %1 = uitofp i32 %a to double
+ ret double %1
+}
+
+define double @sitofp_aext_i32_to_f64(i32 %a) nounwind {
+; RV64ID-LABEL: sitofp_aext_i32_to_f64:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fcvt.d.w ft0, a0
+; RV64ID-NEXT: fmv.x.d a0, ft0
+; RV64ID-NEXT: ret
+ %1 = sitofp i32 %a to double
+ ret double %1
+}
+
+define double @sitofp_sext_i32_to_f64(i32 signext %a) nounwind {
+; RV64ID-LABEL: sitofp_sext_i32_to_f64:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fcvt.d.l ft0, a0
+; RV64ID-NEXT: fmv.x.d a0, ft0
+; RV64ID-NEXT: ret
+ %1 = sitofp i32 %a to double
+ ret double %1
+}
+
+define double @sitofp_zext_i32_to_f64(i32 zeroext %a) nounwind {
+; RV64ID-LABEL: sitofp_zext_i32_to_f64:
+; RV64ID: # %bb.0:
+; RV64ID-NEXT: fcvt.d.w ft0, a0
+; RV64ID-NEXT: fmv.x.d a0, ft0
+; RV64ID-NEXT: ret
+ %1 = sitofp i32 %a to double
+ ret double %1
+}