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