xref: /llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfoF.td (revision 3fb0bea859efaf401ad0ce420d7b75e3ff1c4746)
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