xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfoF.td (revision 397e83df75e0fcd0d3fcb95ae4d794cb7600fc89)
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>]>;
34
35def riscv_fclass
36    : SDNode<"RISCVISD::FCLASS", SDT_RISCVFCLASS>;
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// 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
140// default.
141def FRMArgLegacy : AsmOperandClass {
142  let Name = "FRMArgLegacy";
143  let RenderMethod = "addFRMArgOperands";
144  let ParserMethod = "parseFRMArg";
145  let IsOptional = 1;
146  let DefaultMethod = "defaultFRMArgLegacyOp";
147}
148
149def frmarglegacy : Operand<XLenVT> {
150  let ParserMatchClass = FRMArgLegacy;
151  let PrintMethod = "printFRMArgLegacy";
152  let DecoderMethod = "decodeFRMArg";
153}
154
155//===----------------------------------------------------------------------===//
156// Instruction class templates
157//===----------------------------------------------------------------------===//
158
159let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
160class FPLoad_r<bits<3> funct3, string opcodestr, DAGOperand rty,
161               SchedWrite sw>
162    : RVInstI<funct3, OPC_LOAD_FP, (outs rty:$rd),
163              (ins GPRMem:$rs1, simm12:$imm12),
164              opcodestr, "$rd, ${imm12}(${rs1})">,
165      Sched<[sw, ReadFMemBase]>;
166
167let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
168class FPStore_r<bits<3> funct3, string opcodestr, DAGOperand rty,
169                SchedWrite sw>
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]>;
174
175let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
176    UseNamedOperandTable = 1, hasPostISelHook = 1, isCommutable = 1 in
177class FPFMA_rrr_frm<RISCVOpcode opcode, bits<2> funct2, string opcodestr,
178                    DAGOperand rty>
179    : RVInstR4Frm<funct2, opcode, (outs rty:$rd),
180                  (ins rty:$rs1, rty:$rs2, rty:$rs3, frmarg:$frm),
181                  opcodestr, "$rd, $rs1, $rs2, $rs3$frm">;
182
183multiclass 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>;
187}
188
189let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in
190class 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;
195}
196multiclass 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>;
200}
201
202let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
203    UseNamedOperandTable = 1, hasPostISelHook = 1 in
204class FPALU_rr_frm<bits<7> funct7, string opcodestr, DAGOperand rty,
205                   bit Commutable>
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;
210}
211multiclass 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>;
215}
216
217let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1 in
218class 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"> {
222  let rs2 = rs2val;
223}
224multiclass FPUnaryOp_r_m<bits<7> funct7, bits<5> rs2val, bits<3> funct3,
225                         ExtInfo Ext, DAGOperand rdty, DAGOperand rs1ty,
226                         string opcodestr> {
227  let Predicates = Ext.Predicates, DecoderNamespace = Ext.Space in
228  def Ext.Suffix : FPUnaryOp_r<funct7, rs2val, funct3, rdty, rs1ty, opcodestr>;
229}
230
231let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
232    UseNamedOperandTable = 1, hasPostISelHook = 1 in
233class 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,
237                  "$rd, $rs1$frm"> {
238  let rs2 = rs2val;
239}
240multiclass 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,
246                                   opcodestr>;
247}
248
249let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
250    UseNamedOperandTable = 1, hasPostISelHook = 1 in
251class 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,
255                  "$rd, $rs1$frm"> {
256  let rs2 = rs2val;
257}
258multiclass 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,
264                                         opcodestr>;
265}
266
267let hasSideEffects = 0, mayLoad = 0, mayStore = 0, mayRaiseFPException = 1,
268    IsSignExtendingOpW = 1 in
269class 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;
274}
275multiclass 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>;
279}
280
281class 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;
285  let mayLoad = 0;
286  let mayStore = 0;
287  let usesCustomInserter = 1;
288  let mayRaiseFPException = 1;
289}
290
291//===----------------------------------------------------------------------===//
292// Instructions
293//===----------------------------------------------------------------------===//
294
295let Predicates = [HasStdExtF] in {
296def FLW : FPLoad_r<0b010, "flw", FPR32, WriteFLD32>;
297
298// Operands for stores are in the order srcreg, base, offset rather than
299// reflecting the order these fields are specified in the instruction
300// encoding.
301def FSW : FPStore_r<0b010, "fsw", FPR32, WriteFST32>;
302} // Predicates = [HasStdExtF]
303
304foreach 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>;
310  }
311
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>;
315  }
316
317  let SchedRW = [WriteFMul32, ReadFMul32, ReadFMul32] in
318  defm FMUL_S : FPALU_rr_frm_m<0b0001000, "fmul.s", Ext, Commutable=1>;
319
320  let SchedRW = [WriteFDiv32, ReadFDiv32, ReadFDiv32] in
321  defm FDIV_S : FPALU_rr_frm_m<0b0001100, "fdiv.s", Ext>;
322
323  defm FSQRT_S : FPUnaryOp_r_frm_m<0b0101100, 0b00000, Ext, Ext.PrimaryTy,
324                                   Ext.PrimaryTy, "fsqrt.s">,
325                 Sched<[WriteFSqrt32, ReadFSqrt32]>;
326
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>;
332  }
333
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>;
337  }
338
339  let IsSignExtendingOpW = 1 in
340  defm FCVT_W_S : FPUnaryOp_r_frm_m<0b1100000, 0b00000, Ext, GPR, Ext.PrimaryTy,
341                                    "fcvt.w.s">,
342                  Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>;
343
344  let IsSignExtendingOpW = 1 in
345  defm FCVT_WU_S : FPUnaryOp_r_frm_m<0b1100000, 0b00001, Ext, GPR, Ext.PrimaryTy,
346                                     "fcvt.wu.s">,
347                   Sched<[WriteFCvtF32ToI32, ReadFCvtF32ToI32]>;
348
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>;
353  }
354
355  let mayRaiseFPException = 0 in
356  defm FCLASS_S : FPUnaryOp_r_m<0b1110000, 0b00000, 0b001, Ext, GPR, Ext.PrimaryTy,
357                                "fclass.s">,
358                  Sched<[WriteFClass32, ReadFClass32]>;
359
360  defm FCVT_S_W : FPUnaryOp_r_frm_m<0b1101000, 0b00000, Ext, Ext.PrimaryTy, GPR,
361                                    "fcvt.s.w">,
362                  Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>;
363
364  defm FCVT_S_WU : FPUnaryOp_r_frm_m<0b1101000, 0b00001, Ext, Ext.PrimaryTy, GPR,
365                                     "fcvt.s.wu">,
366                   Sched<[WriteFCvtI32ToF32, ReadFCvtI32ToF32]>;
367
368  defm FCVT_L_S  : FPUnaryOp_r_frm_m<0b1100000, 0b00010, Ext, GPR, Ext.PrimaryTy,
369                                     "fcvt.l.s", [IsRV64]>,
370                   Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>;
371
372  defm FCVT_LU_S  : FPUnaryOp_r_frm_m<0b1100000, 0b00011, Ext, GPR, Ext.PrimaryTy,
373                                      "fcvt.lu.s", [IsRV64]>,
374                    Sched<[WriteFCvtF32ToI64, ReadFCvtF32ToI64]>;
375
376  defm FCVT_S_L : FPUnaryOp_r_frm_m<0b1101000, 0b00010, Ext, Ext.PrimaryTy, GPR,
377                                    "fcvt.s.l", [IsRV64]>,
378                  Sched<[WriteFCvtI64ToF32, ReadFCvtI64ToF32]>;
379
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
384
385let Predicates = [HasStdExtF], mayRaiseFPException = 0,
386    IsSignExtendingOpW = 1 in
387def FMV_X_W : FPUnaryOp_r<0b1110000, 0b00000, 0b000, GPR, FPR32, "fmv.x.w">,
388              Sched<[WriteFMovF32ToI32, ReadFMovF32ToI32]>;
389
390let Predicates = [HasStdExtF], mayRaiseFPException = 0 in
391def FMV_W_X : FPUnaryOp_r<0b1111000, 0b00000, 0b000, FPR32, GPR, "fmv.w.x">,
392              Sched<[WriteFMovI32ToF32, ReadFMovI32ToF32]>;
393
394//===----------------------------------------------------------------------===//
395// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
396//===----------------------------------------------------------------------===//
397
398let Predicates = [HasStdExtF] in {
399def : InstAlias<"flw $rd, (${rs1})",  (FLW FPR32:$rd,  GPR:$rs1, 0), 0>;
400def : InstAlias<"fsw $rs2, (${rs1})", (FSW FPR32:$rs2, GPR:$rs1, 0), 0>;
401
402def : InstAlias<"fmv.s $rd, $rs",  (FSGNJ_S  FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
403def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
404def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S FPR32:$rd, FPR32:$rs, FPR32:$rs)>;
405
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.
408def : InstAlias<"fgt.s $rd, $rs, $rt",
409                (FLT_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;
410def : InstAlias<"fge.s $rd, $rs, $rt",
411                (FLE_S GPR:$rd, FPR32:$rt, FPR32:$rs), 0>;
412
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".
416def : InstAlias<"frcsr $rd",      (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 2>;
417def : InstAlias<"fscsr $rd, $rs", (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs)>;
418def : InstAlias<"fscsr $rs",      (CSRRW      X0, SysRegFCSR.Encoding, GPR:$rs), 2>;
419
420// frsr, fssr are obsolete aliases replaced by frcsr, fscsr, so give them
421// zero weight.
422def : InstAlias<"frsr $rd",       (CSRRS GPR:$rd, SysRegFCSR.Encoding, X0), 0>;
423def : InstAlias<"fssr $rd, $rs",  (CSRRW GPR:$rd, SysRegFCSR.Encoding, GPR:$rs), 0>;
424def : InstAlias<"fssr $rs",       (CSRRW      X0, SysRegFCSR.Encoding, GPR:$rs), 0>;
425
426def : InstAlias<"frrm $rd",        (CSRRS  GPR:$rd, SysRegFRM.Encoding, X0), 2>;
427def : InstAlias<"fsrm $rd, $rs",   (CSRRW  GPR:$rd, SysRegFRM.Encoding, GPR:$rs)>;
428def : InstAlias<"fsrm $rs",        (CSRRW       X0, SysRegFRM.Encoding, GPR:$rs), 2>;
429def : InstAlias<"fsrmi $rd, $imm", (CSRRWI GPR:$rd, SysRegFRM.Encoding, uimm5:$imm)>;
430def : InstAlias<"fsrmi $imm",      (CSRRWI      X0, SysRegFRM.Encoding, uimm5:$imm), 2>;
431
432def : InstAlias<"frflags $rd",        (CSRRS  GPR:$rd, SysRegFFLAGS.Encoding, X0), 2>;
433def : InstAlias<"fsflags $rd, $rs",   (CSRRW  GPR:$rd, SysRegFFLAGS.Encoding, GPR:$rs)>;
434def : InstAlias<"fsflags $rs",        (CSRRW       X0, SysRegFFLAGS.Encoding, GPR:$rs), 2>;
435def : InstAlias<"fsflagsi $rd, $imm", (CSRRWI GPR:$rd, SysRegFFLAGS.Encoding, uimm5:$imm)>;
436def : InstAlias<"fsflagsi $imm",      (CSRRWI      X0, SysRegFFLAGS.Encoding, uimm5:$imm), 2>;
437
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.
440def : MnemonicAlias<"fmv.s.x", "fmv.w.x">;
441def : MnemonicAlias<"fmv.x.s", "fmv.x.w">;
442
443def PseudoFLW  : PseudoFloatLoad<"flw", FPR32>;
444def PseudoFSW  : PseudoStore<"fsw", FPR32>;
445let usesCustomInserter = 1 in {
446def PseudoQuietFLE_S : PseudoQuietFCMP<FPR32>;
447def PseudoQuietFLT_S : PseudoQuietFCMP<FPR32>;
448}
449} // Predicates = [HasStdExtF]
450
451let Predicates = [HasStdExtZfinx] in {
452def : InstAlias<"fabs.s $rd, $rs", (FSGNJX_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
453def : InstAlias<"fneg.s $rd, $rs", (FSGNJN_S_INX FPR32INX:$rd, FPR32INX:$rs, FPR32INX:$rs)>;
454
455def : InstAlias<"fgt.s $rd, $rs, $rt",
456                (FLT_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>;
457def : InstAlias<"fge.s $rd, $rs, $rt",
458                (FLE_S_INX GPR:$rd, FPR32INX:$rt, FPR32INX:$rs), 0>;
459let usesCustomInserter = 1 in {
460def PseudoQuietFLE_S_INX : PseudoQuietFCMP<FPR32INX>;
461def PseudoQuietFLT_S_INX : PseudoQuietFCMP<FPR32INX>;
462}
463} // Predicates = [HasStdExtZfinx]
464
465//===----------------------------------------------------------------------===//
466// Pseudo-instructions and codegen patterns
467//===----------------------------------------------------------------------===//
468
469defvar FRM_RNE = 0b000;
470defvar FRM_RTZ = 0b001;
471defvar FRM_RDN = 0b010;
472defvar FRM_RUP = 0b011;
473defvar FRM_RMM = 0b100;
474defvar FRM_DYN = 0b111;
475
476/// Floating point constants
477def fpimm0    : PatLeaf<(fpimm), [{ return N->isExactlyValue(+0.0); }]>;
478
479/// Generic pattern classes
480class 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)>;
483multiclass 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>;
488}
489
490class PatFprFpr<SDPatternOperator OpNode, RVInstR Inst,
491                DAGOperand RegTy, ValueType vt>
492    : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2)>;
493multiclass PatFprFpr_m<SDPatternOperator OpNode, RVInstR Inst,
494                       ExtInfo Ext> {
495  let Predicates = Ext.Predicates in
496  def Ext.Suffix : PatFprFpr<OpNode, !cast<RVInstR>(Inst#Ext.Suffix),
497                             Ext.PrimaryTy, Ext.PrimaryVT>;
498}
499
500class PatFprFprDynFrm<SDPatternOperator OpNode, RVInstRFrm Inst,
501                      DAGOperand RegTy, ValueType vt>
502    : Pat<(OpNode (vt RegTy:$rs1), (vt RegTy:$rs2)), (Inst $rs1, $rs2, FRM_DYN)>;
503multiclass PatFprFprDynFrm_m<SDPatternOperator OpNode, RVInstRFrm Inst,
504                             ExtInfo Ext> {
505  let Predicates = Ext.Predicates in
506  def Ext.Suffix : PatFprFprDynFrm<OpNode,
507                                   !cast<RVInstRFrm>(Inst#Ext.Suffix),
508                                   Ext.PrimaryTy, Ext.PrimaryVT>;
509}
510
511/// Float conversion operations
512
513// [u]int32<->float conversion patterns must be gated on IsRV32 or IsRV64, so
514// are defined later.
515
516/// Float arithmetic operations
517foreach 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>;
522}
523
524let Predicates = [HasStdExtF] in {
525def : Pat<(any_fsqrt FPR32:$rs1), (FSQRT_S FPR32:$rs1, FRM_DYN)>;
526
527def : Pat<(fneg FPR32:$rs1), (FSGNJN_S $rs1, $rs1)>;
528def : Pat<(fabs FPR32:$rs1), (FSGNJX_S $rs1, $rs1)>;
529
530def : Pat<(riscv_fclass FPR32:$rs1), (FCLASS_S $rs1)>;
531} // Predicates = [HasStdExtF]
532
533let Predicates = [HasStdExtZfinx] in {
534def : Pat<(any_fsqrt FPR32INX:$rs1), (FSQRT_S_INX FPR32INX:$rs1, FRM_DYN)>;
535
536def : Pat<(fneg FPR32INX:$rs1), (FSGNJN_S_INX $rs1, $rs1)>;
537def : Pat<(fabs FPR32INX:$rs1), (FSGNJX_S_INX $rs1, $rs1)>;
538
539def : Pat<(riscv_fclass FPR32INX:$rs1), (FCLASS_S_INX $rs1)>;
540} // Predicates = [HasStdExtZfinx]
541
542foreach Ext = FExts in
543defm : PatFprFpr_m<fcopysign, FSGNJ_S, Ext>;
544
545let Predicates = [HasStdExtF] in {
546def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>;
547
548// fmadd: rs1 * rs2 + rs3
549def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, FPR32:$rs3),
550          (FMADD_S $rs1, $rs2, $rs3, FRM_DYN)>;
551
552// fmsub: rs1 * rs2 - rs3
553def : Pat<(any_fma FPR32:$rs1, FPR32:$rs2, (fneg FPR32:$rs3)),
554          (FMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
555
556// fnmsub: -rs1 * rs2 + rs3
557def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, FPR32:$rs3),
558          (FNMSUB_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
559
560// fnmadd: -rs1 * rs2 - rs3
561def : Pat<(any_fma (fneg FPR32:$rs1), FPR32:$rs2, (fneg FPR32:$rs3)),
562          (FNMADD_S FPR32:$rs1, FPR32:$rs2, FPR32:$rs3, FRM_DYN)>;
563
564// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
565def : 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]
568
569let Predicates = [HasStdExtZfinx] in {
570def : Pat<(fcopysign FPR32INX:$rs1, (fneg FPR32INX:$rs2)), (FSGNJN_S_INX $rs1, $rs2)>;
571
572// fmadd: rs1 * rs2 + rs3
573def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3),
574          (FMADD_S_INX $rs1, $rs2, $rs3, FRM_DYN)>;
575
576// fmsub: rs1 * rs2 - rs3
577def : Pat<(any_fma FPR32INX:$rs1, FPR32INX:$rs2, (fneg FPR32INX:$rs3)),
578          (FMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
579
580// fnmsub: -rs1 * rs2 + rs3
581def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, FPR32INX:$rs3),
582          (FNMSUB_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
583
584// fnmadd: -rs1 * rs2 - rs3
585def : Pat<(any_fma (fneg FPR32INX:$rs1), FPR32INX:$rs2, (fneg FPR32INX:$rs3)),
586          (FNMADD_S_INX FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3, FRM_DYN)>;
587
588// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
589def : 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]
592
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>.
596foreach 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>;
601}
602
603/// Setcc
604// FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for
605// strict versions of those.
606
607// Match non-signaling FEQ_S
608foreach 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>;
615}
616
617let Predicates = [HasStdExtF] in {
618// Match signaling FEQ_S
619def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs2, SETEQ)),
620          (AND (FLE_S $rs1, $rs2),
621               (FLE_S $rs2, $rs1))>;
622def : 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.
626def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETEQ)),
627          (FLE_S $rs1, $rs1)>;
628def : Pat<(XLenVT (strict_fsetccs FPR32:$rs1, FPR32:$rs1, SETOEQ)),
629          (FLE_S $rs1, $rs1)>;
630} // Predicates = [HasStdExtF]
631
632let Predicates = [HasStdExtZfinx] in {
633// Match signaling FEQ_S
634def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs2, SETEQ)),
635          (AND (FLE_S_INX $rs1, $rs2),
636               (FLE_S_INX $rs2, $rs1))>;
637def : 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.
641def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETEQ)),
642          (FLE_S_INX $rs1, $rs1)>;
643def : Pat<(XLenVT (strict_fsetccs FPR32INX:$rs1, FPR32INX:$rs1, SETOEQ)),
644          (FLE_S_INX $rs1, $rs1)>;
645} // Predicates = [HasStdExtZfinx]
646
647foreach 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>;
652}
653
654let Predicates = [HasStdExtF] in {
655defm Select_FPR32 : SelectCC_GPR_rrirr<FPR32, f32>;
656
657def PseudoFROUND_S : PseudoFROUND<FPR32, f32>;
658
659/// Loads
660
661def : LdPat<load, FLW, f32>;
662
663/// Stores
664
665def : StPat<store, FSW, FPR32, f32>;
666
667} // Predicates = [HasStdExtF]
668
669let Predicates = [HasStdExtZfinx] in {
670defm Select_FPR32INX : SelectCC_GPR_rrirr<FPR32INX, f32>;
671
672def PseudoFROUND_S_INX : PseudoFROUND<FPR32INX, f32>;
673
674/// Loads
675def : Pat<(f32 (load (AddrRegImm (XLenVT GPR:$rs1), simm12:$imm12))),
676          (COPY_TO_REGCLASS (LW GPR:$rs1, simm12:$imm12), GPRF32)>;
677
678/// Stores
679def : 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]
682
683let Predicates = [HasStdExtF] in {
684// Moves (no conversion)
685def : Pat<(bitconvert (i32 GPR:$rs1)), (FMV_W_X GPR:$rs1)>;
686def : Pat<(i32 (bitconvert FPR32:$rs1)), (FMV_X_W FPR32:$rs1)>;
687} // Predicates = [HasStdExtF]
688
689let Predicates = [HasStdExtZfinx] in {
690// Moves (no conversion)
691def : Pat<(f32 (bitconvert (i32 GPR:$rs1))), (COPY_TO_REGCLASS GPR:$rs1, GPRF32)>;
692def : Pat<(i32 (bitconvert FPR32INX:$rs1)), (COPY_TO_REGCLASS FPR32INX:$rs1, GPR)>;
693} // Predicates = [HasStdExtZfinx]
694
695let Predicates = [HasStdExtF] in {
696// float->[u]int. Round-to-zero must be used.
697def : Pat<(i32 (any_fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RTZ)>;
698def : Pat<(i32 (any_fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, FRM_RTZ)>;
699
700// Saturating float->[u]int32.
701def : Pat<(i32 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_W_S $rs1, timm:$frm)>;
702def : Pat<(i32 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_WU_S $rs1, timm:$frm)>;
703
704// float->int32 with current rounding mode.
705def : Pat<(i32 (any_lrint FPR32:$rs1)), (FCVT_W_S $rs1, FRM_DYN)>;
706
707// float->int32 rounded to nearest with ties rounded away from zero.
708def : Pat<(i32 (any_lround FPR32:$rs1)), (FCVT_W_S $rs1, FRM_RMM)>;
709
710// [u]int->float. Match GCC and default to using dynamic rounding mode.
711def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W $rs1, FRM_DYN)>;
712def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU $rs1, FRM_DYN)>;
713} // Predicates = [HasStdExtF]
714
715let Predicates = [HasStdExtZfinx] in {
716// float->[u]int. Round-to-zero must be used.
717def : Pat<(i32 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RTZ)>;
718def : Pat<(i32 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_WU_S_INX $rs1, FRM_RTZ)>;
719
720// Saturating float->[u]int32.
721def : Pat<(i32 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_W_S_INX $rs1, timm:$frm)>;
722def : Pat<(i32 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_WU_S_INX $rs1, timm:$frm)>;
723
724// float->int32 with current rounding mode.
725def : Pat<(i32 (any_lrint FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_DYN)>;
726
727// float->int32 rounded to nearest with ties rounded away from zero.
728def : Pat<(i32 (any_lround FPR32INX:$rs1)), (FCVT_W_S_INX $rs1, FRM_RMM)>;
729
730// [u]int->float. Match GCC and default to using dynamic rounding mode.
731def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W_INX $rs1, FRM_DYN)>;
732def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU_INX $rs1, FRM_DYN)>;
733} // Predicates = [HasStdExtZfinx]
734
735let Predicates = [HasStdExtF, IsRV64] in {
736// Moves (no conversion)
737def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (FMV_W_X GPR:$src)>;
738def : Pat<(riscv_fmv_x_anyextw_rv64 FPR32:$src), (FMV_X_W FPR32:$src)>;
739
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.
743def : Pat<(riscv_any_fcvt_w_rv64 FPR32:$rs1, timm:$frm),  (FCVT_W_S $rs1, timm:$frm)>;
744def : Pat<(riscv_any_fcvt_wu_rv64 FPR32:$rs1, timm:$frm), (FCVT_WU_S $rs1, timm:$frm)>;
745
746// float->[u]int64. Round-to-zero must be used.
747def : Pat<(i64 (any_fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RTZ)>;
748def : Pat<(i64 (any_fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, FRM_RTZ)>;
749
750// Saturating float->[u]int64.
751def : Pat<(i64 (riscv_fcvt_x FPR32:$rs1, timm:$frm)), (FCVT_L_S $rs1, timm:$frm)>;
752def : Pat<(i64 (riscv_fcvt_xu FPR32:$rs1, timm:$frm)), (FCVT_LU_S $rs1, timm:$frm)>;
753
754// float->int64 with current rounding mode.
755def : Pat<(i64 (any_lrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>;
756def : Pat<(i64 (any_llrint FPR32:$rs1)), (FCVT_L_S $rs1, FRM_DYN)>;
757
758// float->int64 rounded to neartest with ties rounded away from zero.
759def : Pat<(i64 (any_lround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>;
760def : Pat<(i64 (any_llround FPR32:$rs1)), (FCVT_L_S $rs1, FRM_RMM)>;
761
762// [u]int->fp. Match GCC and default to using dynamic rounding mode.
763def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W $rs1, FRM_DYN)>;
764def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU $rs1, FRM_DYN)>;
765def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L $rs1, FRM_DYN)>;
766def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU $rs1, FRM_DYN)>;
767} // Predicates = [HasStdExtF, IsRV64]
768
769let Predicates = [HasStdExtZfinx, IsRV64] in {
770// Moves (no conversion)
771def : Pat<(riscv_fmv_w_x_rv64 GPR:$src), (COPY_TO_REGCLASS GPR:$src, GPRF32)>;
772def : Pat<(riscv_fmv_x_anyextw_rv64 GPRF32:$src), (COPY_TO_REGCLASS GPRF32:$src, GPR)>;
773
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.
777def : Pat<(riscv_any_fcvt_w_rv64 FPR32INX:$rs1, timm:$frm),  (FCVT_W_S_INX $rs1, timm:$frm)>;
778def : Pat<(riscv_any_fcvt_wu_rv64 FPR32INX:$rs1, timm:$frm), (FCVT_WU_S_INX $rs1, timm:$frm)>;
779
780// float->[u]int64. Round-to-zero must be used.
781def : Pat<(i64 (any_fp_to_sint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_RTZ)>;
782def : Pat<(i64 (any_fp_to_uint FPR32INX:$rs1)), (FCVT_LU_S_INX $rs1, FRM_RTZ)>;
783
784// Saturating float->[u]int64.
785def : Pat<(i64 (riscv_fcvt_x FPR32INX:$rs1, timm:$frm)), (FCVT_L_S_INX $rs1, timm:$frm)>;
786def : Pat<(i64 (riscv_fcvt_xu FPR32INX:$rs1, timm:$frm)), (FCVT_LU_S_INX $rs1, timm:$frm)>;
787
788// float->int64 with current rounding mode.
789def : Pat<(i64 (any_lrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
790def : Pat<(i64 (any_llrint FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
791
792// float->int64 rounded to neartest with ties rounded away from zero.
793def : Pat<(i64 (any_lround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
794def : Pat<(i64 (any_llround FPR32INX:$rs1)), (FCVT_L_S_INX $rs1, FRM_DYN)>;
795
796// [u]int->fp. Match GCC and default to using dynamic rounding mode.
797def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W_INX $rs1, FRM_DYN)>;
798def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU_INX $rs1, FRM_DYN)>;
799def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_S_L_INX $rs1, FRM_DYN)>;
800def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_S_LU_INX $rs1, FRM_DYN)>;
801} // Predicates = [HasStdExtZfinx, IsRV64]
802