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-exception 6// 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_RV64 19 : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>; 20def SDT_RISCVFMV_X_ANYEXTW_RV64 21 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>; 22def SDT_RISCVFCVT_W_RV64 23 : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisFP<1>, 24 SDTCisVT<2, i64>]>; 25def SDT_RISCVFCVT_X 26 : SDTypeProfile<1, 2, [SDTCisVT<0, XLenVT>, SDTCisFP<1>, 27 SDTCisVT<2, XLenVT>]>; 28 29def SDT_RISCVFROUND 30 : SDTypeProfile<1, 3, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, 31 SDTCisVT<3, XLenVT>]>; 32def SDT_RISCVFCLASS 33 : SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisFP<1>]>; 34def SDT_RISCVFSGNJX 35 : SDTypeProfile<1, 2, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>]>; 36 37def riscv_fclass 38 : SDNode<"RISCVISD::FCLASS", SDT_RISCVFCLASS>; 39 40def riscv_fround 41 : SDNode<"RISCVISD::FROUND", SDT_RISCVFROUND>; 42 43def riscv_fsgnjx 44 : SDNode<"RISCVISD::FSGNJX", SDT_RISCVFSGNJX>; 45 46def riscv_fmv_w_x_rv64 47 : SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>; 48def riscv_fmv_x_anyextw_rv64 49 : SDNode<"RISCVISD::FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>; 50def riscv_fcvt_w_rv64 51 : SDNode<"RISCVISD::FCVT_W_RV64", SDT_RISCVFCVT_W_RV64>; 52def riscv_fcvt_wu_rv64 53 : SDNode<"RISCVISD::FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64>; 54def riscv_fcvt_x 55 : SDNode<"RISCVISD::FCVT_X", SDT_RISCVFCVT_X>; 56def riscv_fcvt_xu 57 : SDNode<"RISCVISD::FCVT_XU", SDT_RISCVFCVT_X>; 58 59def riscv_fmin : SDNode<"RISCVISD::FMIN", SDTFPBinOp>; 60def riscv_fmax : SDNode<"RISCVISD::FMAX", SDTFPBinOp>; 61 62def riscv_strict_fcvt_w_rv64 63 : SDNode<"RISCVISD::STRICT_FCVT_W_RV64", SDT_RISCVFCVT_W_RV64, 64 [SDNPHasChain]>; 65def riscv_strict_fcvt_wu_rv64 66 : SDNode<"RISCVISD::STRICT_FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64, 67 [SDNPHasChain]>; 68 69def riscv_any_fcvt_w_rv64 : PatFrags<(ops node:$src, node:$frm), 70 [(riscv_strict_fcvt_w_rv64 node:$src, node:$frm), 71 (riscv_fcvt_w_rv64 node:$src, node:$frm)]>; 72def riscv_any_fcvt_wu_rv64 : PatFrags<(ops node:$src, node:$frm), 73 [(riscv_strict_fcvt_wu_rv64 node:$src, node:$frm), 74 (riscv_fcvt_wu_rv64 node:$src, node:$frm)]>; 75 76def any_fma_nsz : PatFrag<(ops node:$rs1, node:$rs2, node:$rs3), 77 (any_fma node:$rs1, node:$rs2, node:$rs3), [{ 78 return N->getFlags().hasNoSignedZeros(); 79}]>; 80//===----------------------------------------------------------------------===// 81// Operand and SDNode transformation definitions. 82//===----------------------------------------------------------------------===// 83 84// Zfinx 85 86def GPRAsFPR32 : AsmOperandClass { 87 let Name = "GPRAsFPR32"; 88 let ParserMethod = "parseGPRAsFPR"; 89 let RenderMethod = "addRegOperands"; 90} 91 92def FPR32INX : RegisterOperand<GPRF32> { 93 let ParserMatchClass = GPRAsFPR32; 94} 95 96// Describes a combination of predicates from F/D/Zfh/Zfhmin or 97// Zfinx/Zdinx/Zhinx/Zhinxmin that are applied to scalar FP instruction. 98// Contains the DAGOperand for the primary type for the predicates. The primary 99// type may be unset for combinations of predicates like Zfh+D. 100// Also contains the DAGOperand for f16/f32/f64, instruction suffix, and 101// decoder namespace that go with an instruction given those predicates. 102// 103// The DAGOperand can be unset if the predicates are not enough to define it. 104class ExtInfo<string suffix, string space, list<Predicate> predicates, 105 ValueType primaryvt, DAGOperand primaryty, DAGOperand f32ty, 106 DAGOperand f64ty, DAGOperand f16ty> { 107 list<Predicate> Predicates = predicates; 108 string Suffix = suffix; 109 string Space = space; 110 DAGOperand PrimaryTy = primaryty; 111 DAGOperand F16Ty = f16ty; 112 DAGOperand F32Ty = f32ty; 113 DAGOperand F64Ty = f64ty; 114 ValueType PrimaryVT = primaryvt; 115} 116 117def FExt : ExtInfo<"", "", [HasStdExtF], f32, FPR32, FPR32, ?, ?>; 118 119def ZfinxExt : ExtInfo<"_INX", "RVZfinx", [HasStdExtZfinx], f32, FPR32INX, FPR32INX, ?, ?>; 120 121defvar FExts = [FExt, ZfinxExt]; 122 123// Floating-point rounding mode 124 125def FRMArg : AsmOperandClass { 126 let Name = "FRMArg"; 127 let RenderMethod = "addFRMArgOperands"; 128 let ParserMethod = "parseFRMArg"; 129 let IsOptional = 1; 130 let DefaultMethod = "defaultFRMArgOp"; 131} 132 133def frmarg : Operand<XLenVT> { 134 let ParserMatchClass = FRMArg; 135 let PrintMethod = "printFRMArg"; 136 let DecoderMethod = "decodeFRMArg"; 137 let OperandType = "OPERAND_FRMARG"; 138 let OperandNamespace = "RISCVOp"; 139} 140 141// Variants of the rounding mode operand that default to 'rne'. This is used 142// for historical/legacy reasons. fcvt functions where the rounding mode 143// doesn't affect the output originally always set it to 0b000 ('rne'). As old 144// versions of LLVM and GCC will fail to decode versions of these instructions 145// with the rounding mode set to something other than 'rne', we retain this 146// default. 147def FRMArgLegacy : AsmOperandClass { 148 let Name = "FRMArgLegacy"; 149 let RenderMethod = "addFRMArgOperands"; 150 let ParserMethod = "parseFRMArg"; 151 let IsOptional = 1; 152 let DefaultMethod = "defaultFRMArgLegacyOp"; 153} 154 155def frmarglegacy : Operand<XLenVT> { 156 let ParserMatchClass = FRMArgLegacy; 157 let PrintMethod = "printFRMArgLegacy"; 158 let DecoderMethod = "decodeFRMArg"; 159 let OperandType = "OPERAND_FRMARG"; 160 let OperandNamespace = "RISCVOp"; 161} 162 163//===----------------------------------------------------------------------===// 164// Instruction class templates 165//===----------------------------------------------------------------------===// 166 167let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in 168class FPLoad_r<bits<3> funct3, string opcodestr, DAGOperand rty, 169 SchedWrite sw> 170 : RVInstI<funct3, OPC_LOAD_FP, (outs rty:$rd), 171 (ins GPRMem:$rs1, simm12:$imm12), 172 opcodestr, "$rd, ${imm12}(${rs1})">, 173 Sched<[sw, ReadFMemBase]>; 174 175let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in 176class FPStore_r<bits<3> funct3, string opcodestr, DAGOperand rty, 177 SchedWrite sw> 178 : RVInstS<funct3, OPC_STORE_FP, (outs), 179 (ins rty:$rs2, GPRMem:$rs1, simm12:$imm12), 180 opcodestr, "$rs2, ${imm12}(${rs1})">, 181 Sched<[sw, ReadFStoreData, ReadFMemBase]>; 182 183let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 184 UseNamedOperandTable = 1, hasPostISelHook = 1, isCommutable = 1 in 185class FPFMA_rrr_frm<RISCVOpcode opcode, bits<2> funct2, string opcodestr, 186 DAGOperand rty> 187 : RVInstR4Frm<funct2, opcode, (outs rty:$rd), 188 (ins rty:$rs1, rty:$rs2, rty:$rs3, frmarg:$frm), 189 opcodestr, "$rd, $rs1, $rs2, $rs3$frm">; 190 191multiclass FPFMA_rrr_frm_m<RISCVOpcode opcode, bits<2> funct2, 192 string opcodestr, ExtInfo Ext> { 193 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 194 def Ext.Suffix : FPFMA_rrr_frm<opcode, funct2, opcodestr, Ext.PrimaryTy>; 195} 196 197let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in 198class FPALU_rr<bits<7> funct7, bits<3> funct3, string opcodestr, 199 DAGOperand rty, bit Commutable> 200 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rty:$rd), 201 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2"> { 202 let isCommutable = Commutable; 203} 204multiclass FPALU_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr, 205 ExtInfo Ext, bit Commutable = 0> { 206 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 207 def Ext.Suffix : FPALU_rr<funct7, funct3, opcodestr, Ext.PrimaryTy, Commutable>; 208} 209 210let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 211 UseNamedOperandTable = 1, hasPostISelHook = 1 in 212class FPALU_rr_frm<bits<7> funct7, string opcodestr, DAGOperand rty, 213 bit Commutable> 214 : RVInstRFrm<funct7, OPC_OP_FP, (outs rty:$rd), 215 (ins rty:$rs1, rty:$rs2, frmarg:$frm), opcodestr, 216 "$rd, $rs1, $rs2$frm"> { 217 let isCommutable = Commutable; 218} 219multiclass FPALU_rr_frm_m<bits<7> funct7, string opcodestr, 220 ExtInfo Ext, bit Commutable = 0> { 221 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 222 def Ext.Suffix : FPALU_rr_frm<funct7, opcodestr, Ext.PrimaryTy, Commutable>; 223} 224 225let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in 226class FPUnaryOp_r<bits<7> funct7, bits<5> rs2val, bits<3> funct3, 227 DAGOperand rdty, DAGOperand rs1ty, string opcodestr> 228 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd), (ins rs1ty:$rs1), 229 opcodestr, "$rd, $rs1"> { 230 let rs2 = rs2val; 231} 232multiclass FPUnaryOp_r_m<bits<7> funct7, bits<5> rs2val, bits<3> funct3, 233 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty, 234 string opcodestr> { 235 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 236 def Ext.Suffix : FPUnaryOp_r<funct7, rs2val, funct3, rdty, rs1ty, opcodestr>; 237} 238 239let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 240 UseNamedOperandTable = 1, hasPostISelHook = 1 in 241class FPUnaryOp_r_frm<bits<7> funct7, bits<5> rs2val, DAGOperand rdty, 242 DAGOperand rs1ty, string opcodestr> 243 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd), 244 (ins rs1ty:$rs1, frmarg:$frm), opcodestr, 245 "$rd, $rs1$frm"> { 246 let rs2 = rs2val; 247} 248multiclass FPUnaryOp_r_frm_m<bits<7> funct7, bits<5> rs2val, 249 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty, 250 string opcodestr, list<Predicate> ExtraPreds = []> { 251 let Predicates = !listconcat(Ext.Predicates, ExtraPreds), 252 DecoderNamespace = Ext.Space in 253 def Ext.Suffix : FPUnaryOp_r_frm<funct7, rs2val, rdty, rs1ty, 254 opcodestr>; 255} 256 257let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 258 UseNamedOperandTable = 1, hasPostISelHook = 1 in 259class FPUnaryOp_r_frmlegacy<bits<7> funct7, bits<5> rs2val, DAGOperand rdty, 260 DAGOperand rs1ty, string opcodestr> 261 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd), 262 (ins rs1ty:$rs1, frmarglegacy:$frm), opcodestr, 263 "$rd, $rs1$frm"> { 264 let rs2 = rs2val; 265} 266multiclass FPUnaryOp_r_frmlegacy_m<bits<7> funct7, bits<5> rs2val, 267 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty, 268 string opcodestr, list<Predicate> ExtraPreds = []> { 269 let Predicates = !listconcat(Ext.Predicates, ExtraPreds), 270 DecoderNamespace = Ext.Space in 271 def Ext.Suffix : FPUnaryOp_r_frmlegacy<funct7, rs2val, rdty, rs1ty, 272 opcodestr>; 273} 274 275let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1, 276 IsSignExtendingOpW = 1 in 277class FPCmp_rr<bits<7> funct7, bits<3> funct3, string opcodestr, 278 DAGOperand rty, bit Commutable = 0> 279 : RVInstR<funct7, funct3, OPC_OP_FP, (outs GPR:$rd), 280 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2"> { 281 let isCommutable = Commutable; 282} 283multiclass FPCmp_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr, 284 ExtInfo Ext, bit Commutable = 0> { 285 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in 286 def Ext.Suffix : FPCmp_rr<funct7, funct3, opcodestr, Ext.PrimaryTy, Commutable>; 287} 288 289class PseudoFROUND<DAGOperand Ty, ValueType vt> 290 : Pseudo<(outs Ty:$rd), (ins Ty:$rs1, Ty:$rs2, ixlenimm:$rm), 291 [(set Ty:$rd, (vt (riscv_fround Ty:$rs1, Ty:$rs2, timm:$rm)))]> { 292 let hasSideEffects = 0; 293 let mayLoad = 0; 294 let mayStore = 0; 295 let usesCustomInserter = 1; 296 let mayRaiseFPException = 1; 297} 298 299//===----------------------------------------------------------------------===// 300// Instructions 301//===----------------------------------------------------------------------===// 302 303let Predicates = [HasStdExtF] in { 304def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>; 305 306// Operands for stores are in the order srcreg, base, offset rather than 307// reflecting the order these fields are specified in the instruction 308// encoding. 309def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>; 310} // Predicates = [HasStdExtF] 311 312let Predicates = [HasStdExtZfinx], isCodeGenOnly = 1 in { 313def LW_INX : Load_ri<0b010, "lw", GPRF32>, Sched<[WriteLDW, ReadMemBase]>; 314def SW_INX : Store_rri<0b010, "sw", GPRF32>, 315 Sched<[WriteSTW, ReadStoreData, ReadMemBase]>; 316 317// ADDI with GPRF32 register class to use for copy. This should not be used as 318// general ADDI, so the immediate should always be zero. 319let isReMaterializable = 1, isAsCheapAsAMove = 1, isMoveReg = 1, 320 hasSideEffects = 0, mayLoad = 0, mayStore = 0 in 321def PseudoMV_FPR32INX : Pseudo<(outs GPRF32:$rd), (ins GPRF32:$rs), []>, 322 Sched<[WriteIALU, ReadIALU]>; 323} 324 325foreach Ext = FExts in { 326 let SchedRW = [WriteFMA32, ReadFMA32, ReadFMA32, ReadFMA32Addend] in { 327 defm FMADD_S : FPFMA_rrr_frm_m<OPC_MADD, 0b00, "fmadd.s", Ext>; 328 defm FMSUB_S : FPFMA_rrr_frm_m<OPC_MSUB, 0b00, "fmsub.s", Ext>; 329 defm FNMSUB_S : FPFMA_rrr_frm_m<OPC_NMSUB, 0b00, "fnmsub.s", Ext>; 330 defm FNMADD_S : FPFMA_rrr_frm_m<OPC_NMADD, 0b00, "fnmadd.s", Ext>; 331 } 332 333 let SchedRW = [WriteFAdd32, ReadFAdd32, ReadFAdd32] in { 334 defm FADD_S : FPALU_rr_frm_m<0b0000000, "fadd.s", Ext, Commutable=1>; 335 defm FSUB_S : FPALU_rr_frm_m<0b0000100, "fsub.s", Ext>; 336 } 337 338 let SchedRW = [WriteFMul32, ReadFMul32, ReadFMul32] in 339 defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", Ext, Commutable=1>; 340 341 let SchedRW = [WriteFDiv32, ReadFDiv32, ReadFDiv32] in 342 defm FDIV_S : FPALU_rr_frm_m<0b0001100, "fdiv.s", Ext>; 343 344 defm FSQRT_S : FPUnaryOp_r_frm_m<0b0101100, 0b00000, Ext, Ext.PrimaryTy, 345 Ext.PrimaryTy, "fsqrt.s">, 346 Sched<[WriteFSqrt32, ReadFSqrt32]>; 347 348 let SchedRW = [WriteFSGNJ32, ReadFSGNJ32, ReadFSGNJ32], 349 mayRaiseFPException = 0 in { 350 defm FSGNJ_S : FPALU_rr_m<0b0010000, 0b000, "fsgnj.s", Ext>; 351 defm FSGNJN_S : FPALU_rr_m<0b0010000, 0b001, "fsgnjn.s", Ext>; 352 defm FSGNJX_S : FPALU_rr_m<0b0010000, 0b010, "fsgnjx.s", Ext>; 353 } 354 355 let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in { 356 defm FMIN_S : FPALU_rr_m<0b0010100, 0b000, "fmin.s", Ext, Commutable=1>; 357 defm FMAX_S : FPALU_rr_m<0b0010100, 0b001, "fmax.s", Ext, Commutable=1>; 358 } 359 360 let IsSignExtendingOpW = 1 in 361 defm FCVT_W_S : FPUnaryOp_r_frm_m<0b1100000, 0b00000, Ext, GPR, Ext.PrimaryTy, 362 "fcvt.w.s">, 363 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>; 364 365 let IsSignExtendingOpW = 1 in 366 defm FCVT_WU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00001, Ext, GPR, Ext.PrimaryTy, 367 "fcvt.wu.s">, 368 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>; 369 370 let SchedRW = [WriteFCmp32, ReadFCmp32, ReadFCmp32] in { 371 defm FEQ_S : FPCmp_rr_m<0b1010000, 0b010, "feq.s", Ext, Commutable=1>; 372 defm FLT_S : FPCmp_rr_m<0b1010000, 0b001, "flt.s", Ext>; 373 defm FLE_S : FPCmp_rr_m<0b1010000, 0b000, "fle.s", Ext>; 374 } 375 376 let mayRaiseFPException = 0 in 377 defm FCLASS_S : FPUnaryOp_r_m<0b1110000, 0b00000, 0b001, Ext, GPR, Ext.PrimaryTy, 378 "fclass.s">, 379 Sched<[WriteFClass32, ReadFClass32]>; 380 381 defm FCVT_S_W : FPUnaryOp_r_frm_m<0b1101000, 0b00000, Ext, Ext.PrimaryTy, GPR, 382 "fcvt.s.w">, 383 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>; 384 385 defm FCVT_S_WU : FPUnaryOp_r_frm_m<0b1101000, 0b00001, Ext, Ext.PrimaryTy, GPR, 386 "fcvt.s.wu">, 387 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>; 388 389 defm FCVT_L_S : FPUnaryOp_r_frm_m<0b1100000, 0b00010, Ext, GPR, Ext.PrimaryTy, 390 "fcvt.l.s", [IsRV64]>, 391 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>; 392 393 defm FCVT_LU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00011, Ext, GPR, Ext.PrimaryTy, 394 "fcvt.lu.s", [IsRV64]>, 395 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>; 396 397 defm FCVT_S_L : FPUnaryOp_r_frm_m<0b1101000, 0b00010, Ext, Ext.PrimaryTy, GPR, 398 "fcvt.s.l", [IsRV64]>, 399 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>; 400 401 defm FCVT_S_LU : FPUnaryOp_r_frm_m<0b1101000, 0b00011, Ext, Ext.PrimaryTy, GPR, 402 "fcvt.s.lu", [IsRV64]>, 403 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>; 404} // foreach Ext = FExts 405 406let Predicates = [HasStdExtF], mayRaiseFPException = 0, 407 IsSignExtendingOpW = 1 in 408def FMV_X_W : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR32, "fmv.x.w">, 409 Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>; 410 411let Predicates = [HasStdExtF], mayRaiseFPException = 0 in 412def FMV_W_X : FPUnaryOp_r<0b1111000, 0b00000, 0b000, FPR32, GPR, "fmv.w.x">, 413 Sched<[WriteFMovI32ToF32, ReadFMovI32ToF32]>; 414 415//===----------------------------------------------------------------------===// 416// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20) 417//===----------------------------------------------------------------------===// 418 419let Predicates = [HasStdExtFOrZfinx] in { 420// The following csr instructions actually alias instructions from the base ISA. 421// However, it only makes sense to support them when the F or Zfinx extension is 422// enabled. 423// NOTE: "frcsr", "frrm", and "frflags" are more specialized version of "csrr". 424def : InstAlias<"frcsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 2>; 425def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs)>; 426def : InstAlias<"fscsr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 2>; 427 428// frsr, fssr are obsolete aliases replaced by frcsr, fscsr, so give them 429// zero weight. 430def : InstAlias<"frsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 0>; 431def : InstAlias<"fssr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs), 0>; 432def : InstAlias<"fssr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 0>; 433 434def : InstAlias<"frrm $rd", (CSRRS GPR:$rd, SysRegFRM.Encoding, X0), 2>; 435def : InstAlias<"fsrm $rd, $rs", (CSRRW GPR:$rd, SysRegFRM.Encoding, GPR:$rs)>; 436def : InstAlias<"fsrm $rs", (CSRRW X0, SysRegFRM.Encoding, GPR:$rs), 2>; 437def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, SysRegFRM.Encoding, uimm5:$imm)>; 438def : InstAlias<"fsrmi $imm", (CSRRWI X0, SysRegFRM.Encoding, uimm5:$imm), 2>; 439 440def : InstAlias<"frflags $rd", (CSRRS GPR:$rd, SysRegFFLAGS.Encoding, X0), 2>; 441def : InstAlias<"fsflags $rd, $rs", (CSRRW GPR:$rd, SysRegFFLAGS.Encoding, GPR:$rs)>; 442def : InstAlias<"fsflags $rs", (CSRRW X0, SysRegFFLAGS.Encoding, GPR:$rs), 2>; 443def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, SysRegFFLAGS.Encoding, uimm5:$imm)>; 444def : InstAlias<"fsflagsi $imm", (CSRRWI X0, SysRegFFLAGS.Encoding, uimm5:$imm), 2>; 445} // Predicates = [HasStdExtFOrZfinx] 446 447let Predicates = [HasStdExtF] in { 448def : InstAlias<"flw $rd, (${rs1})", (FLW FPR32:$rd, GPR:$rs1, 0), 0>; 449def : InstAlias<"fsw $rs2, (${rs1})", (FSW FPR32:$rs2, GPR:$rs1, 0), 0>; 450 451def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; 452def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; 453def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>; 454 455// fgt.s/fge.s are recognised by the GNU assembler but the canonical 456// flt.s/fle.s forms will always be printed. Therefore, set a zero weight. 457def : InstAlias<"fgt.s $rd, $rs, $rt", 458 (FLT_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>; 459def : InstAlias<"fge.s $rd, $rs, $rt", 460 (FLE_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>; 461 462// fmv.w.x and fmv.x.w were previously known as fmv.s.x and fmv.x.s. Both 463// spellings should be supported by standard tools. 464def : MnemonicAlias<"fmv.s.x", "fmv.w.x">; 465def : MnemonicAlias<"fmv.x.s", "fmv.x.w">; 466 467def PseudoFLW : PseudoFloatLoad<"flw", FPR32>; 468def PseudoFSW : PseudoStore<"fsw", FPR32>; 469let usesCustomInserter = 1 in { 470def PseudoQuietFLE_S : PseudoQuietFCMP<FPR32>; 471def PseudoQuietFLT_S : PseudoQuietFCMP<FPR32>; 472} 473} // Predicates = [HasStdExtF] 474 475let Predicates = [HasStdExtZfinx] in { 476def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>; 477def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>; 478def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>; 479 480def : InstAlias<"fgt.s $rd, $rs, $rt", 481 (FLT_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>; 482def : InstAlias<"fge.s $rd, $rs, $rt", 483 (FLE_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>; 484let usesCustomInserter = 1 in { 485def PseudoQuietFLE_S_INX : PseudoQuietFCMP<FPR32INX>; 486def PseudoQuietFLT_S_INX : PseudoQuietFCMP<FPR32INX>; 487} 488} // Predicates = [HasStdExtZfinx] 489 490//===----------------------------------------------------------------------===// 491// Pseudo-instructions and codegen patterns 492//===----------------------------------------------------------------------===// 493 494defvar FRM_RNE = 0b000; 495defvar FRM_RTZ = 0b001; 496defvar FRM_RDN = 0b010; 497defvar FRM_RUP = 0b011; 498defvar FRM_RMM = 0b100; 499defvar FRM_DYN = 0b111; 500 501/// Floating point constants 502def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>; 503 504/// Generic pattern classes 505class PatSetCC<DAGOperand Ty, SDPatternOperator OpNode, CondCode Cond, 506 RVInst Inst, ValueType vt> 507 : Pat<(XLenVT (OpNode (vt Ty:$rs1), Ty:$rs2, Cond)), (Inst $rs1, $rs2)>; 508multiclass PatSetCC_m<SDPatternOperator OpNode, CondCode Cond, 509 RVInst Inst, ExtInfo Ext> { 510 let Predicates = Ext.Predicates in 511 def Ext.Suffix : PatSetCC<Ext.PrimaryTy, OpNode, Cond, 512 !cast<RVInst>(Inst#Ext.Suffix), Ext.PrimaryVT>; 513} 514 515class PatFprFpr<SDPatternOperator OpNode, RVInstR Inst, 516 DAGOperand RegTy, ValueType vt> 517 : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2)>; 518multiclass PatFprFpr_m<SDPatternOperator OpNode, RVInstR Inst, 519 ExtInfo Ext> { 520 let Predicates = Ext.Predicates in 521 def Ext.Suffix : PatFprFpr<OpNode, !cast<RVInstR>(Inst#Ext.Suffix), 522 Ext.PrimaryTy, Ext.PrimaryVT>; 523} 524 525class PatFprFprDynFrm<SDPatternOperator OpNode, RVInstRFrm Inst, 526 DAGOperand RegTy, ValueType vt> 527 : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2, FRM_DYN)>; 528multiclass PatFprFprDynFrm_m<SDPatternOperator OpNode, RVInstRFrm Inst, 529 ExtInfo Ext> { 530 let Predicates = Ext.Predicates in 531 def Ext.Suffix : PatFprFprDynFrm<OpNode, 532 !cast<RVInstRFrm>(Inst#Ext.Suffix), 533 Ext.PrimaryTy, Ext.PrimaryVT>; 534} 535 536/// Float conversion operations 537 538// [u]int32<->float conversion patterns must be gated on IsRV32 or IsRV64, so 539// are defined later. 540 541/// Float arithmetic operations 542foreach Ext = FExts in { 543 defm : PatFprFprDynFrm_m<any_fadd, FADD_S, Ext>; 544 defm : PatFprFprDynFrm_m<any_fsub, FSUB_S, Ext>; 545 defm : PatFprFprDynFrm_m<any_fmul, FMUL_S, Ext>; 546 defm : PatFprFprDynFrm_m<any_fdiv, FDIV_S, Ext>; 547} 548 549let Predicates = [HasStdExtF] in { 550def : Pat<(any_fsqrt FPR32:$rs1), (FSQRT_S FPR32:$rs1, FRM_DYN)>; 551 552def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>; 553def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>; 554 555def : Pat<(riscv_fclass FPR32:$rs1), (FCLASS_S $rs1)>; 556} // Predicates = [HasStdExtF] 557 558let Predicates = [HasStdExtZfinx] in { 559def : Pat<(any_fsqrt FPR32INX:$rs1), (FSQRT_S_INX FPR32INX:$rs1, FRM_DYN)>; 560 561def : Pat<(fneg FPR32INX:$rs1), (FSGNJN_S_INX $rs1, $rs1)>; 562def : Pat<(fabs FPR32INX:$rs1), (FSGNJX_S_INX $rs1, $rs1)>; 563 564def : Pat<(riscv_fclass FPR32INX:$rs1), (FCLASS_S_INX $rs1)>; 565} // Predicates = [HasStdExtZfinx] 566 567foreach Ext = FExts in { 568defm : PatFprFpr_m<fcopysign, FSGNJ_S, Ext>; 569defm : PatFprFpr_m<riscv_fsgnjx, FSGNJX_S, Ext>; 570} 571 572let Predicates = [HasStdExtF] in { 573def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), 574 (FSGNJN_S FPR32:$rs1, FPR32:$rs2)>; 575 576// fmadd: rs1 * rs2 + rs3 577def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3), 578 (FMADD_S $rs1, $rs2, $rs3, FRM_DYN)>; 579 580// fmsub: rs1 * rs2 - rs3 581def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)), 582 (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>; 583 584// fnmsub: -rs1 * rs2 + rs3 585def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, FPR32:$rs3), 586 (FNMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>; 587 588// fnmadd: -rs1 * rs2 - rs3 589def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)), 590 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>; 591 592// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA) 593def : Pat<(fneg (any_fma_nsz FPR32:$rs1, FPR32:$rs2, FPR32:$rs3)), 594 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>; 595} // Predicates = [HasStdExtF] 596 597let Predicates = [HasStdExtZfinx] in { 598def : Pat<(fcopysign FPR32INX:$rs1, (fneg FPR32INX:$rs2)), 599 (FSGNJN_S_INX FPR32INX:$rs1, FPR32INX:$rs2)>; 600 601// fmadd: rs1 * rs2 + rs3 602def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3), 603 (FMADD_S_INX $rs1, $rs2, $rs3, FRM_DYN)>; 604 605// fmsub: rs1 * rs2 - rs3 606def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, (fneg FPR32INX:$rs3)), 607 (FMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>; 608 609// fnmsub: -rs1 * rs2 + rs3 610def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, FPR32INX:$rs3), 611 (FNMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>; 612 613// fnmadd: -rs1 * rs2 - rs3 614def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, (fneg FPR32INX:$rs3)), 615 (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>; 616 617// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA) 618def : Pat<(fneg (any_fma_nsz FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3)), 619 (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>; 620} // Predicates = [HasStdExtZfinx] 621 622// The ratified 20191213 ISA spec defines fmin and fmax in a way that matches 623// LLVM's fminnum and fmaxnum 624// <https://github.com/riscv/riscv-isa-manual/commit/cd20cee7efd9bac7c5aa127ec3b451749d2b3cce>. 625foreach Ext = FExts in { 626 defm : PatFprFpr_m<fminnum, FMIN_S, Ext>; 627 defm : PatFprFpr_m<fmaxnum, FMAX_S, Ext>; 628 defm : PatFprFpr_m<fminimumnum, FMIN_S, Ext>; 629 defm : PatFprFpr_m<fmaximumnum, FMAX_S, Ext>; 630 defm : PatFprFpr_m<riscv_fmin, FMIN_S, Ext>; 631 defm : PatFprFpr_m<riscv_fmax, FMAX_S, Ext>; 632 def : Pat<(f32 (fcanonicalize FPR32:$rs1)), (FMIN_S $rs1, $rs1)>; 633} 634 635/// Setcc 636// FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for 637// strict versions of those. 638 639// Match non-signaling FEQ_S 640foreach Ext = FExts in { 641 defm : PatSetCC_m<any_fsetcc, SETEQ, FEQ_S, Ext>; 642 defm : PatSetCC_m<any_fsetcc, SETOEQ, FEQ_S, Ext>; 643 defm : PatSetCC_m<strict_fsetcc, SETLT, PseudoQuietFLT_S, Ext>; 644 defm : PatSetCC_m<strict_fsetcc, SETOLT, PseudoQuietFLT_S, Ext>; 645 defm : PatSetCC_m<strict_fsetcc, SETLE, PseudoQuietFLE_S, Ext>; 646 defm : PatSetCC_m<strict_fsetcc, SETOLE, PseudoQuietFLE_S, Ext>; 647} 648 649let Predicates = [HasStdExtF] in { 650// Match signaling FEQ_S 651def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETEQ)), 652 (AND (XLenVT (FLE_S $rs1, $rs2)), 653 (XLenVT (FLE_S $rs2, $rs1)))>; 654def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETOEQ)), 655 (AND (XLenVT (FLE_S $rs1, $rs2)), 656 (XLenVT (FLE_S $rs2, $rs1)))>; 657// If both operands are the same, use a single FLE. 658def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETEQ)), 659 (FLE_S $rs1, $rs1)>; 660def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETOEQ)), 661 (FLE_S $rs1, $rs1)>; 662} // Predicates = [HasStdExtF] 663 664let Predicates = [HasStdExtZfinx] in { 665// Match signaling FEQ_S 666def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETEQ)), 667 (AND (XLenVT (FLE_S_INX $rs1, $rs2)), 668 (XLenVT (FLE_S_INX $rs2, $rs1)))>; 669def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETOEQ)), 670 (AND (XLenVT (FLE_S_INX $rs1, $rs2)), 671 (XLenVT (FLE_S_INX $rs2, $rs1)))>; 672// If both operands are the same, use a single FLE. 673def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETEQ)), 674 (FLE_S_INX $rs1, $rs1)>; 675def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETOEQ)), 676 (FLE_S_INX $rs1, $rs1)>; 677} // Predicates = [HasStdExtZfinx] 678 679foreach Ext = FExts in { 680 defm : PatSetCC_m<any_fsetccs, SETLT, FLT_S, Ext>; 681 defm : PatSetCC_m<any_fsetccs, SETOLT, FLT_S, Ext>; 682 defm : PatSetCC_m<any_fsetccs, SETLE, FLE_S, Ext>; 683 defm : PatSetCC_m<any_fsetccs, SETOLE, FLE_S, Ext>; 684} 685 686let Predicates = [HasStdExtF] in { 687defm Select_FPR32 : SelectCC_GPR_rrirr<FPR32, f32>; 688 689def PseudoFROUND_S : PseudoFROUND<FPR32, f32>; 690 691/// Loads 692 693def : LdPat<load, FLW, f32>; 694 695/// Stores 696 697def : StPat<store, FSW, FPR32, f32>; 698 699} // Predicates = [HasStdExtF] 700 701let Predicates = [HasStdExtZfinx] in { 702defm Select_FPR32INX : SelectCC_GPR_rrirr<FPR32INX, f32>; 703 704def PseudoFROUND_S_INX : PseudoFROUND<FPR32INX, f32>; 705 706/// Loads 707def : LdPat<load, LW_INX, f32>; 708 709/// Stores 710def : StPat<store, SW_INX, GPRF32, f32>; 711} // Predicates = [HasStdExtZfinx] 712 713let Predicates = [HasStdExtF, IsRV32] in { 714// Moves (no conversion) 715def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>; 716def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>; 717} // Predicates = [HasStdExtF] 718 719let Predicates = [HasStdExtZfinx, IsRV32] in { 720// Moves (no conversion) 721def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (EXTRACT_SUBREG GPR:$rs1, sub_32)>; 722def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR32INX:$rs1, sub_32)>; 723} // Predicates = [HasStdExtZfinx] 724 725let Predicates = [HasStdExtF, IsRV32] in { 726// float->[u]int. Round-to-zero must be used. 727def : Pat<(i32 (any_fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RTZ)>; 728def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, FRM_RTZ)>; 729 730// Saturating float->[u]int32. 731def : Pat<(i32 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_W_S $rs1, timm:$frm)>; 732def : Pat<(i32 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_WU_S $rs1, timm:$frm)>; 733 734// float->int32 with current rounding mode. 735def : Pat<(i32 (any_lrint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_DYN)>; 736 737// float->int32 rounded to nearest with ties rounded away from zero. 738def : Pat<(i32 (any_lround FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RMM)>; 739 740// [u]int->float. Match GCC and default to using dynamic rounding mode. 741def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W $rs1, FRM_DYN)>; 742def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU $rs1, FRM_DYN)>; 743} // Predicates = [HasStdExtF, IsRV32] 744 745let Predicates = [HasStdExtZfinx, IsRV32] in { 746// float->[u]int. Round-to-zero must be used. 747def : Pat<(i32 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RTZ)>; 748def : Pat<(i32 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_WU_S_INX $rs1, FRM_RTZ)>; 749 750// Saturating float->[u]int32. 751def : Pat<(i32 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_W_S_INX $rs1, timm:$frm)>; 752def : Pat<(i32 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_WU_S_INX $rs1, timm:$frm)>; 753 754// float->int32 with current rounding mode. 755def : Pat<(i32 (any_lrint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_DYN)>; 756 757// float->int32 rounded to nearest with ties rounded away from zero. 758def : Pat<(i32 (any_lround FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RMM)>; 759 760// [u]int->float. Match GCC and default to using dynamic rounding mode. 761def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W_INX $rs1, FRM_DYN)>; 762def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU_INX $rs1, FRM_DYN)>; 763} // Predicates = [HasStdExtZfinx, IsRV32] 764 765let Predicates = [HasStdExtF, IsRV64] in { 766// Moves (no conversion) 767def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>; 768def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>; 769 770// Use target specific isd nodes to help us remember the result is sign 771// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be 772// duplicated if it has another user that didn't need the sign_extend. 773def : Pat<(riscv_any_fcvt_w_rv64 FPR32:$rs1, timm:$frm), (FCVT_W_S $rs1, timm:$frm)>; 774def : Pat<(riscv_any_fcvt_wu_rv64 FPR32:$rs1, timm:$frm), (FCVT_WU_S $rs1, timm:$frm)>; 775 776// float->[u]int64. Round-to-zero must be used. 777def : Pat<(i64 (any_fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RTZ)>; 778def : Pat<(i64 (any_fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, FRM_RTZ)>; 779 780// Saturating float->[u]int64. 781def : Pat<(i64 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_L_S $rs1, timm:$frm)>; 782def : Pat<(i64 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_LU_S $rs1, timm:$frm)>; 783 784// float->int64 with current rounding mode. 785def : Pat<(i64 (any_lrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>; 786def : Pat<(i64 (any_llrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>; 787 788// float->int64 rounded to neartest with ties rounded away from zero. 789def : Pat<(i64 (any_lround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>; 790def : Pat<(i64 (any_llround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>; 791 792// [u]int->fp. Match GCC and default to using dynamic rounding mode. 793def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W $rs1, FRM_DYN)>; 794def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU $rs1, FRM_DYN)>; 795def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L $rs1, FRM_DYN)>; 796def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU $rs1, FRM_DYN)>; 797} // Predicates = [HasStdExtF, IsRV64] 798 799let Predicates = [HasStdExtZfinx, IsRV64] in { 800// Moves (no conversion) 801def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (EXTRACT_SUBREG GPR:$src, sub_32)>; 802def : Pat<(riscv_fmv_x_anyextw_rv64 GPRF32:$src), (INSERT_SUBREG (XLenVT (IMPLICIT_DEF)), FPR32INX:$src, sub_32)>; 803 804// Use target specific isd nodes to help us remember the result is sign 805// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be 806// duplicated if it has another user that didn't need the sign_extend. 807def : Pat<(riscv_any_fcvt_w_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_W_S_INX $rs1, timm:$frm)>; 808def : Pat<(riscv_any_fcvt_wu_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_WU_S_INX $rs1, timm:$frm)>; 809 810// float->[u]int64. Round-to-zero must be used. 811def : Pat<(i64 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RTZ)>; 812def : Pat<(i64 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_LU_S_INX $rs1, FRM_RTZ)>; 813 814// Saturating float->[u]int64. 815def : Pat<(i64 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_L_S_INX $rs1, timm:$frm)>; 816def : Pat<(i64 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_LU_S_INX $rs1, timm:$frm)>; 817 818// float->int64 with current rounding mode. 819def : Pat<(i64 (any_lrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>; 820def : Pat<(i64 (any_llrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>; 821 822// float->int64 rounded to neartest with ties rounded away from zero. 823def : Pat<(i64 (any_lround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RMM)>; 824def : Pat<(i64 (any_llround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RMM)>; 825 826// [u]int->fp. Match GCC and default to using dynamic rounding mode. 827def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W_INX $rs1, FRM_DYN)>; 828def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU_INX $rs1, FRM_DYN)>; 829def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L_INX $rs1, FRM_DYN)>; 830def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU_INX $rs1, FRM_DYN)>; 831} // Predicates = [HasStdExtZfinx, IsRV64] 832