[llvm] b57cbbc - [RISCV][GISel] Improve fptos/ui and s/uitofp handling and testing.
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 6 12:19:08 PST 2024
Author: Craig Topper
Date: 2024-11-06T12:18:56-08:00
New Revision: b57cbbcb6a6b8f7134848c52dce4b6f64c02d149
URL: https://github.com/llvm/llvm-project/commit/b57cbbcb6a6b8f7134848c52dce4b6f64c02d149
DIFF: https://github.com/llvm/llvm-project/commit/b57cbbcb6a6b8f7134848c52dce4b6f64c02d149.diff
LOG: [RISCV][GISel] Improve fptos/ui and s/uitofp handling and testing.
Replace clampScalar of the integer type with minScalar. We can't
narrow the integer type, we can only make it larger. If the type
is larger than xLen we need to use a 2*xlen libcall. If it's larger
than 2*xlen we can't handle it at all.
Added:
llvm/test/CodeGen/RISCV/GlobalISel/double-convert.ll
llvm/test/CodeGen/RISCV/GlobalISel/float-convert.ll
llvm/test/CodeGen/RISCV/GlobalISel/rv64-double-convert.ll
llvm/test/CodeGen/RISCV/GlobalISel/rv64-float-convert.ll
Modified:
llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index f2a51a7ea0d426..34742394a291ed 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -90,6 +90,7 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
const LLT s16 = LLT::scalar(16);
const LLT s32 = LLT::scalar(32);
const LLT s64 = LLT::scalar(64);
+ const LLT s128 = LLT::scalar(128);
const LLT nxv1s1 = LLT::scalable_vector(1, s1);
const LLT nxv2s1 = LLT::scalable_vector(2, s1);
@@ -535,13 +536,16 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
.legalIf(all(typeInSet(0, {s32, sXLen}), typeIsScalarFPArith(1, ST)))
.widenScalarToNextPow2(0)
- .clampScalar(0, s32, sXLen)
- .libcall();
+ .minScalar(0, s32)
+ .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
+ .libcallFor(ST.is64Bit(), {{s128, s32}, {s128, s64}});
getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
.legalIf(all(typeIsScalarFPArith(0, ST), typeInSet(1, {s32, sXLen})))
.widenScalarToNextPow2(1)
- .clampScalar(1, s32, sXLen);
+ .minScalar(1, s32)
+ .libcallFor({{s32, s32}, {s64, s32}, {s32, s64}, {s64, s64}})
+ .libcallFor(ST.is64Bit(), {{s32, s128}, {s64, s128}});
// FIXME: We can do custom inline expansion like SelectionDAG.
// FIXME: Legal with Zfa.
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/double-convert.ll b/llvm/test/CodeGen/RISCV/GlobalISel/double-convert.ll
new file mode 100644
index 00000000000000..785cc2aafde11b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/double-convert.ll
@@ -0,0 +1,370 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -global-isel -mattr=+d -verify-machineinstrs < %s \
+; RUN: -target-abi=ilp32d | FileCheck -check-prefixes=CHECKIFD,RV32IFD %s
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+d -verify-machineinstrs < %s \
+; RUN: -target-abi=lp64d | FileCheck -check-prefixes=CHECKIFD,RV64IFD %s
+
+define float @fcvt_s_d(double %a) nounwind {
+; CHECKIFD-LABEL: fcvt_s_d:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.s.d fa0, fa0
+; CHECKIFD-NEXT: ret
+ %1 = fptrunc double %a to float
+ ret float %1
+}
+
+define double @fcvt_d_s(float %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_s:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.s fa0, fa0
+; CHECKIFD-NEXT: ret
+ %1 = fpext float %a to double
+ ret double %1
+}
+
+define i32 @fcvt_w_d(double %a) nounwind {
+; CHECKIFD-LABEL: fcvt_w_d:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.w.d a0, fa0, rtz
+; CHECKIFD-NEXT: ret
+ %1 = fptosi double %a to i32
+ ret i32 %1
+}
+
+define i32 @fcvt_wu_d(double %a) nounwind {
+; CHECKIFD-LABEL: fcvt_wu_d:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.wu.d a0, fa0, rtz
+; CHECKIFD-NEXT: ret
+ %1 = fptoui double %a to i32
+ ret i32 %1
+}
+
+define i32 @fcvt_wu_d_multiple_use(double %x, ptr %y) nounwind {
+; RV32IFD-LABEL: fcvt_wu_d_multiple_use:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.wu.d a1, fa0, rtz
+; RV32IFD-NEXT: li a0, 1
+; RV32IFD-NEXT: beqz a1, .LBB4_2
+; RV32IFD-NEXT: # %bb.1:
+; RV32IFD-NEXT: mv a0, a1
+; RV32IFD-NEXT: .LBB4_2:
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_wu_d_multiple_use:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.wu.d a1, fa0, rtz
+; RV64IFD-NEXT: slli a0, a1, 32
+; RV64IFD-NEXT: srli a2, a0, 32
+; RV64IFD-NEXT: li a0, 1
+; RV64IFD-NEXT: beqz a2, .LBB4_2
+; RV64IFD-NEXT: # %bb.1:
+; RV64IFD-NEXT: mv a0, a1
+; RV64IFD-NEXT: .LBB4_2:
+; RV64IFD-NEXT: ret
+ %a = fptoui double %x to i32
+ %b = icmp eq i32 %a, 0
+ %c = select i1 %b, i32 1, i32 %a
+ ret i32 %c
+}
+
+define double @fcvt_d_w(i32 %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_w:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.w fa0, a0
+; CHECKIFD-NEXT: ret
+ %1 = sitofp i32 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_w_load(ptr %p) nounwind {
+; CHECKIFD-LABEL: fcvt_d_w_load:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: lw a0, 0(a0)
+; CHECKIFD-NEXT: fcvt.d.w fa0, a0
+; CHECKIFD-NEXT: ret
+ %a = load i32, ptr %p
+ %1 = sitofp i32 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_wu(i32 %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_wu:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.wu fa0, a0
+; CHECKIFD-NEXT: ret
+ %1 = uitofp i32 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_wu_load(ptr %p) nounwind {
+; CHECKIFD-LABEL: fcvt_d_wu_load:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: lw a0, 0(a0)
+; CHECKIFD-NEXT: fcvt.d.wu fa0, a0
+; CHECKIFD-NEXT: ret
+ %a = load i32, ptr %p
+ %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) # 4-byte Folded Spill
+; RV32IFD-NEXT: call __fixdfdi
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_l_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.l.d a0, fa0, 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) # 4-byte Folded Spill
+; RV32IFD-NEXT: call __fixunsdfdi
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_lu_d:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.lu.d a0, fa0, 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: fadd.d fa5, fa0, fa1
+; RV32IFD-NEXT: fsd fa5, 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: fadd.d fa5, fa0, fa1
+; RV64IFD-NEXT: fmv.x.d a0, fa5
+; 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) # 4-byte Folded Spill
+; RV32IFD-NEXT: call __floatdidf
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_l:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.d.l fa0, a0
+; 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) # 4-byte Folded Spill
+; RV32IFD-NEXT: call __floatundidf
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_lu:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.d.lu fa0, a0
+; RV64IFD-NEXT: ret
+ %1 = uitofp i64 %a to double
+ ret double %1
+}
+
+define double @fmv_d_x(i64 %a, i64 %b) nounwind {
+; RV32IFD-LABEL: fmv_d_x:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw a0, 8(sp)
+; RV32IFD-NEXT: sw a1, 12(sp)
+; RV32IFD-NEXT: fld fa5, 8(sp)
+; RV32IFD-NEXT: sw a2, 8(sp)
+; RV32IFD-NEXT: sw a3, 12(sp)
+; RV32IFD-NEXT: fld fa4, 8(sp)
+; RV32IFD-NEXT: fadd.d fa0, fa5, fa4
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fmv_d_x:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.d.x fa5, a0
+; RV64IFD-NEXT: fmv.d.x fa4, a1
+; RV64IFD-NEXT: fadd.d fa0, fa5, fa4
+; RV64IFD-NEXT: ret
+ %1 = bitcast i64 %a to double
+ %2 = bitcast i64 %b to double
+ %3 = fadd double %1, %2
+ ret double %3
+}
+
+define double @fcvt_d_w_i8(i8 signext %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_w_i8:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.w fa0, a0
+; CHECKIFD-NEXT: ret
+ %1 = sitofp i8 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_wu_i8(i8 zeroext %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_wu_i8:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.wu fa0, a0
+; CHECKIFD-NEXT: ret
+ %1 = uitofp i8 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_w_i16(i16 signext %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_w_i16:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.w fa0, a0
+; CHECKIFD-NEXT: ret
+ %1 = sitofp i16 %a to double
+ ret double %1
+}
+
+define double @fcvt_d_wu_i16(i16 zeroext %a) nounwind {
+; CHECKIFD-LABEL: fcvt_d_wu_i16:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.d.wu fa0, a0
+; CHECKIFD-NEXT: ret
+ %1 = uitofp i16 %a to double
+ ret double %1
+}
+
+define signext i32 @fcvt_d_w_demanded_bits(i32 signext %0, ptr %1) nounwind {
+; RV32IFD-LABEL: fcvt_d_w_demanded_bits:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi a0, a0, 1
+; RV32IFD-NEXT: fcvt.d.w fa5, a0
+; RV32IFD-NEXT: fsd fa5, 0(a1)
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_w_demanded_bits:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addiw a0, a0, 1
+; RV64IFD-NEXT: fcvt.d.w fa5, a0
+; RV64IFD-NEXT: fsd fa5, 0(a1)
+; RV64IFD-NEXT: ret
+ %3 = add i32 %0, 1
+ %4 = sitofp i32 %3 to double
+ store double %4, ptr %1, align 8
+ ret i32 %3
+}
+
+define signext i32 @fcvt_d_wu_demanded_bits(i32 signext %0, ptr %1) nounwind {
+; RV32IFD-LABEL: fcvt_d_wu_demanded_bits:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi a0, a0, 1
+; RV32IFD-NEXT: fcvt.d.wu fa5, a0
+; RV32IFD-NEXT: fsd fa5, 0(a1)
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_d_wu_demanded_bits:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: addiw a0, a0, 1
+; RV64IFD-NEXT: fcvt.d.wu fa5, a0
+; RV64IFD-NEXT: fsd fa5, 0(a1)
+; RV64IFD-NEXT: ret
+ %3 = add i32 %0, 1
+ %4 = uitofp i32 %3 to double
+ store double %4, ptr %1, align 8
+ ret i32 %3
+}
+
+define signext i16 @fcvt_w_s_i16(double %a) nounwind {
+; RV32IFD-LABEL: fcvt_w_s_i16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.w.d a0, fa0, rtz
+; RV32IFD-NEXT: slli a0, a0, 16
+; RV32IFD-NEXT: srai a0, a0, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_w_s_i16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.w.d a0, fa0, rtz
+; RV64IFD-NEXT: slli a0, a0, 48
+; RV64IFD-NEXT: srai a0, a0, 48
+; RV64IFD-NEXT: ret
+ %1 = fptosi double %a to i16
+ ret i16 %1
+}
+
+define zeroext i16 @fcvt_wu_s_i16(double %a) nounwind {
+; RV32IFD-LABEL: fcvt_wu_s_i16:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.wu.d a0, fa0, rtz
+; RV32IFD-NEXT: lui a1, 16
+; RV32IFD-NEXT: addi a1, a1, -1
+; RV32IFD-NEXT: and a0, a0, a1
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_wu_s_i16:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.wu.d a0, fa0, rtz
+; RV64IFD-NEXT: lui a1, 16
+; RV64IFD-NEXT: addiw a1, a1, -1
+; RV64IFD-NEXT: and a0, a0, a1
+; RV64IFD-NEXT: ret
+ %1 = fptoui double %a to i16
+ ret i16 %1
+}
+
+define signext i8 @fcvt_w_s_i8(double %a) nounwind {
+; RV32IFD-LABEL: fcvt_w_s_i8:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fcvt.w.d a0, fa0, rtz
+; RV32IFD-NEXT: slli a0, a0, 24
+; RV32IFD-NEXT: srai a0, a0, 24
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: fcvt_w_s_i8:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fcvt.w.d a0, fa0, rtz
+; RV64IFD-NEXT: slli a0, a0, 56
+; RV64IFD-NEXT: srai a0, a0, 56
+; RV64IFD-NEXT: ret
+ %1 = fptosi double %a to i8
+ ret i8 %1
+}
+
+define zeroext i8 @fcvt_wu_s_i8(double %a) nounwind {
+; CHECKIFD-LABEL: fcvt_wu_s_i8:
+; CHECKIFD: # %bb.0:
+; CHECKIFD-NEXT: fcvt.wu.d a0, fa0, rtz
+; CHECKIFD-NEXT: andi a0, a0, 255
+; CHECKIFD-NEXT: ret
+ %1 = fptoui double %a to i8
+ ret i8 %1
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/float-convert.ll b/llvm/test/CodeGen/RISCV/GlobalISel/float-convert.ll
new file mode 100644
index 00000000000000..d6a36c5a702ac8
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/float-convert.ll
@@ -0,0 +1,342 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -global-isel -mattr=+f -verify-machineinstrs < %s \
+; RUN: -target-abi=ilp32f | FileCheck -check-prefixes=CHECKIF,RV32IF %s
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+f -verify-machineinstrs < %s \
+; RUN: -target-abi=lp64f | FileCheck -check-prefixes=CHECKIF,RV64IF %s
+
+define i32 @fcvt_w_s(float %a) nounwind {
+; CHECKIF-LABEL: fcvt_w_s:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.w.s a0, fa0, rtz
+; CHECKIF-NEXT: ret
+ %1 = fptosi float %a to i32
+ ret i32 %1
+}
+
+define i32 @fcvt_wu_s(float %a) nounwind {
+; CHECKIF-LABEL: fcvt_wu_s:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.wu.s a0, fa0, rtz
+; CHECKIF-NEXT: ret
+ %1 = fptoui float %a to i32
+ ret i32 %1
+}
+
+; Test where the fptoui has multiple uses, one of which causes a sext to be
+; inserted on RV64.
+define i32 @fcvt_wu_s_multiple_use(float %x, ptr %y) nounwind {
+; RV32IF-LABEL: fcvt_wu_s_multiple_use:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fcvt.wu.s a1, fa0, rtz
+; RV32IF-NEXT: li a0, 1
+; RV32IF-NEXT: beqz a1, .LBB2_2
+; RV32IF-NEXT: # %bb.1:
+; RV32IF-NEXT: mv a0, a1
+; RV32IF-NEXT: .LBB2_2:
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_wu_s_multiple_use:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.wu.s a1, fa0, rtz
+; RV64IF-NEXT: slli a0, a1, 32
+; RV64IF-NEXT: srli a2, a0, 32
+; RV64IF-NEXT: li a0, 1
+; RV64IF-NEXT: beqz a2, .LBB2_2
+; RV64IF-NEXT: # %bb.1:
+; RV64IF-NEXT: mv a0, a1
+; RV64IF-NEXT: .LBB2_2:
+; RV64IF-NEXT: ret
+ %a = fptoui float %x to i32
+ %b = icmp eq i32 %a, 0
+ %c = select i1 %b, i32 1, i32 %a
+ ret i32 %c
+}
+
+define signext i32 @fmv_x_w(float %a, float %b) nounwind {
+; RV32IF-LABEL: fmv_x_w:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fadd.s fa5, fa0, fa1
+; RV32IF-NEXT: fmv.x.w a0, fa5
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fmv_x_w:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fadd.s fa5, fa0, fa1
+; RV64IF-NEXT: fmv.x.w a0, fa5
+; RV64IF-NEXT: sext.w a0, a0
+; RV64IF-NEXT: ret
+; Ensure fmv.x.w is generated even for a soft float calling convention
+ %1 = fadd float %a, %b
+ %2 = bitcast float %1 to i32
+ ret i32 %2
+}
+
+define float @fcvt_s_w(i32 %a) nounwind {
+; CHECKIF-LABEL: fcvt_s_w:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.s.w fa0, a0
+; CHECKIF-NEXT: ret
+ %1 = sitofp i32 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_w_load(ptr %p) nounwind {
+; CHECKIF-LABEL: fcvt_s_w_load:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: lw a0, 0(a0)
+; CHECKIF-NEXT: fcvt.s.w fa0, a0
+; CHECKIF-NEXT: ret
+ %a = load i32, ptr %p
+ %1 = sitofp i32 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_wu(i32 %a) nounwind {
+; CHECKIF-LABEL: fcvt_s_wu:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.s.wu fa0, a0
+; CHECKIF-NEXT: ret
+ %1 = uitofp i32 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_wu_load(ptr %p) nounwind {
+; CHECKIF-LABEL: fcvt_s_wu_load:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: lw a0, 0(a0)
+; CHECKIF-NEXT: fcvt.s.wu fa0, a0
+; CHECKIF-NEXT: ret
+ %a = load i32, ptr %p
+ %1 = uitofp i32 %a to float
+ ret float %1
+}
+
+define float @fmv_w_x(i32 %a, i32 %b) nounwind {
+; CHECKIF-LABEL: fmv_w_x:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fmv.w.x fa5, a0
+; CHECKIF-NEXT: fmv.w.x fa4, a1
+; CHECKIF-NEXT: fadd.s fa0, fa5, fa4
+; CHECKIF-NEXT: ret
+; Ensure fmv.w.x is generated even for a soft float calling convention
+ %1 = bitcast i32 %a to float
+ %2 = bitcast i32 %b to float
+ %3 = fadd float %1, %2
+ ret float %3
+}
+
+define i64 @fcvt_l_s(float %a) nounwind {
+; RV32IF-LABEL: fcvt_l_s:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi sp, sp, -16
+; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IF-NEXT: call __fixsfdi
+; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IF-NEXT: addi sp, sp, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_l_s:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.l.s a0, fa0, rtz
+; RV64IF-NEXT: ret
+ %1 = fptosi float %a to i64
+ ret i64 %1
+}
+
+define i64 @fcvt_lu_s(float %a) nounwind {
+; RV32IF-LABEL: fcvt_lu_s:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi sp, sp, -16
+; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IF-NEXT: call __fixunssfdi
+; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IF-NEXT: addi sp, sp, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_lu_s:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.lu.s a0, fa0, rtz
+; RV64IF-NEXT: ret
+ %1 = fptoui float %a to i64
+ ret i64 %1
+}
+
+define float @fcvt_s_l(i64 %a) nounwind {
+; RV32IF-LABEL: fcvt_s_l:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi sp, sp, -16
+; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IF-NEXT: call __floatdisf
+; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IF-NEXT: addi sp, sp, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_s_l:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.s.l fa0, a0
+; RV64IF-NEXT: ret
+ %1 = sitofp i64 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_lu(i64 %a) nounwind {
+; RV32IF-LABEL: fcvt_s_lu:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi sp, sp, -16
+; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IF-NEXT: call __floatundisf
+; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IF-NEXT: addi sp, sp, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_s_lu:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.s.lu fa0, a0
+; RV64IF-NEXT: ret
+ %1 = uitofp i64 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_w_i8(i8 signext %a) nounwind {
+; CHECKIF-LABEL: fcvt_s_w_i8:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.s.w fa0, a0
+; CHECKIF-NEXT: ret
+ %1 = sitofp i8 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_wu_i8(i8 zeroext %a) nounwind {
+; CHECKIF-LABEL: fcvt_s_wu_i8:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.s.wu fa0, a0
+; CHECKIF-NEXT: ret
+ %1 = uitofp i8 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_w_i16(i16 signext %a) nounwind {
+; CHECKIF-LABEL: fcvt_s_w_i16:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.s.w fa0, a0
+; CHECKIF-NEXT: ret
+ %1 = sitofp i16 %a to float
+ ret float %1
+}
+
+define float @fcvt_s_wu_i16(i16 zeroext %a) nounwind {
+; CHECKIF-LABEL: fcvt_s_wu_i16:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.s.wu fa0, a0
+; CHECKIF-NEXT: ret
+ %1 = uitofp i16 %a to float
+ ret float %1
+}
+
+; Make sure we select W version of addi on RV64.
+define signext i32 @fcvt_s_w_demanded_bits(i32 signext %0, ptr %1) nounwind {
+; RV32IF-LABEL: fcvt_s_w_demanded_bits:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi a0, a0, 1
+; RV32IF-NEXT: fcvt.s.w fa5, a0
+; RV32IF-NEXT: fsw fa5, 0(a1)
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_s_w_demanded_bits:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: addiw a0, a0, 1
+; RV64IF-NEXT: fcvt.s.w fa5, a0
+; RV64IF-NEXT: fsw fa5, 0(a1)
+; RV64IF-NEXT: ret
+ %3 = add i32 %0, 1
+ %4 = sitofp i32 %3 to float
+ store float %4, ptr %1, align 4
+ ret i32 %3
+}
+
+; Make sure we select W version of addi on RV64.
+define signext i32 @fcvt_s_wu_demanded_bits(i32 signext %0, ptr %1) nounwind {
+; RV32IF-LABEL: fcvt_s_wu_demanded_bits:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi a0, a0, 1
+; RV32IF-NEXT: fcvt.s.wu fa5, a0
+; RV32IF-NEXT: fsw fa5, 0(a1)
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_s_wu_demanded_bits:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: addiw a0, a0, 1
+; RV64IF-NEXT: fcvt.s.wu fa5, a0
+; RV64IF-NEXT: fsw fa5, 0(a1)
+; RV64IF-NEXT: ret
+ %3 = add i32 %0, 1
+ %4 = uitofp i32 %3 to float
+ store float %4, ptr %1, align 4
+ ret i32 %3
+}
+
+define signext i16 @fcvt_w_s_i16(float %a) nounwind {
+; RV32IF-LABEL: fcvt_w_s_i16:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fcvt.w.s a0, fa0, rtz
+; RV32IF-NEXT: slli a0, a0, 16
+; RV32IF-NEXT: srai a0, a0, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_w_s_i16:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.w.s a0, fa0, rtz
+; RV64IF-NEXT: slli a0, a0, 48
+; RV64IF-NEXT: srai a0, a0, 48
+; RV64IF-NEXT: ret
+ %1 = fptosi float %a to i16
+ ret i16 %1
+}
+
+define zeroext i16 @fcvt_wu_s_i16(float %a) nounwind {
+; RV32IF-LABEL: fcvt_wu_s_i16:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fcvt.wu.s a0, fa0, rtz
+; RV32IF-NEXT: lui a1, 16
+; RV32IF-NEXT: addi a1, a1, -1
+; RV32IF-NEXT: and a0, a0, a1
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_wu_s_i16:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.wu.s a0, fa0, rtz
+; RV64IF-NEXT: lui a1, 16
+; RV64IF-NEXT: addiw a1, a1, -1
+; RV64IF-NEXT: and a0, a0, a1
+; RV64IF-NEXT: ret
+ %1 = fptoui float %a to i16
+ ret i16 %1
+}
+
+define signext i8 @fcvt_w_s_i8(float %a) nounwind {
+; RV32IF-LABEL: fcvt_w_s_i8:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fcvt.w.s a0, fa0, rtz
+; RV32IF-NEXT: slli a0, a0, 24
+; RV32IF-NEXT: srai a0, a0, 24
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: fcvt_w_s_i8:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fcvt.w.s a0, fa0, rtz
+; RV64IF-NEXT: slli a0, a0, 56
+; RV64IF-NEXT: srai a0, a0, 56
+; RV64IF-NEXT: ret
+ %1 = fptosi float %a to i8
+ ret i8 %1
+}
+
+define zeroext i8 @fcvt_wu_s_i8(float %a) nounwind {
+; CHECKIF-LABEL: fcvt_wu_s_i8:
+; CHECKIF: # %bb.0:
+; CHECKIF-NEXT: fcvt.wu.s a0, fa0, rtz
+; CHECKIF-NEXT: andi a0, a0, 255
+; CHECKIF-NEXT: ret
+ %1 = fptoui float %a to i8
+ ret i8 %1
+}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/rv64-double-convert.ll b/llvm/test/CodeGen/RISCV/GlobalISel/rv64-double-convert.ll
new file mode 100644
index 00000000000000..0d2d3d1e8b8915
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/rv64-double-convert.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -global-isel -verify-machineinstrs < %s \
+; RUN: -target-abi=lp64 | FileCheck %s -check-prefixes=CHECK,RV64I
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+d -verify-machineinstrs < %s \
+; RUN: -target-abi=lp64d | FileCheck %s -check-prefixes=CHECK,RV64ID
+
+define i128 @fptosi_f64_to_i128(double %a) nounwind {
+; CHECK-LABEL: fptosi_f64_to_i128:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __fixdfti
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = fptosi double %a to i128
+ ret i128 %1
+}
+
+define i128 @fptoui_f64_to_i128(double %a) nounwind {
+; CHECK-LABEL: fptoui_f64_to_i128:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __fixunsdfti
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = fptoui double %a to i128
+ ret i128 %1
+}
+
+define double @sitofp_i128_to_f64(i128 %a) nounwind {
+; CHECK-LABEL: sitofp_i128_to_f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __floattidf
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = sitofp i128 %a to double
+ ret double %1
+}
+
+define double @uitofp_i128_to_f64(i128 %a) nounwind {
+; CHECK-LABEL: uitofp_i128_to_f64:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __floatuntidf
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = uitofp i128 %a to double
+ ret double %1
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; RV64I: {{.*}}
+; RV64ID: {{.*}}
diff --git a/llvm/test/CodeGen/RISCV/GlobalISel/rv64-float-convert.ll b/llvm/test/CodeGen/RISCV/GlobalISel/rv64-float-convert.ll
new file mode 100644
index 00000000000000..7a240091b0f1b6
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/GlobalISel/rv64-float-convert.ll
@@ -0,0 +1,60 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -global-isel -target-abi=lp64 -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefixes=CHECK,RV64I
+; RUN: llc -mtriple=riscv64 -global-isel -mattr=+f -target-abi=lp64f -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefixes=CHECK,RV64IF
+
+define i128 @fptosi_f32_to_i128(float %a) nounwind {
+; CHECK-LABEL: fptosi_f32_to_i128:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __fixsfti
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = fptosi float %a to i128
+ ret i128 %1
+}
+
+define i128 @fptoui_f32_to_i128(float %a) nounwind {
+; CHECK-LABEL: fptoui_f32_to_i128:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __fixunssfti
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = fptoui float %a to i128
+ ret i128 %1
+}
+
+define float @sitofp_i128_to_f32(i128 %a) nounwind {
+; CHECK-LABEL: sitofp_i128_to_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __floattisf
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = sitofp i128 %a to float
+ ret float %1
+}
+
+define float @uitofp_i128_to_f32(i128 %a) nounwind {
+; CHECK-LABEL: uitofp_i128_to_f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: addi sp, sp, -16
+; CHECK-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT: call __floatuntisf
+; CHECK-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT: addi sp, sp, 16
+; CHECK-NEXT: ret
+ %1 = uitofp i128 %a to float
+ ret float %1
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; RV64I: {{.*}}
+; RV64IF: {{.*}}
More information about the llvm-commits
mailing list