diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -8827,7 +8827,13 @@ // Only handle XLen or i32 types. Other types narrower than XLen will // eventually be legalized to XLenVT. EVT VT = N->getValueType(0); - if (VT != MVT::i32 && VT != XLenVT) + bool IsVector = VT.isVector(); + + if (VT != MVT::i32 && VT != XLenVT && !IsVector) + return SDValue(); + + // For vector, ensure the result type is legal. + if (IsVector && !TLI.isTypeLegal(VT)) return SDValue(); SDValue Src = N->getOperand(0); @@ -8844,15 +8850,23 @@ if (FRM == RISCVFPRndMode::Invalid) return SDValue(); + // We only have static rtz in RVV. + if (IsVector && FRM != RISCVFPRndMode::RTZ) + return SDValue(); + bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT; unsigned Opc; - if (VT == XLenVT) + SDLoc DL(N); + if (IsVector) + // (fp_to_int (ftrunc V)) -> fp_to_int (V) + // Keep fp_to_int for RVV, let it do custom lowerring. + return DAG.getNode(N->getOpcode(), DL, VT, Src.getOperand(0)); + else if (VT == XLenVT) Opc = IsSigned ? RISCVISD::FCVT_X : RISCVISD::FCVT_XU; else Opc = IsSigned ? RISCVISD::FCVT_W_RV64 : RISCVISD::FCVT_WU_RV64; - SDLoc DL(N); SDValue FpToInt = DAG.getNode(Opc, DL, XLenVT, Src.getOperand(0), DAG.getTargetConstant(FRM, DL, XLenVT)); return DAG.getNode(ISD::TRUNCATE, DL, VT, FpToInt); diff --git a/llvm/test/CodeGen/RISCV/rvv/vftrunc-conv.ll b/llvm/test/CodeGen/RISCV/rvv/vftrunc-conv.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/vftrunc-conv.ll @@ -0,0 +1,135 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=ilp32d \ +; RUN: -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -mtriple=riscv64 -mattr=+d,+zfh,+experimental-zvfh,+v -target-abi=lp64d \ +; RUN: -verify-machineinstrs < %s | FileCheck %s + +define @vftrunc_tosi_nxv8f64_nxv8i1( %va) { +; CHECK-LABEL: vftrunc_tosi_nxv8f64_nxv8i1: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.x.f.w v16, v8 +; CHECK-NEXT: vand.vi v8, v16, 1 +; CHECK-NEXT: vmsne.vi v0, v8, 0 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptosi %vb to + ret %evec +} + +define @vftrunc_toui_nxv8f64_nxv8i1( %va) { +; CHECK-LABEL: vftrunc_toui_nxv8f64_nxv8i1: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.xu.f.w v16, v8 +; CHECK-NEXT: vand.vi v8, v16, 1 +; CHECK-NEXT: vmsne.vi v0, v8, 0 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptoui %vb to + ret %evec +} + +define @vftrunc_tosi_nxv8f64_nxv8i8( %va) { +; CHECK-LABEL: vftrunc_tosi_nxv8f64_nxv8i8: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.x.f.w v16, v8 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, mu +; CHECK-NEXT: vnsrl.wi v10, v16, 0 +; CHECK-NEXT: vsetvli zero, zero, e8, m1, ta, mu +; CHECK-NEXT: vnsrl.wi v8, v10, 0 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptosi %vb to + ret %evec +} + +define @vftrunc_toui_nxv8f64_nxv8i8( %va) { +; CHECK-LABEL: vftrunc_toui_nxv8f64_nxv8i8: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.xu.f.w v16, v8 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, mu +; CHECK-NEXT: vnsrl.wi v10, v16, 0 +; CHECK-NEXT: vsetvli zero, zero, e8, m1, ta, mu +; CHECK-NEXT: vnsrl.wi v8, v10, 0 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptoui %vb to + ret %evec +} + +define @vftrunc_tosi_nxv8f64_nxv8i16( %va) { +; CHECK-LABEL: vftrunc_tosi_nxv8f64_nxv8i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.x.f.w v16, v8 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, mu +; CHECK-NEXT: vnsrl.wi v8, v16, 0 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptosi %vb to + ret %evec +} + +define @vftrunc_toui_nxv8f64_nxv8i16( %va) { +; CHECK-LABEL: vftrunc_toui_nxv8f64_nxv8i16: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.xu.f.w v16, v8 +; CHECK-NEXT: vsetvli zero, zero, e16, m2, ta, mu +; CHECK-NEXT: vnsrl.wi v8, v16, 0 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptoui %vb to + ret %evec +} + +define @vftrunc_tosi_nxv8f64_nxv8i32( %va) { +; CHECK-LABEL: vftrunc_tosi_nxv8f64_nxv8i32: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.x.f.w v16, v8 +; CHECK-NEXT: vmv.v.v v8, v16 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptosi %vb to + ret %evec +} + +define @vftrunc_toui_nxv8f64_nxv8i32( %va) { +; CHECK-LABEL: vftrunc_toui_nxv8f64_nxv8i32: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e32, m4, ta, mu +; CHECK-NEXT: vfncvt.rtz.xu.f.w v16, v8 +; CHECK-NEXT: vmv.v.v v8, v16 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptoui %vb to + ret %evec +} + +define @vftrunc_tosi_nxv8f64_nxv8i64( %va) { +; CHECK-LABEL: vftrunc_tosi_nxv8f64_nxv8i64: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e64, m8, ta, mu +; CHECK-NEXT: vfcvt.rtz.x.f.v v8, v8 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptosi %vb to + ret %evec +} + +define @vftrunc_toui_nxv8f64_nxv8i64( %va) { +; CHECK-LABEL: vftrunc_toui_nxv8f64_nxv8i64: +; CHECK: # %bb.0: +; CHECK-NEXT: vsetvli a0, zero, e64, m8, ta, mu +; CHECK-NEXT: vfcvt.rtz.xu.f.v v8, v8 +; CHECK-NEXT: ret + %vb = call @llvm.trunc.nxv8f64( %va) + %evec = fptoui %vb to + ret %evec +} + +declare @llvm.trunc.nxv8f64()