1 //===-- RISCVInstrInfoF.td - RISC-V 'F' instructions -------*- tablegen -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file describes the RISC-V instructions from the standard 'F',
10 // Single-Precision Floating-Point instruction set extension.
12 //===----------------------------------------------------------------------===//
14 //===----------------------------------------------------------------------===//
15 // RISC-V specific DAG Nodes.
16 //===----------------------------------------------------------------------===//
18 def SDT_RISCVFMV_W_X_RV64
19 : SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisVT<1, i64>]>;
20 def SDT_RISCVFMV_X_ANYEXTW_RV64
21 : SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, f32>]>;
22 def SDT_RISCVFCVT_W_RV64
23 : SDTypeProfile<1, 2, [SDTCisVT<0, i64>, SDTCisFP<1>,
26 : SDTypeProfile<1, 2, [SDTCisVT<0, XLenVT>, SDTCisFP<1>,
27 SDTCisVT<2, XLenVT>]>;
30 : SDTypeProfile<1, 3, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
31 SDTCisVT<3, XLenVT>]>;
33 : SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisFP<1>]>;
36 : SDNode<"RISCVISD::FCLASS", SDT_RISCVFCLASS>;
39 : SDNode<"RISCVISD::FROUND", SDT_RISCVFROUND>;
41 def riscv_fmv_w_x_rv64
42 : SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>;
43 def riscv_fmv_x_anyextw_rv64
44 : SDNode<"RISCVISD::FMV_X_ANYEXTW_RV64", SDT_RISCVFMV_X_ANYEXTW_RV64>;
46 : SDNode<"RISCVISD::FCVT_W_RV64", SDT_RISCVFCVT_W_RV64>;
47 def riscv_fcvt_wu_rv64
48 : SDNode<"RISCVISD::FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64>;
50 : SDNode<"RISCVISD::FCVT_X", SDT_RISCVFCVT_X>;
52 : SDNode<"RISCVISD::FCVT_XU", SDT_RISCVFCVT_X>;
54 def riscv_fmin : SDNode<"RISCVISD::FMIN", SDTFPBinOp>;
55 def riscv_fmax : SDNode<"RISCVISD::FMAX", SDTFPBinOp>;
57 def riscv_strict_fcvt_w_rv64
58 : SDNode<"RISCVISD::STRICT_FCVT_W_RV64", SDT_RISCVFCVT_W_RV64,
60 def riscv_strict_fcvt_wu_rv64
61 : SDNode<"RISCVISD::STRICT_FCVT_WU_RV64", SDT_RISCVFCVT_W_RV64,
64 def riscv_any_fcvt_w_rv64 : PatFrags<(ops node:$src, node:$frm),
65 [(riscv_strict_fcvt_w_rv64 node:$src, node:$frm),
66 (riscv_fcvt_w_rv64 node:$src, node:$frm)]>;
67 def riscv_any_fcvt_wu_rv64 : PatFrags<(ops node:$src, node:$frm),
68 [(riscv_strict_fcvt_wu_rv64 node:$src, node:$frm),
69 (riscv_fcvt_wu_rv64 node:$src, node:$frm)]>;
71 def any_fma_nsz : PatFrag<(ops node:$rs1, node:$rs2, node:$rs3),
72 (any_fma node:$rs1, node:$rs2, node:$rs3), [{
73 return N->getFlags().hasNoSignedZeros();
75 //===----------------------------------------------------------------------===//
76 // Operand and SDNode transformation definitions.
77 //===----------------------------------------------------------------------===//
81 def GPRAsFPR : AsmOperandClass {
82 let Name = "GPRAsFPR";
83 let ParserMethod = "parseGPRAsFPR";
84 let RenderMethod = "addRegOperands";
87 def FPR32INX : RegisterOperand<GPRF32> {
88 let ParserMatchClass = GPRAsFPR;
89 let DecoderMethod = "DecodeGPRRegisterClass";
92 // Describes a combination of predicates from F/D/Zfh/Zfhmin or
93 // Zfinx/Zdinx/Zhinx/Zhinxmin that are applied to scalar FP instruction.
94 // Contains the DAGOperand for the primary type for the predicates. The primary
95 // type may be unset for combinations of predicates like Zfh+D.
96 // Also contains the DAGOperand for f16/f32/f64, instruction suffix, and
97 // decoder namespace that go with an instruction given those predicates.
99 // The DAGOperand can be unset if the predicates are not enough to define it.
100 class ExtInfo<string suffix, string space, list<Predicate> predicates,
101 ValueType primaryvt, DAGOperand primaryty, DAGOperand f32ty,
102 DAGOperand f64ty, DAGOperand f16ty> {
103 list<Predicate> Predicates = predicates;
104 string Suffix = suffix;
105 string Space = space;
106 DAGOperand PrimaryTy = primaryty;
107 DAGOperand F16Ty = f16ty;
108 DAGOperand F32Ty = f32ty;
109 DAGOperand F64Ty = f64ty;
110 ValueType PrimaryVT = primaryvt;
113 def FExt : ExtInfo<"", "", [HasStdExtF], f32, FPR32, FPR32, ?, ?>;
115 def ZfinxExt : ExtInfo<"_INX", "RVZfinx", [HasStdExtZfinx], f32, FPR32INX, FPR32INX, ?, ?>;
117 defvar FExts = [FExt, ZfinxExt];
119 // Floating-point rounding mode
121 def FRMArg : AsmOperandClass {
123 let RenderMethod = "addFRMArgOperands";
124 let ParserMethod = "parseFRMArg";
126 let DefaultMethod = "defaultFRMArgOp";
129 def frmarg : Operand<XLenVT> {
130 let ParserMatchClass = FRMArg;
131 let PrintMethod = "printFRMArg";
132 let DecoderMethod = "decodeFRMArg";
135 // Variants of the rounding mode operand that default to 'rne'. This is used
136 // for historical/legacy reasons. fcvt functions where the rounding mode
137 // doesn't affect the output originally always set it to 0b000 ('rne'). As old
138 // versions of LLVM and GCC will fail to decode versions of these instructions
139 // with the rounding mode set to something other than 'rne', we retain this
141 def FRMArgLegacy : AsmOperandClass {
142 let Name = "FRMArgLegacy";
143 let RenderMethod = "addFRMArgOperands";
144 let ParserMethod = "parseFRMArg";
146 let DefaultMethod = "defaultFRMArgLegacyOp";
149 def frmarglegacy : Operand<XLenVT> {
150 let ParserMatchClass = FRMArgLegacy;
151 let PrintMethod = "printFRMArgLegacy";
152 let DecoderMethod = "decodeFRMArg";
155 //===----------------------------------------------------------------------===//
156 // Instruction class templates
157 //===----------------------------------------------------------------------===//
159 let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
160 class FPLoad_r<bits<3> funct3, string opcodestr, DAGOperand rty,
162 : RVInstI<funct3, OPC_LOAD_FP, (outs rty:$rd),
163 (ins GPRMem:$rs1, simm12:$imm12),
164 opcodestr, "$rd, ${imm12}(${rs1})">,
165 Sched<[sw, ReadFMemBase]>;
167 let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
168 class FPStore_r<bits<3> funct3, string opcodestr, DAGOperand rty,
170 : RVInstS<funct3, OPC_STORE_FP, (outs),
171 (ins rty:$rs2, GPRMem:$rs1, simm12:$imm12),
172 opcodestr, "$rs2, ${imm12}(${rs1})">,
173 Sched<[sw, ReadFStoreData, ReadFMemBase]>;
175 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
176 UseNamedOperandTable = 1, hasPostISelHook = 1, isCommutable = 1 in
177 class FPFMA_rrr_frm<RISCVOpcode opcode, bits<2> funct2, string opcodestr,
179 : RVInstR4Frm<funct2, opcode, (outs rty:$rd),
180 (ins rty:$rs1, rty:$rs2, rty:$rs3, frmarg:$frm),
181 opcodestr, "$rd, $rs1, $rs2, $rs3$frm">;
183 multiclass FPFMA_rrr_frm_m<RISCVOpcode opcode, bits<2> funct2,
184 string opcodestr, ExtInfo Ext> {
185 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in
186 def Ext.Suffix : FPFMA_rrr_frm<opcode, funct2, opcodestr, Ext.PrimaryTy>;
189 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in
190 class FPALU_rr<bits<7> funct7, bits<3> funct3, string opcodestr,
191 DAGOperand rty, bit Commutable>
192 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rty:$rd),
193 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2"> {
194 let isCommutable = Commutable;
196 multiclass FPALU_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr,
197 ExtInfo Ext, bit Commutable = 0> {
198 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in
199 def Ext.Suffix : FPALU_rr<funct7, funct3, opcodestr, Ext.PrimaryTy, Commutable>;
202 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
203 UseNamedOperandTable = 1, hasPostISelHook = 1 in
204 class FPALU_rr_frm<bits<7> funct7, string opcodestr, DAGOperand rty,
206 : RVInstRFrm<funct7, OPC_OP_FP, (outs rty:$rd),
207 (ins rty:$rs1, rty:$rs2, frmarg:$frm), opcodestr,
208 "$rd, $rs1, $rs2$frm"> {
209 let isCommutable = Commutable;
211 multiclass FPALU_rr_frm_m<bits<7> funct7, string opcodestr,
212 ExtInfo Ext, bit Commutable = 0> {
213 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in
214 def Ext.Suffix : FPALU_rr_frm<funct7, opcodestr, Ext.PrimaryTy, Commutable>;
217 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in
218 class FPUnaryOp_r<bits<7> funct7, bits<5> rs2val, bits<3> funct3,
219 DAGOperand rdty, DAGOperand rs1ty, string opcodestr>
220 : RVInstR<funct7, funct3, OPC_OP_FP, (outs rdty:$rd), (ins rs1ty:$rs1),
221 opcodestr, "$rd, $rs1"> {
224 multiclass FPUnaryOp_r_m<bits<7> funct7, bits<5> rs2val, bits<3> funct3,
225 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,
227 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in
228 def Ext.Suffix : FPUnaryOp_r<funct7, rs2val, funct3, rdty, rs1ty, opcodestr>;
231 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
232 UseNamedOperandTable = 1, hasPostISelHook = 1 in
233 class FPUnaryOp_r_frm<bits<7> funct7, bits<5> rs2val, DAGOperand rdty,
234 DAGOperand rs1ty, string opcodestr>
235 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd),
236 (ins rs1ty:$rs1, frmarg:$frm), opcodestr,
240 multiclass FPUnaryOp_r_frm_m<bits<7> funct7, bits<5> rs2val,
241 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,
242 string opcodestr, list<Predicate> ExtraPreds = []> {
243 let Predicates = !listconcat(Ext.Predicates, ExtraPreds),
244 DecoderNamespace = Ext.Space in
245 def Ext.Suffix : FPUnaryOp_r_frm<funct7, rs2val, rdty, rs1ty,
249 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
250 UseNamedOperandTable = 1, hasPostISelHook = 1 in
251 class FPUnaryOp_r_frmlegacy<bits<7> funct7, bits<5> rs2val, DAGOperand rdty,
252 DAGOperand rs1ty, string opcodestr>
253 : RVInstRFrm<funct7, OPC_OP_FP, (outs rdty:$rd),
254 (ins rs1ty:$rs1, frmarglegacy:$frm), opcodestr,
258 multiclass FPUnaryOp_r_frmlegacy_m<bits<7> funct7, bits<5> rs2val,
259 ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,
260 string opcodestr, list<Predicate> ExtraPreds = []> {
261 let Predicates = !listconcat(Ext.Predicates, ExtraPreds),
262 DecoderNamespace = Ext.Space in
263 def Ext.Suffix : FPUnaryOp_r_frmlegacy<funct7, rs2val, rdty, rs1ty,
267 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
268 IsSignExtendingOpW = 1 in
269 class FPCmp_rr<bits<7> funct7, bits<3> funct3, string opcodestr,
270 DAGOperand rty, bit Commutable = 0>
271 : RVInstR<funct7, funct3, OPC_OP_FP, (outs GPR:$rd),
272 (ins rty:$rs1, rty:$rs2), opcodestr, "$rd, $rs1, $rs2"> {
273 let isCommutable = Commutable;
275 multiclass FPCmp_rr_m<bits<7> funct7, bits<3> funct3, string opcodestr,
276 ExtInfo Ext, bit Commutable = 0> {
277 let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in
278 def Ext.Suffix : FPCmp_rr<funct7, funct3, opcodestr, Ext.PrimaryTy, Commutable>;
281 class PseudoFROUND<DAGOperand Ty, ValueType vt>
282 : Pseudo<(outs Ty:$rd), (ins Ty:$rs1, Ty:$rs2, ixlenimm:$rm),
283 [(set Ty:$rd, (vt (riscv_fround Ty:$rs1, Ty:$rs2, timm:$rm)))]> {
284 let hasSideEffects = 0;
287 let usesCustomInserter = 1;
288 let mayRaiseFPException = 1;
291 //===----------------------------------------------------------------------===//
293 //===----------------------------------------------------------------------===//
295 let Predicates = [HasStdExtF] in {
296 def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>;
298 // Operands for stores are in the order srcreg, base, offset rather than
299 // reflecting the order these fields are specified in the instruction
301 def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>;
302 } // Predicates = [HasStdExtF]
304 foreach Ext = FExts in {
305 let SchedRW = [WriteFMA32, ReadFMA32, ReadFMA32, ReadFMA32Addend] in {
306 defm FMADD_S : FPFMA_rrr_frm_m<OPC_MADD, 0b00, "fmadd.s", Ext>;
307 defm FMSUB_S : FPFMA_rrr_frm_m<OPC_MSUB, 0b00, "fmsub.s", Ext>;
308 defm FNMSUB_S : FPFMA_rrr_frm_m<OPC_NMSUB, 0b00, "fnmsub.s", Ext>;
309 defm FNMADD_S : FPFMA_rrr_frm_m<OPC_NMADD, 0b00, "fnmadd.s", Ext>;
312 let SchedRW = [WriteFAdd32, ReadFAdd32, ReadFAdd32] in {
313 defm FADD_S : FPALU_rr_frm_m<0b0000000, "fadd.s", Ext, Commutable=1>;
314 defm FSUB_S : FPALU_rr_frm_m<0b0000100, "fsub.s", Ext>;
317 let SchedRW = [WriteFMul32, ReadFMul32, ReadFMul32] in
318 defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", Ext, Commutable=1>;
320 let SchedRW = [WriteFDiv32, ReadFDiv32, ReadFDiv32] in
321 defm FDIV_S : FPALU_rr_frm_m<0b0001100, "fdiv.s", Ext>;
323 defm FSQRT_S : FPUnaryOp_r_frm_m<0b0101100, 0b00000, Ext, Ext.PrimaryTy,
324 Ext.PrimaryTy, "fsqrt.s">,
325 Sched<[WriteFSqrt32, ReadFSqrt32]>;
327 let SchedRW = [WriteFSGNJ32, ReadFSGNJ32, ReadFSGNJ32],
328 mayRaiseFPException = 0 in {
329 defm FSGNJ_S : FPALU_rr_m<0b0010000, 0b000, "fsgnj.s", Ext>;
330 defm FSGNJN_S : FPALU_rr_m<0b0010000, 0b001, "fsgnjn.s", Ext>;
331 defm FSGNJX_S : FPALU_rr_m<0b0010000, 0b010, "fsgnjx.s", Ext>;
334 let SchedRW = [WriteFMinMax32, ReadFMinMax32, ReadFMinMax32] in {
335 defm FMIN_S : FPALU_rr_m<0b0010100, 0b000, "fmin.s", Ext, Commutable=1>;
336 defm FMAX_S : FPALU_rr_m<0b0010100, 0b001, "fmax.s", Ext, Commutable=1>;
339 let IsSignExtendingOpW = 1 in
340 defm FCVT_W_S : FPUnaryOp_r_frm_m<0b1100000, 0b00000, Ext, GPR, Ext.PrimaryTy,
342 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>;
344 let IsSignExtendingOpW = 1 in
345 defm FCVT_WU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00001, Ext, GPR, Ext.PrimaryTy,
347 Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>;
349 let SchedRW = [WriteFCmp32, ReadFCmp32, ReadFCmp32] in {
350 defm FEQ_S : FPCmp_rr_m<0b1010000, 0b010, "feq.s", Ext, Commutable=1>;
351 defm FLT_S : FPCmp_rr_m<0b1010000, 0b001, "flt.s", Ext>;
352 defm FLE_S : FPCmp_rr_m<0b1010000, 0b000, "fle.s", Ext>;
355 let mayRaiseFPException = 0 in
356 defm FCLASS_S : FPUnaryOp_r_m<0b1110000, 0b00000, 0b001, Ext, GPR, Ext.PrimaryTy,
358 Sched<[WriteFClass32, ReadFClass32]>;
360 defm FCVT_S_W : FPUnaryOp_r_frm_m<0b1101000, 0b00000, Ext, Ext.PrimaryTy, GPR,
362 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>;
364 defm FCVT_S_WU : FPUnaryOp_r_frm_m<0b1101000, 0b00001, Ext, Ext.PrimaryTy, GPR,
366 Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>;
368 defm FCVT_L_S : FPUnaryOp_r_frm_m<0b1100000, 0b00010, Ext, GPR, Ext.PrimaryTy,
369 "fcvt.l.s", [IsRV64]>,
370 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>;
372 defm FCVT_LU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00011, Ext, GPR, Ext.PrimaryTy,
373 "fcvt.lu.s", [IsRV64]>,
374 Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>;
376 defm FCVT_S_L : FPUnaryOp_r_frm_m<0b1101000, 0b00010, Ext, Ext.PrimaryTy, GPR,
377 "fcvt.s.l", [IsRV64]>,
378 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>;
380 defm FCVT_S_LU : FPUnaryOp_r_frm_m<0b1101000, 0b00011, Ext, Ext.PrimaryTy, GPR,
381 "fcvt.s.lu", [IsRV64]>,
382 Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>;
383 } // foreach Ext = FExts
385 let Predicates = [HasStdExtF], mayRaiseFPException = 0,
386 IsSignExtendingOpW = 1 in
387 def FMV_X_W : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR32, "fmv.x.w">,
388 Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>;
390 let Predicates = [HasStdExtF], mayRaiseFPException = 0 in
391 def FMV_W_X : FPUnaryOp_r<0b1111000, 0b00000, 0b000, FPR32, GPR, "fmv.w.x">,
392 Sched<[WriteFMovI32ToF32, ReadFMovI32ToF32]>;
394 //===----------------------------------------------------------------------===//
395 // Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
396 //===----------------------------------------------------------------------===//
398 let Predicates = [HasStdExtF] in {
399 def : InstAlias<"flw $rd, (${rs1})", (FLW FPR32:$rd, GPR:$rs1, 0), 0>;
400 def : InstAlias<"fsw $rs2, (${rs1})", (FSW FPR32:$rs2, GPR:$rs1, 0), 0>;
402 def : InstAlias<"fmv.s $rd, $rs", (FSGNJ_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
403 def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
404 def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
406 // fgt.s/fge.s are recognised by the GNU assembler but the canonical
407 // flt.s/fle.s forms will always be printed. Therefore, set a zero weight.
408 def : InstAlias<"fgt.s $rd, $rs, $rt",
409 (FLT_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;
410 def : InstAlias<"fge.s $rd, $rs, $rt",
411 (FLE_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;
413 // The following csr instructions actually alias instructions from the base ISA.
414 // However, it only makes sense to support them when the F extension is enabled.
415 // NOTE: "frcsr", "frrm", and "frflags" are more specialized version of "csrr".
416 def : InstAlias<"frcsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 2>;
417 def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs)>;
418 def : InstAlias<"fscsr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 2>;
420 // frsr, fssr are obsolete aliases replaced by frcsr, fscsr, so give them
422 def : InstAlias<"frsr $rd", (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 0>;
423 def : InstAlias<"fssr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs), 0>;
424 def : InstAlias<"fssr $rs", (CSRRW X0, SysRegFCSR.Encoding, GPR:$rs), 0>;
426 def : InstAlias<"frrm $rd", (CSRRS GPR:$rd, SysRegFRM.Encoding, X0), 2>;
427 def : InstAlias<"fsrm $rd, $rs", (CSRRW GPR:$rd, SysRegFRM.Encoding, GPR:$rs)>;
428 def : InstAlias<"fsrm $rs", (CSRRW X0, SysRegFRM.Encoding, GPR:$rs), 2>;
429 def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, SysRegFRM.Encoding, uimm5:$imm)>;
430 def : InstAlias<"fsrmi $imm", (CSRRWI X0, SysRegFRM.Encoding, uimm5:$imm), 2>;
432 def : InstAlias<"frflags $rd", (CSRRS GPR:$rd, SysRegFFLAGS.Encoding, X0), 2>;
433 def : InstAlias<"fsflags $rd, $rs", (CSRRW GPR:$rd, SysRegFFLAGS.Encoding, GPR:$rs)>;
434 def : InstAlias<"fsflags $rs", (CSRRW X0, SysRegFFLAGS.Encoding, GPR:$rs), 2>;
435 def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, SysRegFFLAGS.Encoding, uimm5:$imm)>;
436 def : InstAlias<"fsflagsi $imm", (CSRRWI X0, SysRegFFLAGS.Encoding, uimm5:$imm), 2>;
438 // fmv.w.x and fmv.x.w were previously known as fmv.s.x and fmv.x.s. Both
439 // spellings should be supported by standard tools.
440 def : MnemonicAlias<"fmv.s.x", "fmv.w.x">;
441 def : MnemonicAlias<"fmv.x.s", "fmv.x.w">;
443 def PseudoFLW : PseudoFloatLoad<"flw", FPR32>;
444 def PseudoFSW : PseudoStore<"fsw", FPR32>;
445 let usesCustomInserter = 1 in {
446 def PseudoQuietFLE_S : PseudoQuietFCMP<FPR32>;
447 def PseudoQuietFLT_S : PseudoQuietFCMP<FPR32>;
449 } // Predicates = [HasStdExtF]
451 let Predicates = [HasStdExtZfinx] in {
452 def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
453 def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
455 def : InstAlias<"fgt.s $rd, $rs, $rt",
456 (FLT_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>;
457 def : InstAlias<"fge.s $rd, $rs, $rt",
458 (FLE_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>;
459 let usesCustomInserter = 1 in {
460 def PseudoQuietFLE_S_INX : PseudoQuietFCMP<FPR32INX>;
461 def PseudoQuietFLT_S_INX : PseudoQuietFCMP<FPR32INX>;
463 } // Predicates = [HasStdExtZfinx]
465 //===----------------------------------------------------------------------===//
466 // Pseudo-instructions and codegen patterns
467 //===----------------------------------------------------------------------===//
469 defvar FRM_RNE = 0b000;
470 defvar FRM_RTZ = 0b001;
471 defvar FRM_RDN = 0b010;
472 defvar FRM_RUP = 0b011;
473 defvar FRM_RMM = 0b100;
474 defvar FRM_DYN = 0b111;
476 /// Floating point constants
477 def fpimm0 : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;
479 /// Generic pattern classes
480 class PatSetCC<DAGOperand Ty, SDPatternOperator OpNode, CondCode Cond,
481 RVInst Inst, ValueType vt>
482 : Pat<(XLenVT (OpNode (vt Ty:$rs1), Ty:$rs2, Cond)), (Inst $rs1, $rs2)>;
483 multiclass PatSetCC_m<SDPatternOperator OpNode, CondCode Cond,
484 RVInst Inst, ExtInfo Ext> {
485 let Predicates = Ext.Predicates in
486 def Ext.Suffix : PatSetCC<Ext.PrimaryTy, OpNode, Cond,
487 !cast<RVInst>(Inst#Ext.Suffix), Ext.PrimaryVT>;
490 class PatFprFpr<SDPatternOperator OpNode, RVInstR Inst,
491 DAGOperand RegTy, ValueType vt>
492 : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2)>;
493 multiclass PatFprFpr_m<SDPatternOperator OpNode, RVInstR Inst,
495 let Predicates = Ext.Predicates in
496 def Ext.Suffix : PatFprFpr<OpNode, !cast<RVInstR>(Inst#Ext.Suffix),
497 Ext.PrimaryTy, Ext.PrimaryVT>;
500 class PatFprFprDynFrm<SDPatternOperator OpNode, RVInstRFrm Inst,
501 DAGOperand RegTy, ValueType vt>
502 : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2, FRM_DYN)>;
503 multiclass PatFprFprDynFrm_m<SDPatternOperator OpNode, RVInstRFrm Inst,
505 let Predicates = Ext.Predicates in
506 def Ext.Suffix : PatFprFprDynFrm<OpNode,
507 !cast<RVInstRFrm>(Inst#Ext.Suffix),
508 Ext.PrimaryTy, Ext.PrimaryVT>;
511 /// Float conversion operations
513 // [u]int32<->float conversion patterns must be gated on IsRV32 or IsRV64, so
514 // are defined later.
516 /// Float arithmetic operations
517 foreach Ext = FExts in {
518 defm : PatFprFprDynFrm_m<any_fadd, FADD_S, Ext>;
519 defm : PatFprFprDynFrm_m<any_fsub, FSUB_S, Ext>;
520 defm : PatFprFprDynFrm_m<any_fmul, FMUL_S, Ext>;
521 defm : PatFprFprDynFrm_m<any_fdiv, FDIV_S, Ext>;
524 let Predicates = [HasStdExtF] in {
525 def : Pat<(any_fsqrt FPR32:$rs1), (FSQRT_S FPR32:$rs1, FRM_DYN)>;
527 def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>;
528 def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>;
530 def : Pat<(riscv_fclass FPR32:$rs1), (FCLASS_S $rs1)>;
531 } // Predicates = [HasStdExtF]
533 let Predicates = [HasStdExtZfinx] in {
534 def : Pat<(any_fsqrt FPR32INX:$rs1), (FSQRT_S_INX FPR32INX:$rs1, FRM_DYN)>;
536 def : Pat<(fneg FPR32INX:$rs1), (FSGNJN_S_INX $rs1, $rs1)>;
537 def : Pat<(fabs FPR32INX:$rs1), (FSGNJX_S_INX $rs1, $rs1)>;
539 def : Pat<(riscv_fclass FPR32INX:$rs1), (FCLASS_S_INX $rs1)>;
540 } // Predicates = [HasStdExtZfinx]
542 foreach Ext = FExts in
543 defm : PatFprFpr_m<fcopysign, FSGNJ_S, Ext>;
545 let Predicates = [HasStdExtF] in {
546 def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>;
548 // fmadd: rs1 * rs2 + rs3
549 def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3),
550 (FMADD_S $rs1, $rs2, $rs3, FRM_DYN)>;
552 // fmsub: rs1 * rs2 - rs3
553 def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)),
554 (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
556 // fnmsub: -rs1 * rs2 + rs3
557 def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, FPR32:$rs3),
558 (FNMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
560 // fnmadd: -rs1 * rs2 - rs3
561 def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)),
562 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
564 // fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
565 def : Pat<(fneg (any_fma_nsz FPR32:$rs1, FPR32:$rs2, FPR32:$rs3)),
566 (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
567 } // Predicates = [HasStdExtF]
569 let Predicates = [HasStdExtZfinx] in {
570 def : Pat<(fcopysign FPR32INX:$rs1, (fneg FPR32INX:$rs2)), (FSGNJN_S_INX $rs1, $rs2)>;
572 // fmadd: rs1 * rs2 + rs3
573 def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3),
574 (FMADD_S_INX $rs1, $rs2, $rs3, FRM_DYN)>;
576 // fmsub: rs1 * rs2 - rs3
577 def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, (fneg FPR32INX:$rs3)),
578 (FMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
580 // fnmsub: -rs1 * rs2 + rs3
581 def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, FPR32INX:$rs3),
582 (FNMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
584 // fnmadd: -rs1 * rs2 - rs3
585 def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, (fneg FPR32INX:$rs3)),
586 (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
588 // fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
589 def : Pat<(fneg (any_fma_nsz FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3)),
590 (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
591 } // Predicates = [HasStdExtZfinx]
593 // The ratified 20191213 ISA spec defines fmin and fmax in a way that matches
594 // LLVM's fminnum and fmaxnum
595 // <https://github.com/riscv/riscv-isa-manual/commit/cd20cee7efd9bac7c5aa127ec3b451749d2b3cce>.
596 foreach Ext = FExts in {
597 defm : PatFprFpr_m<fminnum, FMIN_S, Ext>;
598 defm : PatFprFpr_m<fmaxnum, FMAX_S, Ext>;
599 defm : PatFprFpr_m<riscv_fmin, FMIN_S, Ext>;
600 defm : PatFprFpr_m<riscv_fmax, FMAX_S, Ext>;
604 // FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for
605 // strict versions of those.
607 // Match non-signaling FEQ_S
608 foreach Ext = FExts in {
609 defm : PatSetCC_m<any_fsetcc, SETEQ, FEQ_S, Ext>;
610 defm : PatSetCC_m<any_fsetcc, SETOEQ, FEQ_S, Ext>;
611 defm : PatSetCC_m<strict_fsetcc, SETLT, PseudoQuietFLT_S, Ext>;
612 defm : PatSetCC_m<strict_fsetcc, SETOLT, PseudoQuietFLT_S, Ext>;
613 defm : PatSetCC_m<strict_fsetcc, SETLE, PseudoQuietFLE_S, Ext>;
614 defm : PatSetCC_m<strict_fsetcc, SETOLE, PseudoQuietFLE_S, Ext>;
617 let Predicates = [HasStdExtF] in {
618 // Match signaling FEQ_S
619 def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETEQ)),
620 (AND (FLE_S $rs1, $rs2),
621 (FLE_S $rs2, $rs1))>;
622 def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETOEQ)),
623 (AND (FLE_S $rs1, $rs2),
624 (FLE_S $rs2, $rs1))>;
625 // If both operands are the same, use a single FLE.
626 def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETEQ)),
628 def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETOEQ)),
630 } // Predicates = [HasStdExtF]
632 let Predicates = [HasStdExtZfinx] in {
633 // Match signaling FEQ_S
634 def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETEQ)),
635 (AND (FLE_S_INX $rs1, $rs2),
636 (FLE_S_INX $rs2, $rs1))>;
637 def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETOEQ)),
638 (AND (FLE_S_INX $rs1, $rs2),
639 (FLE_S_INX $rs2, $rs1))>;
640 // If both operands are the same, use a single FLE.
641 def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETEQ)),
642 (FLE_S_INX $rs1, $rs1)>;
643 def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETOEQ)),
644 (FLE_S_INX $rs1, $rs1)>;
645 } // Predicates = [HasStdExtZfinx]
647 foreach Ext = FExts in {
648 defm : PatSetCC_m<any_fsetccs, SETLT, FLT_S, Ext>;
649 defm : PatSetCC_m<any_fsetccs, SETOLT, FLT_S, Ext>;
650 defm : PatSetCC_m<any_fsetccs, SETLE, FLE_S, Ext>;
651 defm : PatSetCC_m<any_fsetccs, SETOLE, FLE_S, Ext>;
654 let Predicates = [HasStdExtF] in {
655 defm Select_FPR32 : SelectCC_GPR_rrirr<FPR32, f32>;
657 def PseudoFROUND_S : PseudoFROUND<FPR32, f32>;
661 def : LdPat<load, FLW, f32>;
665 def : StPat<store, FSW, FPR32, f32>;
667 } // Predicates = [HasStdExtF]
669 let Predicates = [HasStdExtZfinx] in {
670 defm Select_FPR32INX : SelectCC_GPR_rrirr<FPR32INX, f32>;
672 def PseudoFROUND_S_INX : PseudoFROUND<FPR32INX, f32>;
675 def : Pat<(f32 (load (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12))),
676 (COPY_TO_REGCLASS (LW GPR:$rs1, simm12:$imm12), GPRF32)>;
679 def : Pat<(store (f32 FPR32INX:$rs2), (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12)),
680 (SW (COPY_TO_REGCLASS FPR32INX:$rs2, GPR), GPR:$rs1, simm12:$imm12)>;
681 } // Predicates = [HasStdExtZfinx]
683 let Predicates = [HasStdExtF] in {
684 // Moves (no conversion)
685 def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>;
686 def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>;
687 } // Predicates = [HasStdExtF]
689 let Predicates = [HasStdExtZfinx] in {
690 // Moves (no conversion)
691 def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (COPY_TO_REGCLASS GPR:$rs1, GPRF32)>;
692 def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (COPY_TO_REGCLASS FPR32INX:$rs1, GPR)>;
693 } // Predicates = [HasStdExtZfinx]
695 let Predicates = [HasStdExtF] in {
696 // float->[u]int. Round-to-zero must be used.
697 def : Pat<(i32 (any_fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RTZ)>;
698 def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, FRM_RTZ)>;
700 // Saturating float->[u]int32.
701 def : Pat<(i32 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_W_S $rs1, timm:$frm)>;
702 def : Pat<(i32 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_WU_S $rs1, timm:$frm)>;
704 // float->int32 with current rounding mode.
705 def : Pat<(i32 (any_lrint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_DYN)>;
707 // float->int32 rounded to nearest with ties rounded away from zero.
708 def : Pat<(i32 (any_lround FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RMM)>;
710 // [u]int->float. Match GCC and default to using dynamic rounding mode.
711 def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W $rs1, FRM_DYN)>;
712 def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU $rs1, FRM_DYN)>;
713 } // Predicates = [HasStdExtF]
715 let Predicates = [HasStdExtZfinx] in {
716 // float->[u]int. Round-to-zero must be used.
717 def : Pat<(i32 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RTZ)>;
718 def : Pat<(i32 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_WU_S_INX $rs1, FRM_RTZ)>;
720 // Saturating float->[u]int32.
721 def : Pat<(i32 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_W_S_INX $rs1, timm:$frm)>;
722 def : Pat<(i32 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_WU_S_INX $rs1, timm:$frm)>;
724 // float->int32 with current rounding mode.
725 def : Pat<(i32 (any_lrint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_DYN)>;
727 // float->int32 rounded to nearest with ties rounded away from zero.
728 def : Pat<(i32 (any_lround FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RMM)>;
730 // [u]int->float. Match GCC and default to using dynamic rounding mode.
731 def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W_INX $rs1, FRM_DYN)>;
732 def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU_INX $rs1, FRM_DYN)>;
733 } // Predicates = [HasStdExtZfinx]
735 let Predicates = [HasStdExtF, IsRV64] in {
736 // Moves (no conversion)
737 def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>;
738 def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>;
740 // Use target specific isd nodes to help us remember the result is sign
741 // extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be
742 // duplicated if it has another user that didn't need the sign_extend.
743 def : Pat<(riscv_any_fcvt_w_rv64 FPR32:$rs1, timm:$frm), (FCVT_W_S $rs1, timm:$frm)>;
744 def : Pat<(riscv_any_fcvt_wu_rv64 FPR32:$rs1, timm:$frm), (FCVT_WU_S $rs1, timm:$frm)>;
746 // float->[u]int64. Round-to-zero must be used.
747 def : Pat<(i64 (any_fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RTZ)>;
748 def : Pat<(i64 (any_fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, FRM_RTZ)>;
750 // Saturating float->[u]int64.
751 def : Pat<(i64 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_L_S $rs1, timm:$frm)>;
752 def : Pat<(i64 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_LU_S $rs1, timm:$frm)>;
754 // float->int64 with current rounding mode.
755 def : Pat<(i64 (any_lrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>;
756 def : Pat<(i64 (any_llrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>;
758 // float->int64 rounded to neartest with ties rounded away from zero.
759 def : Pat<(i64 (any_lround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>;
760 def : Pat<(i64 (any_llround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>;
762 // [u]int->fp. Match GCC and default to using dynamic rounding mode.
763 def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W $rs1, FRM_DYN)>;
764 def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU $rs1, FRM_DYN)>;
765 def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L $rs1, FRM_DYN)>;
766 def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU $rs1, FRM_DYN)>;
767 } // Predicates = [HasStdExtF, IsRV64]
769 let Predicates = [HasStdExtZfinx, IsRV64] in {
770 // Moves (no conversion)
771 def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (COPY_TO_REGCLASS GPR:$src, GPRF32)>;
772 def : Pat<(riscv_fmv_x_anyextw_rv64 GPRF32:$src), (COPY_TO_REGCLASS GPRF32:$src, GPR)>;
774 // Use target specific isd nodes to help us remember the result is sign
775 // extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be
776 // duplicated if it has another user that didn't need the sign_extend.
777 def : Pat<(riscv_any_fcvt_w_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_W_S_INX $rs1, timm:$frm)>;
778 def : Pat<(riscv_any_fcvt_wu_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_WU_S_INX $rs1, timm:$frm)>;
780 // float->[u]int64. Round-to-zero must be used.
781 def : Pat<(i64 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RTZ)>;
782 def : Pat<(i64 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_LU_S_INX $rs1, FRM_RTZ)>;
784 // Saturating float->[u]int64.
785 def : Pat<(i64 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_L_S_INX $rs1, timm:$frm)>;
786 def : Pat<(i64 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_LU_S_INX $rs1, timm:$frm)>;
788 // float->int64 with current rounding mode.
789 def : Pat<(i64 (any_lrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
790 def : Pat<(i64 (any_llrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
792 // float->int64 rounded to neartest with ties rounded away from zero.
793 def : Pat<(i64 (any_lround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
794 def : Pat<(i64 (any_llround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
796 // [u]int->fp. Match GCC and default to using dynamic rounding mode.
797 def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W_INX $rs1, FRM_DYN)>;
798 def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU_INX $rs1, FRM_DYN)>;
799 def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L_INX $rs1, FRM_DYN)>;
800 def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU_INX $rs1, FRM_DYN)>;
801 } // Predicates = [HasStdExtZfinx, IsRV64]