863 lines · plain
1//===-- RISCVInstrInfoF.td - RISC-V 'F' instructions -------*- tablegen -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file describes the RISC-V instructions from the standard 'F',10// Single-Precision Floating-Point instruction set extension.11//12//===----------------------------------------------------------------------===//13 14//===----------------------------------------------------------------------===//15// RISC-V specific DAG Nodes.16//===----------------------------------------------------------------------===//17 18def SDT_RISCVFMV_W_X_RV6419 : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>;20def SDT_RISCVFMV_X_ANYEXTW_RV6421 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>;22def SDT_RISCVFCVT_W_RV6423 : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisFP<1>,24 SDTCisVT<2, i64>]>;25def SDT_RISCVFCVT_X26 : SDTypeProfile<1, 2, [SDTCisVT<0, XLenVT>, SDTCisFP<1>,27 SDTCisVT<2, XLenVT>]>;28 29def SDT_RISCVFROUND30 : SDTypeProfile<1, 3, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,31 SDTCisVT<3, XLenVT>]>;32def SDT_RISCVFCLASS33 : SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisFP<1>]>;34def SDT_RISCVFSGNJX35 : SDTypeProfile<1, 2, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>]>;36 37def riscv_fclass38 : RVSDNode<"FCLASS", SDT_RISCVFCLASS>;39 40// Rounds an FP value to its corresponding integer in the same FP format.41// First operand is the value to round, the second operand is the largest42// integer that can be represented exactly in the FP format. This will be43// expanded into multiple instructions and basic blocks with a custom44// inserter.45def riscv_fround46 : RVSDNode<"FROUND", SDT_RISCVFROUND>;47 48def riscv_fsgnjx49 : RVSDNode<"FSGNJX", SDT_RISCVFSGNJX>;50 51// FPR<->GPR transfer operations when the FPR is smaller than XLEN, needed as52// XLEN is the only legal integer width.53//54// FMV_W_X_RV64 matches the semantics of the FMV.W.X.55// FMV_X_ANYEXTW_RV64 is similar to FMV.X.W but has an any-extended result.56//57// This is a more convenient semantic for producing dagcombines that remove58// unnecessary GPR->FPR->GPR moves.59def riscv_fmv_w_x_rv6460 : RVSDNode<"FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>;61def riscv_fmv_x_anyextw_rv6462 : RVSDNode<"FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>;63 64// FP to 32 bit int conversions for RV64. These are used to keep track of the65// result being sign extended to 64 bit. These saturate out of range inputs.66// Used for FP_TO_S/UINT and FP_TO_S/UINT_SAT lowering. Rounding mode67// is passed as a TargetConstant operand using the RISCVFPRndMode enum.68def riscv_fcvt_w_rv6469 : RVSDNode<"FCVT_W_RV64", SDT_RISCVFCVT_W_RV64>;70def riscv_fcvt_wu_rv6471 : RVSDNode<"FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64>;72 73// FP to XLen int conversions. Corresponds to fcvt.l(u).s/d/h on RV64 and74// fcvt.w(u).s/d/h on RV32. Unlike FP_TO_S/UINT these saturate out of75// range inputs. These are used for FP_TO_S/UINT_SAT lowering. Rounding mode76// is passed as a TargetConstant operand using the RISCVFPRndMode enum.77def riscv_fcvt_x78 : RVSDNode<"FCVT_X", SDT_RISCVFCVT_X>;79def riscv_fcvt_xu80 : RVSDNode<"FCVT_XU", SDT_RISCVFCVT_X>;81 82// Floating point fmax and fmin matching the RISC-V instruction semantics.83def riscv_fmin : RVSDNode<"FMIN", SDTFPBinOp>;84def riscv_fmax : RVSDNode<"FMAX", SDTFPBinOp>;85 86let IsStrictFP = true in {87 // FP to 32 bit int conversions for RV64. These are used to keep track of the88 // result being sign extended to 64 bit. These saturate out of range inputs.89 def riscv_strict_fcvt_w_rv6490 : RVSDNode<"STRICT_FCVT_W_RV64", SDT_RISCVFCVT_W_RV64,91 [SDNPHasChain]>;92 def riscv_strict_fcvt_wu_rv6493 : RVSDNode<"STRICT_FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64,94 [SDNPHasChain]>;95}96 97def riscv_any_fcvt_w_rv64 : PatFrags<(ops node:$src, node:$frm),98 [(riscv_strict_fcvt_w_rv64 node:$src, node:$frm),99 (riscv_fcvt_w_rv64 node:$src, node:$frm)]>;100def riscv_any_fcvt_wu_rv64 : PatFrags<(ops node:$src, node:$frm),101 [(riscv_strict_fcvt_wu_rv64 node:$src, node:$frm),102 (riscv_fcvt_wu_rv64 node:$src, node:$frm)]>;103 104def any_fma_nsz : PatFrag<(ops node:$rs1, node:$rs2, node:$rs3),105 (any_fma node:$rs1, node:$rs2, node:$rs3), [{106 return N->getFlags().hasNoSignedZeros();107}]>;108//===----------------------------------------------------------------------===//109// Operand and SDNode transformation definitions.110//===----------------------------------------------------------------------===//111 112// Zfinx113 114def GPRAsFPR32 : AsmOperandClass {115 let Name = "GPRAsFPR32";116 let ParserMethod = "parseGPRAsFPR";117 let RenderMethod = "addRegOperands";118}119 120def FPR32INX : RegisterOperand<GPRF32> {121 let ParserMatchClass = GPRAsFPR32;122}123 124// Describes a combination of predicates from F/D/Q/Zfh/Zfhmin or125// Zfinx/Zdinx/Zhinx/Zhinxmin that are applied to scalar FP instruction.126// Contains the DAGOperand for the primary type for the predicates. The primary127// type may be unset for combinations of predicates like Zfh+D.128// Also contains the DAGOperand for f16/f32/f64, instruction suffix, and129// decoder namespace that go with an instruction given those predicates.130//131// The DAGOperand can be unset if the predicates are not enough to define it.132class ExtInfo<string suffix, string space, list<Predicate> predicates,133 ValueType primaryvt, DAGOperand primaryty, DAGOperand f32ty,134 DAGOperand f64ty, DAGOperand f16ty, ValueType intvt = XLenVT> {135 list<Predicate> Predicates = predicates;136 string Suffix = suffix;137 string Space = space;138 DAGOperand PrimaryTy = primaryty;139 DAGOperand F16Ty = f16ty;140 DAGOperand F32Ty = f32ty;141 DAGOperand F64Ty = f64ty;142 ValueType PrimaryVT = primaryvt;143 ValueType IntVT = intvt;144}145 146def FExt : ExtInfo<"", "", [HasStdExtF], f32, FPR32, FPR32, ?, ?>;147 148def ZfinxExt : ExtInfo<"_INX", "Zfinx", [HasStdExtZfinx], f32, FPR32INX, FPR32INX, ?, ?>;149 150defvar FExts = [FExt, ZfinxExt];151 152// Floating-point rounding mode153 154def FRMArg : AsmOperandClass {155 let Name = "FRMArg";156 let RenderMethod = "addFRMArgOperands";157 let ParserMethod = "parseFRMArg";158 let IsOptional = 1;159 let DefaultMethod = "defaultFRMArgOp";160}161 162def frmarg : Operand<XLenVT> {163 let ParserMatchClass = FRMArg;164 let PrintMethod = "printFRMArg";165 let DecoderMethod = "decodeFRMArg";166 let OperandType = "OPERAND_FRMARG";167 let OperandNamespace = "RISCVOp";168}169 170// Variants of the rounding mode operand that default to 'rne'. This is used171// for historical/legacy reasons. fcvt functions where the rounding mode172// doesn't affect the output originally always set it to 0b000 ('rne'). As old173// versions of LLVM and GCC will fail to decode versions of these instructions174// with the rounding mode set to something other than 'rne', we retain this175// default.176def FRMArgLegacy : AsmOperandClass {177 let Name = "FRMArgLegacy";178 let RenderMethod = "addFRMArgOperands";179 let ParserMethod = "parseFRMArg";180 let IsOptional = 1;181 let DefaultMethod = "defaultFRMArgLegacyOp";182}183 184def frmarglegacy : Operand<XLenVT> {185 let ParserMatchClass = FRMArgLegacy;186 let PrintMethod = "printFRMArgLegacy";187 let DecoderMethod = "decodeFRMArg";188 let OperandType = "OPERAND_FRMARG";189 let OperandNamespace = "RISCVOp";190}191 192//===----------------------------------------------------------------------===//193// Instruction class templates194//===----------------------------------------------------------------------===//195 196let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in197class FPLoad_r<bits<3> funct3, string opcodestr, DAGOperand rty,198 SchedWrite sw>199 : RVInstI<funct3, OPC_LOAD_FP, (outs rty:$rd),200 (ins GPRMem:$rs1, simm12_lo:$imm12),201 opcodestr, "$rd, ${imm12}(${rs1})">,202 Sched<[sw, ReadFMemBase]>;203 204let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in205class FPStore_r<bits<3> funct3, string opcodestr, DAGOperand rty,206 SchedWrite sw>207 : RVInstS<funct3, OPC_STORE_FP, (outs),208 (ins rty:$rs2, GPRMem:$rs1, simm12_lo:$imm12),209 opcodestr, "$rs2, ${imm12}(${rs1})">,210 Sched<[sw, ReadFStoreData, ReadFMemBase]>;211 212let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,213 UseNamedOperandTable = 1, hasPostISelHook = 1, isCommutable = 1 in214class FPFMA_rrr_frm<RISCVOpcode opcode, bits<2> funct2, string opcodestr,215 DAGOperand rty>216 : RVInstR4Frm<funct2, opcode, (outs rty:$rd),217 (ins rty:$rs1, rty:$rs2, rty:$rs3, frmarg:$frm),218 opcodestr, "$rd, $rs1, $rs2, $rs3$frm">;219 220multiclass FPFMA_rrr_frm_m<RISCVOpcode opcode, bits<2> funct2,221 string opcodestr, ExtInfo Ext> {222 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in223 def Ext.Suffix : FPFMA_rrr_frm<opcode, funct2, opcodestr, Ext.PrimaryTy>;224}225 226let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in227class FPALU_rr<bits<7> funct7, bits<3> funct3, string opcodestr,228 DAGOperand rty, bit Commutable>229 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rty:$rd),230 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2"> {231 let isCommutable = Commutable;232}233multiclass FPALU_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr,234 ExtInfo Ext, bit Commutable = 0> {235 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in236 def Ext.Suffix : FPALU_rr<funct7, funct3, opcodestr, Ext.PrimaryTy, Commutable>;237}238 239let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,240 UseNamedOperandTable = 1, hasPostISelHook = 1 in241class FPALU_rr_frm<bits<7> funct7, string opcodestr, DAGOperand rty,242 bit Commutable>243 : RVInstRFrm<funct7, OPC_OP_FP, (outs rty:$rd),244 (ins rty:$rs1, rty:$rs2, frmarg:$frm), opcodestr,245 "$rd, $rs1, $rs2$frm"> {246 let isCommutable = Commutable;247}248multiclass FPALU_rr_frm_m<bits<7> funct7, string opcodestr,249 ExtInfo Ext, bit Commutable = 0> {250 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in251 def Ext.Suffix : FPALU_rr_frm<funct7, opcodestr, Ext.PrimaryTy, Commutable>;252}253 254let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in255class FPUnaryOp_r<bits<7> funct7, bits<5> rs2val, bits<3> funct3,256 DAGOperand rdty, DAGOperand rs1ty, string opcodestr>257 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd), (ins rs1ty:$rs1),258 opcodestr, "$rd, $rs1"> {259 let rs2 = rs2val;260}261multiclass FPUnaryOp_r_m<bits<7> funct7, bits<5> rs2val, bits<3> funct3,262 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,263 string opcodestr> {264 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in265 def Ext.Suffix : FPUnaryOp_r<funct7, rs2val, funct3, rdty, rs1ty, opcodestr>;266}267 268let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,269 UseNamedOperandTable = 1, hasPostISelHook = 1 in270class FPUnaryOp_r_frm<bits<7> funct7, bits<5> rs2val, DAGOperand rdty,271 DAGOperand rs1ty, string opcodestr>272 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd),273 (ins rs1ty:$rs1, frmarg:$frm), opcodestr,274 "$rd, $rs1$frm"> {275 let rs2 = rs2val;276}277multiclass FPUnaryOp_r_frm_m<bits<7> funct7, bits<5> rs2val,278 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,279 string opcodestr, list<Predicate> ExtraPreds = []> {280 let Predicates = !listconcat(Ext.Predicates, ExtraPreds),281 DecoderNamespace = Ext.Space in282 def Ext.Suffix : FPUnaryOp_r_frm<funct7, rs2val, rdty, rs1ty,283 opcodestr>;284}285 286let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,287 UseNamedOperandTable = 1, hasPostISelHook = 1 in288class FPUnaryOp_r_frmlegacy<bits<7> funct7, bits<5> rs2val, DAGOperand rdty,289 DAGOperand rs1ty, string opcodestr>290 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd),291 (ins rs1ty:$rs1, frmarglegacy:$frm), opcodestr,292 "$rd, $rs1$frm"> {293 let rs2 = rs2val;294}295multiclass FPUnaryOp_r_frmlegacy_m<bits<7> funct7, bits<5> rs2val,296 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,297 string opcodestr, list<Predicate> ExtraPreds = []> {298 let Predicates = !listconcat(Ext.Predicates, ExtraPreds),299 DecoderNamespace = Ext.Space in300 def Ext.Suffix : FPUnaryOp_r_frmlegacy<funct7, rs2val, rdty, rs1ty,301 opcodestr>;302}303 304let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,305 IsSignExtendingOpW = 1 in306class FPCmp_rr<bits<7> funct7, bits<3> funct3, string opcodestr,307 DAGOperand rty, bit Commutable = 0>308 : RVInstR<funct7, funct3, OPC_OP_FP, (outs GPR:$rd),309 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2"> {310 let isCommutable = Commutable;311}312multiclass FPCmp_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr,313 ExtInfo Ext, bit Commutable = 0> {314 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in315 def Ext.Suffix : FPCmp_rr<funct7, funct3, opcodestr, Ext.PrimaryTy, Commutable>;316}317 318class PseudoFROUND<DAGOperand Ty, ValueType vt, ValueType intvt = XLenVT>319 : Pseudo<(outs Ty:$rd), (ins Ty:$rs1, Ty:$rs2, ixlenimm:$rm),320 [(set Ty:$rd, (vt (riscv_fround Ty:$rs1, Ty:$rs2, (intvt timm:$rm))))]> {321 let hasSideEffects = 0;322 let mayLoad = 0;323 let mayStore = 0;324 let usesCustomInserter = 1;325 let mayRaiseFPException = 1;326}327 328//===----------------------------------------------------------------------===//329// Instructions330//===----------------------------------------------------------------------===//331 332let Predicates = [HasStdExtF] in {333let canFoldAsLoad = 1, isReMaterializable = 1 in334def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>;335 336// Operands for stores are in the order srcreg, base, offset rather than337// reflecting the order these fields are specified in the instruction338// encoding.339def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>;340} // Predicates = [HasStdExtF]341 342let Predicates = [HasStdExtZfinx], isCodeGenOnly = 1 in {343def LW_INX : Load_ri<0b010, "lw", GPRF32>, Sched<[WriteLDW, ReadMemBase]>;344def SW_INX : Store_rri<0b010, "sw", GPRF32>,345 Sched<[WriteSTW, ReadStoreData, ReadMemBase]>;346 347// ADDI with GPRF32 register class to use for copy. This should not be used as348// general ADDI, so the immediate should always be zero.349let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveReg = 1,350 hasSideEffects = 0, mayLoad = 0, mayStore = 0 in351def PseudoMV_FPR32INX : Pseudo<(outs GPRF32:$rd), (ins GPRF32:$rs), []>,352 Sched<[WriteIALU, ReadIALU]>;353}354 355foreach Ext = FExts in {356 let SchedRW = [WriteFMA32, ReadFMA32, ReadFMA32, ReadFMA32Addend] in {357 defm FMADD_S : FPFMA_rrr_frm_m<OPC_MADD, 0b00, "fmadd.s", Ext>;358 defm FMSUB_S : FPFMA_rrr_frm_m<OPC_MSUB, 0b00, "fmsub.s", Ext>;359 defm FNMSUB_S : FPFMA_rrr_frm_m<OPC_NMSUB, 0b00, "fnmsub.s", Ext>;360 defm FNMADD_S : FPFMA_rrr_frm_m<OPC_NMADD, 0b00, "fnmadd.s", Ext>;361 }362 363 let SchedRW = [WriteFAdd32, ReadFAdd32, ReadFAdd32] in {364 defm FADD_S : FPALU_rr_frm_m<0b0000000, "fadd.s", Ext, Commutable=1>;365 defm FSUB_S : FPALU_rr_frm_m<0b0000100, "fsub.s", Ext>;366 }367 368 let SchedRW = [WriteFMul32, ReadFMul32, ReadFMul32] in369 defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", Ext, Commutable=1>;370 371 let SchedRW = [WriteFDiv32, ReadFDiv32, ReadFDiv32] in372 defm FDIV_S : FPALU_rr_frm_m<0b0001100, "fdiv.s", Ext>;373 374 defm FSQRT_S : FPUnaryOp_r_frm_m<0b0101100, 0b00000, Ext, Ext.PrimaryTy,375 Ext.PrimaryTy, "fsqrt.s">,376 Sched<[WriteFSqrt32, ReadFSqrt32]>;377 378 let SchedRW = [WriteFSGNJ32, ReadFSGNJ32, ReadFSGNJ32],379 mayRaiseFPException = 0 in {380 defm FSGNJ_S : FPALU_rr_m<0b0010000, 0b000, "fsgnj.s", Ext>;381 defm FSGNJN_S : FPALU_rr_m<0b0010000, 0b001, "fsgnjn.s", Ext>;382 defm FSGNJX_S : FPALU_rr_m<0b0010000, 0b010, "fsgnjx.s", Ext>;383 }384 385 let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in {386 defm FMIN_S : FPALU_rr_m<0b0010100, 0b000, "fmin.s", Ext, Commutable=1>;387 defm FMAX_S : FPALU_rr_m<0b0010100, 0b001, "fmax.s", Ext, Commutable=1>;388 }389 390 let IsSignExtendingOpW = 1 in391 defm FCVT_W_S : FPUnaryOp_r_frm_m<0b1100000, 0b00000, Ext, GPR, Ext.PrimaryTy,392 "fcvt.w.s">,393 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>;394 395 let IsSignExtendingOpW = 1 in396 defm FCVT_WU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00001, Ext, GPR, Ext.PrimaryTy,397 "fcvt.wu.s">,398 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>;399 400 let SchedRW = [WriteFCmp32, ReadFCmp32, ReadFCmp32] in {401 defm FEQ_S : FPCmp_rr_m<0b1010000, 0b010, "feq.s", Ext, Commutable=1>;402 defm FLT_S : FPCmp_rr_m<0b1010000, 0b001, "flt.s", Ext>;403 defm FLE_S : FPCmp_rr_m<0b1010000, 0b000, "fle.s", Ext>;404 }405 406 let mayRaiseFPException = 0 in407 defm FCLASS_S : FPUnaryOp_r_m<0b1110000, 0b00000, 0b001, Ext, GPR, Ext.PrimaryTy,408 "fclass.s">,409 Sched<[WriteFClass32, ReadFClass32]>;410 411 defm FCVT_S_W : FPUnaryOp_r_frm_m<0b1101000, 0b00000, Ext, Ext.PrimaryTy, GPR,412 "fcvt.s.w">,413 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>;414 415 defm FCVT_S_WU : FPUnaryOp_r_frm_m<0b1101000, 0b00001, Ext, Ext.PrimaryTy, GPR,416 "fcvt.s.wu">,417 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>;418 419 defm FCVT_L_S : FPUnaryOp_r_frm_m<0b1100000, 0b00010, Ext, GPR, Ext.PrimaryTy,420 "fcvt.l.s", [IsRV64]>,421 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>;422 423 defm FCVT_LU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00011, Ext, GPR, Ext.PrimaryTy,424 "fcvt.lu.s", [IsRV64]>,425 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>;426 427 defm FCVT_S_L : FPUnaryOp_r_frm_m<0b1101000, 0b00010, Ext, Ext.PrimaryTy, GPR,428 "fcvt.s.l", [IsRV64]>,429 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>;430 431 defm FCVT_S_LU : FPUnaryOp_r_frm_m<0b1101000, 0b00011, Ext, Ext.PrimaryTy, GPR,432 "fcvt.s.lu", [IsRV64]>,433 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>;434} // foreach Ext = FExts435 436let Predicates = [HasStdExtF], mayRaiseFPException = 0,437 IsSignExtendingOpW = 1 in438def FMV_X_W : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR32, "fmv.x.w">,439 Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>;440 441let Predicates = [HasStdExtF], mayRaiseFPException = 0 in442def FMV_W_X : FPUnaryOp_r<0b1111000, 0b00000, 0b000, FPR32, GPR, "fmv.w.x">,443 Sched<[WriteFMovI32ToF32, ReadFMovI32ToF32]>;444 445//===----------------------------------------------------------------------===//446// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)447//===----------------------------------------------------------------------===//448 449let Predicates = [HasStdExtFOrZfinx] in {450// The following csr instructions actually alias instructions from the base ISA.451// However, it only makes sense to support them when the F or Zfinx extension is452// enabled.453// NOTE: "frcsr", "frrm", and "frflags" are more specialized version of "csrr".454def : InstAlias<"frcsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 2>;455def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs)>;456def : InstAlias<"fscsr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 2>;457 458// frsr, fssr are obsolete aliases replaced by frcsr, fscsr.459def : MnemonicAlias<"frsr", "frcsr">;460def : MnemonicAlias<"fssr", "fscsr">;461 462def : InstAlias<"frrm $rd", (CSRRS GPR:$rd, SysRegFRM.Encoding, X0), 2>;463def : InstAlias<"fsrm $rd, $rs", (CSRRW GPR:$rd, SysRegFRM.Encoding, GPR:$rs)>;464def : InstAlias<"fsrm $rs", (CSRRW X0, SysRegFRM.Encoding, GPR:$rs), 2>;465def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, SysRegFRM.Encoding, uimm5:$imm)>;466def : InstAlias<"fsrmi $imm", (CSRRWI X0, SysRegFRM.Encoding, uimm5:$imm), 2>;467 468def : InstAlias<"frflags $rd", (CSRRS GPR:$rd, SysRegFFLAGS.Encoding, X0), 2>;469def : InstAlias<"fsflags $rd, $rs", (CSRRW GPR:$rd, SysRegFFLAGS.Encoding, GPR:$rs)>;470def : InstAlias<"fsflags $rs", (CSRRW X0, SysRegFFLAGS.Encoding, GPR:$rs), 2>;471def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, SysRegFFLAGS.Encoding, uimm5:$imm)>;472def : InstAlias<"fsflagsi $imm", (CSRRWI X0, SysRegFFLAGS.Encoding, uimm5:$imm), 2>;473} // Predicates = [HasStdExtFOrZfinx]474 475let Predicates = [HasStdExtF] in {476def : InstAlias<"flw $rd, (${rs1})", (FLW FPR32:$rd, GPR:$rs1, 0), 0>;477def : InstAlias<"fsw $rs2, (${rs1})", (FSW FPR32:$rs2, GPR:$rs1, 0), 0>;478 479def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;480def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;481def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;482 483// fgt.s/fge.s are recognised by the GNU assembler but the canonical484// flt.s/fle.s forms will always be printed. Therefore, set a zero weight.485def : InstAlias<"fgt.s $rd, $rs, $rt",486 (FLT_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;487def : InstAlias<"fge.s $rd, $rs, $rt",488 (FLE_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;489 490// fmv.w.x and fmv.x.w were previously known as fmv.s.x and fmv.x.s. Both491// spellings should be supported by standard tools.492def : MnemonicAlias<"fmv.s.x", "fmv.w.x">;493def : MnemonicAlias<"fmv.x.s", "fmv.x.w">;494 495def PseudoFLW : PseudoFloatLoad<"flw", FPR32>;496def PseudoFSW : PseudoStore<"fsw", FPR32>;497let usesCustomInserter = 1 in {498def PseudoQuietFLE_S : PseudoQuietFCMP<FPR32>;499def PseudoQuietFLT_S : PseudoQuietFCMP<FPR32>;500}501} // Predicates = [HasStdExtF]502 503let Predicates = [HasStdExtZfinx] in {504def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;505def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;506def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;507 508def : InstAlias<"fgt.s $rd, $rs, $rt",509 (FLT_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>;510def : InstAlias<"fge.s $rd, $rs, $rt",511 (FLE_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>;512let usesCustomInserter = 1 in {513def PseudoQuietFLE_S_INX : PseudoQuietFCMP<FPR32INX>;514def PseudoQuietFLT_S_INX : PseudoQuietFCMP<FPR32INX>;515}516} // Predicates = [HasStdExtZfinx]517 518//===----------------------------------------------------------------------===//519// Pseudo-instructions and codegen patterns520//===----------------------------------------------------------------------===//521 522defvar FRM_RNE = 0b000;523defvar FRM_RTZ = 0b001;524defvar FRM_RDN = 0b010;525defvar FRM_RUP = 0b011;526defvar FRM_RMM = 0b100;527defvar FRM_DYN = 0b111;528 529/// Floating point constants530def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;531 532/// Generic pattern classes533class PatSetCC<DAGOperand Ty, SDPatternOperator OpNode, CondCode Cond,534 RVInstCommon Inst, ValueType vt, ValueType intvt = XLenVT>535 : Pat<(intvt (OpNode (vt Ty:$rs1), Ty:$rs2, Cond)), (Inst $rs1, $rs2)>;536multiclass PatSetCC_m<SDPatternOperator OpNode, CondCode Cond,537 RVInstCommon Inst, ExtInfo Ext> {538 let Predicates = Ext.Predicates in539 def Ext.Suffix : PatSetCC<Ext.PrimaryTy, OpNode, Cond,540 !cast<RVInstCommon>(Inst#Ext.Suffix),541 Ext.PrimaryVT, Ext.IntVT>;542}543 544class PatFprFpr<SDPatternOperator OpNode, RVInstR Inst,545 DAGOperand RegTy, ValueType vt>546 : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2)>;547multiclass PatFprFpr_m<SDPatternOperator OpNode, RVInstR Inst,548 ExtInfo Ext> {549 let Predicates = Ext.Predicates in550 def Ext.Suffix : PatFprFpr<OpNode, !cast<RVInstR>(Inst#Ext.Suffix),551 Ext.PrimaryTy, Ext.PrimaryVT>;552}553 554class PatFprFprDynFrm<SDPatternOperator OpNode, RVInstRFrm Inst,555 DAGOperand RegTy, ValueType vt, ValueType intvt>556 : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)),557 (Inst $rs1, $rs2,(intvt FRM_DYN))>;558multiclass PatFprFprDynFrm_m<SDPatternOperator OpNode, RVInstRFrm Inst,559 ExtInfo Ext> {560 let Predicates = Ext.Predicates in561 def Ext.Suffix : PatFprFprDynFrm<OpNode,562 !cast<RVInstRFrm>(Inst#Ext.Suffix),563 Ext.PrimaryTy, Ext.PrimaryVT, Ext.IntVT>;564}565 566/// Float conversion operations567 568// [u]int32<->float conversion patterns must be gated on IsRV32 or IsRV64, so569// are defined later.570 571/// Float arithmetic operations572foreach Ext = FExts in {573 defm : PatFprFprDynFrm_m<any_fadd, FADD_S, Ext>;574 defm : PatFprFprDynFrm_m<any_fsub, FSUB_S, Ext>;575 defm : PatFprFprDynFrm_m<any_fmul, FMUL_S, Ext>;576 defm : PatFprFprDynFrm_m<any_fdiv, FDIV_S, Ext>;577}578 579let Predicates = [HasStdExtF] in {580def : Pat<(any_fsqrt FPR32:$rs1), (FSQRT_S FPR32:$rs1, FRM_DYN)>;581 582def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>;583def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>;584 585def : Pat<(riscv_fclass FPR32:$rs1), (FCLASS_S $rs1)>;586} // Predicates = [HasStdExtF]587 588let Predicates = [HasStdExtZfinx] in {589def : Pat<(any_fsqrt FPR32INX:$rs1), (FSQRT_S_INX FPR32INX:$rs1, FRM_DYN)>;590 591def : Pat<(fneg FPR32INX:$rs1), (FSGNJN_S_INX $rs1, $rs1)>;592def : Pat<(fabs FPR32INX:$rs1), (FSGNJX_S_INX $rs1, $rs1)>;593 594def : Pat<(riscv_fclass FPR32INX:$rs1), (FCLASS_S_INX $rs1)>;595} // Predicates = [HasStdExtZfinx]596 597foreach Ext = FExts in {598defm : PatFprFpr_m<fcopysign, FSGNJ_S, Ext>;599defm : PatFprFpr_m<riscv_fsgnjx, FSGNJX_S, Ext>;600}601 602let Predicates = [HasStdExtF] in {603def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)),604 (FSGNJN_S FPR32:$rs1, FPR32:$rs2)>;605 606// fmadd: rs1 * rs2 + rs3607def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3),608 (FMADD_S $rs1, $rs2, $rs3, FRM_DYN)>;609 610// fmsub: rs1 * rs2 - rs3611def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)),612 (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;613 614// fnmsub: -rs1 * rs2 + rs3615def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, FPR32:$rs3),616 (FNMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;617 618// fnmadd: -rs1 * rs2 - rs3619def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)),620 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;621 622// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)623def : Pat<(fneg (any_fma_nsz FPR32:$rs1, FPR32:$rs2, FPR32:$rs3)),624 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;625} // Predicates = [HasStdExtF]626 627let Predicates = [HasStdExtZfinx] in {628def : Pat<(fcopysign FPR32INX:$rs1, (fneg FPR32INX:$rs2)),629 (FSGNJN_S_INX FPR32INX:$rs1, FPR32INX:$rs2)>;630 631// fmadd: rs1 * rs2 + rs3632def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3),633 (FMADD_S_INX $rs1, $rs2, $rs3, FRM_DYN)>;634 635// fmsub: rs1 * rs2 - rs3636def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, (fneg FPR32INX:$rs3)),637 (FMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;638 639// fnmsub: -rs1 * rs2 + rs3640def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, FPR32INX:$rs3),641 (FNMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;642 643// fnmadd: -rs1 * rs2 - rs3644def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, (fneg FPR32INX:$rs3)),645 (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;646 647// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)648def : Pat<(fneg (any_fma_nsz FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3)),649 (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;650} // Predicates = [HasStdExtZfinx]651 652// The ratified 20191213 ISA spec defines fmin and fmax in a way that matches653// LLVM's fminnum and fmaxnum654// <https://github.com/riscv/riscv-isa-manual/commit/cd20cee7efd9bac7c5aa127ec3b451749d2b3cce>.655foreach Ext = FExts in {656 defm : PatFprFpr_m<fminnum, FMIN_S, Ext>;657 defm : PatFprFpr_m<fmaxnum, FMAX_S, Ext>;658 defm : PatFprFpr_m<fminimumnum, FMIN_S, Ext>;659 defm : PatFprFpr_m<fmaximumnum, FMAX_S, Ext>;660 defm : PatFprFpr_m<riscv_fmin, FMIN_S, Ext>;661 defm : PatFprFpr_m<riscv_fmax, FMAX_S, Ext>;662 let Predicates = Ext.Predicates in663 def : Pat<(f32 (fcanonicalize FPR32:$rs1)), (FMIN_S $rs1, $rs1)>;664}665 666/// Setcc667// FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for668// strict versions of those.669 670// Match non-signaling FEQ_S671foreach Ext = FExts in {672 defm : PatSetCC_m<any_fsetcc, SETEQ, FEQ_S, Ext>;673 defm : PatSetCC_m<any_fsetcc, SETOEQ, FEQ_S, Ext>;674 defm : PatSetCC_m<strict_fsetcc, SETLT, PseudoQuietFLT_S, Ext>;675 defm : PatSetCC_m<strict_fsetcc, SETOLT, PseudoQuietFLT_S, Ext>;676 defm : PatSetCC_m<strict_fsetcc, SETLE, PseudoQuietFLE_S, Ext>;677 defm : PatSetCC_m<strict_fsetcc, SETOLE, PseudoQuietFLE_S, Ext>;678}679 680let Predicates = [HasStdExtF] in {681// Match signaling FEQ_S682def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETEQ)),683 (AND (XLenVT (FLE_S $rs1, $rs2)),684 (XLenVT (FLE_S $rs2, $rs1)))>;685def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETOEQ)),686 (AND (XLenVT (FLE_S $rs1, $rs2)),687 (XLenVT (FLE_S $rs2, $rs1)))>;688// If both operands are the same, use a single FLE.689def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETEQ)),690 (FLE_S $rs1, $rs1)>;691def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETOEQ)),692 (FLE_S $rs1, $rs1)>;693} // Predicates = [HasStdExtF]694 695let Predicates = [HasStdExtZfinx] in {696// Match signaling FEQ_S697def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETEQ)),698 (AND (XLenVT (FLE_S_INX $rs1, $rs2)),699 (XLenVT (FLE_S_INX $rs2, $rs1)))>;700def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETOEQ)),701 (AND (XLenVT (FLE_S_INX $rs1, $rs2)),702 (XLenVT (FLE_S_INX $rs2, $rs1)))>;703// If both operands are the same, use a single FLE.704def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETEQ)),705 (FLE_S_INX $rs1, $rs1)>;706def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETOEQ)),707 (FLE_S_INX $rs1, $rs1)>;708} // Predicates = [HasStdExtZfinx]709 710foreach Ext = FExts in {711 defm : PatSetCC_m<any_fsetccs, SETLT, FLT_S, Ext>;712 defm : PatSetCC_m<any_fsetccs, SETOLT, FLT_S, Ext>;713 defm : PatSetCC_m<any_fsetccs, SETLE, FLE_S, Ext>;714 defm : PatSetCC_m<any_fsetccs, SETOLE, FLE_S, Ext>;715}716 717let Predicates = [HasStdExtF] in {718defm Select_FPR32 : SelectCC_GPR_rrirr<FPR32, f32>;719 720def PseudoFROUND_S : PseudoFROUND<FPR32, f32>;721 722/// Loads723 724def : LdPat<load, FLW, f32>;725 726/// Stores727 728def : StPat<store, FSW, FPR32, f32>;729 730} // Predicates = [HasStdExtF]731 732let Predicates = [HasStdExtZfinx] in {733defm Select_FPR32INX : SelectCC_GPR_rrirr<FPR32INX, f32>;734 735def PseudoFROUND_S_INX : PseudoFROUND<FPR32INX, f32>;736 737/// Loads738def : LdPat<load, LW_INX, f32>;739 740/// Stores741def : StPat<store, SW_INX, GPRF32, f32>;742} // Predicates = [HasStdExtZfinx]743 744let Predicates = [HasStdExtF, IsRV32] in {745// Moves (no conversion)746def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>;747def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>;748} // Predicates = [HasStdExtF]749 750let Predicates = [HasStdExtZfinx, IsRV32] in {751// Moves (no conversion)752def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (EXTRACT_SUBREG GPR:$rs1, sub_32)>;753def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR32INX:$rs1, sub_32)>;754} // Predicates = [HasStdExtZfinx]755 756let Predicates = [HasStdExtF, IsRV32] in {757// float->[u]int. Round-to-zero must be used.758def : Pat<(i32 (any_fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RTZ)>;759def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, FRM_RTZ)>;760 761// Saturating float->[u]int32.762def : Pat<(i32 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_W_S $rs1, timm:$frm)>;763def : Pat<(i32 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_WU_S $rs1, timm:$frm)>;764 765// float->int32 with current rounding mode.766def : Pat<(i32 (any_lrint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_DYN)>;767 768// float->int32 rounded to nearest with ties rounded away from zero.769def : Pat<(i32 (any_lround FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RMM)>;770 771// [u]int->float. Match GCC and default to using dynamic rounding mode.772def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W $rs1, FRM_DYN)>;773def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU $rs1, FRM_DYN)>;774} // Predicates = [HasStdExtF, IsRV32]775 776let Predicates = [HasStdExtZfinx, IsRV32] in {777// float->[u]int. Round-to-zero must be used.778def : Pat<(i32 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RTZ)>;779def : Pat<(i32 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_WU_S_INX $rs1, FRM_RTZ)>;780 781// Saturating float->[u]int32.782def : Pat<(i32 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_W_S_INX $rs1, timm:$frm)>;783def : Pat<(i32 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_WU_S_INX $rs1, timm:$frm)>;784 785// float->int32 with current rounding mode.786def : Pat<(i32 (any_lrint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_DYN)>;787 788// float->int32 rounded to nearest with ties rounded away from zero.789def : Pat<(i32 (any_lround FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RMM)>;790 791// [u]int->float. Match GCC and default to using dynamic rounding mode.792def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W_INX $rs1, FRM_DYN)>;793def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU_INX $rs1, FRM_DYN)>;794} // Predicates = [HasStdExtZfinx, IsRV32]795 796let Predicates = [HasStdExtF, IsRV64] in {797// Moves (no conversion)798def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>;799def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>;800 801// Use target specific isd nodes to help us remember the result is sign802// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be803// duplicated if it has another user that didn't need the sign_extend.804def : Pat<(riscv_any_fcvt_w_rv64 FPR32:$rs1, timm:$frm), (FCVT_W_S $rs1, timm:$frm)>;805def : Pat<(riscv_any_fcvt_wu_rv64 FPR32:$rs1, timm:$frm), (FCVT_WU_S $rs1, timm:$frm)>;806 807// float->[u]int64. Round-to-zero must be used.808def : Pat<(i64 (any_fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RTZ)>;809def : Pat<(i64 (any_fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, FRM_RTZ)>;810 811// Saturating float->[u]int64.812def : Pat<(i64 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_L_S $rs1, timm:$frm)>;813def : Pat<(i64 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_LU_S $rs1, timm:$frm)>;814 815// float->int64 with current rounding mode.816def : Pat<(i64 (any_lrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>;817def : Pat<(i64 (any_llrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>;818 819// float->int64 rounded to neartest with ties rounded away from zero.820def : Pat<(i64 (any_lround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>;821def : Pat<(i64 (any_llround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>;822 823// [u]int->fp. Match GCC and default to using dynamic rounding mode.824def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W $rs1, FRM_DYN)>;825def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU $rs1, FRM_DYN)>;826def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L $rs1, FRM_DYN)>;827def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU $rs1, FRM_DYN)>;828} // Predicates = [HasStdExtF, IsRV64]829 830let Predicates = [HasStdExtZfinx, IsRV64] in {831// Moves (no conversion)832def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (EXTRACT_SUBREG GPR:$src, sub_32)>;833def : Pat<(riscv_fmv_x_anyextw_rv64 GPRF32:$src), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR32INX:$src, sub_32)>;834 835// Use target specific isd nodes to help us remember the result is sign836// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be837// duplicated if it has another user that didn't need the sign_extend.838def : Pat<(riscv_any_fcvt_w_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_W_S_INX $rs1, timm:$frm)>;839def : Pat<(riscv_any_fcvt_wu_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_WU_S_INX $rs1, timm:$frm)>;840 841// float->[u]int64. Round-to-zero must be used.842def : Pat<(i64 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RTZ)>;843def : Pat<(i64 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_LU_S_INX $rs1, FRM_RTZ)>;844 845// Saturating float->[u]int64.846def : Pat<(i64 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_L_S_INX $rs1, timm:$frm)>;847def : Pat<(i64 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_LU_S_INX $rs1, timm:$frm)>;848 849// float->int64 with current rounding mode.850def : Pat<(i64 (any_lrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;851def : Pat<(i64 (any_llrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;852 853// float->int64 rounded to neartest with ties rounded away from zero.854def : Pat<(i64 (any_lround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RMM)>;855def : Pat<(i64 (any_llround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RMM)>;856 857// [u]int->fp. Match GCC and default to using dynamic rounding mode.858def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W_INX $rs1, FRM_DYN)>;859def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU_INX $rs1, FRM_DYN)>;860def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L_INX $rs1, FRM_DYN)>;861def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU_INX $rs1, FRM_DYN)>;862} // Predicates = [HasStdExtZfinx, IsRV64]863