1//===-- RISCVInstrInfoD.td - RISC-V 'D' 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 'D',
10// Double-Precision Floating-Point instruction set extension.
11//
12//===----------------------------------------------------------------------===//
13
14//===----------------------------------------------------------------------===//
15// RISC-V specific DAG Nodes.
16//===----------------------------------------------------------------------===//
17
18def SDT_RISCVBuildPairF64 : SDTypeProfile<1, 2, [SDTCisVT<0, f64>,
19                                                 SDTCisVT<1, i32>,
20                                                 SDTCisSameAs<1, 2>]>;
21def SDT_RISCVSplitF64     : SDTypeProfile<2, 1, [SDTCisVT<0, i32>,
22                                                 SDTCisVT<1, i32>,
23                                                 SDTCisVT<2, f64>]>;
24
25def RISCVBuildPairF64 : SDNode<"RISCVISD::BuildPairF64", SDT_RISCVBuildPairF64>;
26def RISCVSplitF64     : SDNode<"RISCVISD::SplitF64", SDT_RISCVSplitF64>;
27
28def AddrRegImmINX : ComplexPattern<iPTR, 2, "SelectAddrRegImmINX">;
29
30//===----------------------------------------------------------------------===//
31// Operand and SDNode transformation definitions.
32//===----------------------------------------------------------------------===//
33
34// Zdinx
35
36def GPRPF64AsFPR : AsmOperandClass {
37  let Name = "GPRPF64AsFPR";
38  let ParserMethod = "parseGPRAsFPR";
39  let RenderMethod = "addRegOperands";
40}
41
42def GPRF64AsFPR : AsmOperandClass {
43  let Name = "GPRF64AsFPR";
44  let ParserMethod = "parseGPRAsFPR";
45  let RenderMethod = "addRegOperands";
46}
47
48def FPR64INX : RegisterOperand<GPR> {
49  let ParserMatchClass = GPRF64AsFPR;
50  let DecoderMethod = "DecodeGPRRegisterClass";
51}
52
53def FPR64IN32X : RegisterOperand<GPRPF64> {
54  let ParserMatchClass = GPRPF64AsFPR;
55}
56
57def DExt       : ExtInfo<"", "", [HasStdExtD], f64, FPR64, FPR32, FPR64, ?>;
58
59def ZdinxExt   : ExtInfo<"_INX", "RVZfinx", [HasStdExtZdinx, IsRV64],
60                         f64, FPR64INX, FPR32INX, FPR64INX, ?>;
61def Zdinx32Ext : ExtInfo<"_IN32X", "RV32Zdinx", [HasStdExtZdinx, IsRV32],
62                         f64, FPR64IN32X, FPR32INX, FPR64IN32X, ?>;
63
64defvar DExts     = [DExt, ZdinxExt, Zdinx32Ext];
65defvar DExtsRV64 = [DExt, ZdinxExt];
66
67//===----------------------------------------------------------------------===//
68// Instructions
69//===----------------------------------------------------------------------===//
70
71let Predicates = [HasStdExtD] in {
72def FLD : FPLoad_r<0b011, "fld", FPR64, WriteFLD64>;
73
74// Operands for stores are in the order srcreg, base, offset rather than
75// reflecting the order these fields are specified in the instruction
76// encoding.
77def FSD : FPStore_r<0b011, "fsd", FPR64, WriteFST64>;
78} // Predicates = [HasStdExtD]
79
80foreach Ext = DExts in {
81  let SchedRW = [WriteFMA64, ReadFMA64, ReadFMA64, ReadFMA64] in {
82    defm FMADD_D  : FPFMA_rrr_frm_m<OPC_MADD,  0b01, "fmadd.d",  Ext>;
83    defm FMSUB_D  : FPFMA_rrr_frm_m<OPC_MSUB,  0b01, "fmsub.d",  Ext>;
84    defm FNMSUB_D : FPFMA_rrr_frm_m<OPC_NMSUB, 0b01, "fnmsub.d", Ext>;
85    defm FNMADD_D : FPFMA_rrr_frm_m<OPC_NMADD, 0b01, "fnmadd.d", Ext>;
86  }
87
88  let SchedRW = [WriteFAdd64, ReadFAdd64, ReadFAdd64] in {
89    defm FADD_D : FPALU_rr_frm_m<0b0000001, "fadd.d", Ext, Commutable=1>;
90    defm FSUB_D : FPALU_rr_frm_m<0b0000101, "fsub.d", Ext>;
91  }
92  let SchedRW = [WriteFMul64, ReadFMul64, ReadFMul64] in
93  defm FMUL_D : FPALU_rr_frm_m<0b0001001, "fmul.d", Ext, Commutable=1>;
94
95  let SchedRW = [WriteFDiv64, ReadFDiv64, ReadFDiv64] in
96  defm FDIV_D : FPALU_rr_frm_m<0b0001101, "fdiv.d", Ext>;
97
98  defm FSQRT_D : FPUnaryOp_r_frm_m<0b0101101, 0b00000, Ext, Ext.PrimaryTy,
99                                   Ext.PrimaryTy, "fsqrt.d">,
100                 Sched<[WriteFSqrt64, ReadFSqrt64]>;
101
102  let SchedRW = [WriteFSGNJ64, ReadFSGNJ64, ReadFSGNJ64],
103      mayRaiseFPException = 0 in {
104    defm FSGNJ_D  : FPALU_rr_m<0b0010001, 0b000, "fsgnj.d",  Ext>;
105    defm FSGNJN_D : FPALU_rr_m<0b0010001, 0b001, "fsgnjn.d", Ext>;
106    defm FSGNJX_D : FPALU_rr_m<0b0010001, 0b010, "fsgnjx.d", Ext>;
107  }
108
109  let SchedRW = [WriteFMinMax64, ReadFMinMax64, ReadFMinMax64] in {
110    defm FMIN_D   : FPALU_rr_m<0b0010101, 0b000, "fmin.d", Ext, Commutable=1>;
111    defm FMAX_D   : FPALU_rr_m<0b0010101, 0b001, "fmax.d", Ext, Commutable=1>;
112  }
113
114  defm FCVT_S_D : FPUnaryOp_r_frm_m<0b0100000, 0b00001, Ext, Ext.F32Ty,
115                                    Ext.PrimaryTy, "fcvt.s.d">,
116                  Sched<[WriteFCvtF64ToF32, ReadFCvtF64ToF32]>;
117
118  defm FCVT_D_S : FPUnaryOp_r_m<0b0100001, 0b00000, 0b000, Ext, Ext.PrimaryTy,
119                                Ext.F32Ty, "fcvt.d.s">,
120                  Sched<[WriteFCvtF32ToF64, ReadFCvtF32ToF64]>;
121
122  let SchedRW = [WriteFCmp64, ReadFCmp64, ReadFCmp64] in {
123    defm FEQ_D : FPCmp_rr_m<0b1010001, 0b010, "feq.d", Ext, Commutable=1>;
124    defm FLT_D : FPCmp_rr_m<0b1010001, 0b001, "flt.d", Ext>;
125    defm FLE_D : FPCmp_rr_m<0b1010001, 0b000, "fle.d", Ext>;
126  }
127
128  let mayRaiseFPException = 0 in
129  defm FCLASS_D : FPUnaryOp_r_m<0b1110001, 0b00000, 0b001, Ext, GPR, Ext.PrimaryTy,
130                                "fclass.d">,
131                  Sched<[WriteFClass64, ReadFClass64]>;
132
133  let IsSignExtendingOpW = 1 in
134  defm FCVT_W_D : FPUnaryOp_r_frm_m<0b1100001, 0b00000, Ext, GPR, Ext.PrimaryTy,
135                                    "fcvt.w.d">,
136                 Sched<[WriteFCvtF64ToI32, ReadFCvtF64ToI32]>;
137
138  let IsSignExtendingOpW = 1 in
139  defm FCVT_WU_D : FPUnaryOp_r_frm_m<0b1100001, 0b00001, Ext, GPR, Ext.PrimaryTy,
140                                     "fcvt.wu.d">,
141                   Sched<[WriteFCvtF64ToI32, ReadFCvtF64ToI32]>;
142
143  defm FCVT_D_W : FPUnaryOp_r_m<0b1101001, 0b00000, 0b000, Ext, Ext.PrimaryTy, GPR,
144                                "fcvt.d.w">,
145                  Sched<[WriteFCvtI32ToF64, ReadFCvtI32ToF64]>;
146
147  defm FCVT_D_WU : FPUnaryOp_r_m<0b1101001, 0b00001, 0b000, Ext, Ext.PrimaryTy, GPR,
148                                 "fcvt.d.wu">,
149                   Sched<[WriteFCvtI32ToF64, ReadFCvtI32ToF64]>;
150} // foreach Ext = DExts
151
152foreach Ext = DExtsRV64 in {
153  defm FCVT_L_D : FPUnaryOp_r_frm_m<0b1100001, 0b00010, Ext, GPR, Ext.PrimaryTy,
154                                    "fcvt.l.d", [IsRV64]>,
155                  Sched<[WriteFCvtF64ToI64, ReadFCvtF64ToI64]>;
156
157  defm FCVT_LU_D : FPUnaryOp_r_frm_m<0b1100001, 0b00011, Ext, GPR, Ext.PrimaryTy,
158                                     "fcvt.lu.d", [IsRV64]>,
159                   Sched<[WriteFCvtF64ToI64, ReadFCvtF64ToI64]>;
160
161  defm FCVT_D_L : FPUnaryOp_r_frm_m<0b1101001, 0b00010, Ext, Ext.PrimaryTy, GPR,
162                                    "fcvt.d.l", [IsRV64]>,
163                  Sched<[WriteFCvtI64ToF64, ReadFCvtI64ToF64]>;
164
165  defm FCVT_D_LU : FPUnaryOp_r_frm_m<0b1101001, 0b00011, Ext, Ext.PrimaryTy, GPR,
166                                     "fcvt.d.lu", [IsRV64]>,
167                   Sched<[WriteFCvtI64ToF64, ReadFCvtI64ToF64]>;
168} // foreach Ext = DExts64
169
170let Predicates = [HasStdExtD, IsRV64], mayRaiseFPException = 0 in
171def FMV_X_D : FPUnaryOp_r<0b1110001, 0b00000, 0b000, GPR, FPR64, "fmv.x.d">,
172              Sched<[WriteFMovF64ToI64, ReadFMovF64ToI64]>;
173
174let Predicates = [HasStdExtD, IsRV64], mayRaiseFPException = 0 in
175def FMV_D_X : FPUnaryOp_r<0b1111001, 0b00000, 0b000, FPR64, GPR, "fmv.d.x">,
176              Sched<[WriteFMovI64ToF64, ReadFMovI64ToF64]>;
177
178//===----------------------------------------------------------------------===//
179// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
180//===----------------------------------------------------------------------===//
181
182let Predicates = [HasStdExtD] in {
183def : InstAlias<"fld $rd, (${rs1})",  (FLD FPR64:$rd,  GPR:$rs1, 0), 0>;
184def : InstAlias<"fsd $rs2, (${rs1})", (FSD FPR64:$rs2, GPR:$rs1, 0), 0>;
185
186def : InstAlias<"fmv.d $rd, $rs",  (FSGNJ_D  FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
187def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
188def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
189
190// fgt.d/fge.d are recognised by the GNU assembler but the canonical
191// flt.d/fle.d forms will always be printed. Therefore, set a zero weight.
192def : InstAlias<"fgt.d $rd, $rs, $rt",
193                (FLT_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
194def : InstAlias<"fge.d $rd, $rs, $rt",
195                (FLE_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
196
197def PseudoFLD  : PseudoFloatLoad<"fld", FPR64>;
198def PseudoFSD  : PseudoStore<"fsd", FPR64>;
199let usesCustomInserter = 1 in {
200def PseudoQuietFLE_D : PseudoQuietFCMP<FPR64>;
201def PseudoQuietFLT_D : PseudoQuietFCMP<FPR64>;
202}
203} // Predicates = [HasStdExtD]
204
205let Predicates = [HasStdExtZdinx, IsRV64] in {
206def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D_INX FPR64INX:$rd, FPR64INX:$rs, FPR64INX:$rs)>;
207def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D_INX FPR64INX:$rd, FPR64INX:$rs, FPR64INX:$rs)>;
208
209def : InstAlias<"fgt.d $rd, $rs, $rt",
210                (FLT_D_INX GPR:$rd, FPR64INX:$rt, FPR64INX:$rs), 0>;
211def : InstAlias<"fge.d $rd, $rs, $rt",
212                (FLE_D_INX GPR:$rd, FPR64INX:$rt, FPR64INX:$rs), 0>;
213let usesCustomInserter = 1 in {
214def PseudoQuietFLE_D_INX : PseudoQuietFCMP<FPR64INX>;
215def PseudoQuietFLT_D_INX : PseudoQuietFCMP<FPR64INX>;
216}
217} // Predicates = [HasStdExtZdinx, IsRV64]
218
219let Predicates = [HasStdExtZdinx, IsRV32] in {
220def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D_IN32X FPR64IN32X:$rd, FPR64IN32X:$rs, FPR64IN32X:$rs)>;
221def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D_IN32X FPR64IN32X:$rd, FPR64IN32X:$rs, FPR64IN32X:$rs)>;
222
223def : InstAlias<"fgt.d $rd, $rs, $rt",
224                (FLT_D_IN32X GPR:$rd, FPR64IN32X:$rt, FPR64IN32X:$rs), 0>;
225def : InstAlias<"fge.d $rd, $rs, $rt",
226                (FLE_D_IN32X GPR:$rd, FPR64IN32X:$rt, FPR64IN32X:$rs), 0>;
227let usesCustomInserter = 1 in {
228def PseudoQuietFLE_D_IN32X : PseudoQuietFCMP<FPR64IN32X>;
229def PseudoQuietFLT_D_IN32X : PseudoQuietFCMP<FPR64IN32X>;
230}
231} // Predicates = [HasStdExtZdinx, IsRV32]
232
233//===----------------------------------------------------------------------===//
234// Pseudo-instructions and codegen patterns
235//===----------------------------------------------------------------------===//
236
237let Predicates = [HasStdExtD] in {
238
239/// Float conversion operations
240
241// f64 -> f32, f32 -> f64
242def : Pat<(any_fpround FPR64:$rs1), (FCVT_S_D FPR64:$rs1, FRM_DYN)>;
243def : Pat<(any_fpextend FPR32:$rs1), (FCVT_D_S FPR32:$rs1)>;
244} // Predicates = [HasStdExtD]
245
246let Predicates = [HasStdExtZdinx, IsRV64] in {
247/// Float conversion operations
248
249// f64 -> f32, f32 -> f64
250def : Pat<(any_fpround FPR64INX:$rs1), (FCVT_S_D_INX FPR64INX:$rs1, FRM_DYN)>;
251def : Pat<(any_fpextend FPR32INX:$rs1), (FCVT_D_S_INX FPR32INX:$rs1)>;
252} // Predicates = [HasStdExtZdinx, IsRV64]
253
254let Predicates = [HasStdExtZdinx, IsRV32] in {
255/// Float conversion operations
256
257// f64 -> f32, f32 -> f64
258def : Pat<(any_fpround FPR64IN32X:$rs1), (FCVT_S_D_IN32X FPR64IN32X:$rs1, FRM_DYN)>;
259def : Pat<(any_fpextend FPR32INX:$rs1), (FCVT_D_S_IN32X FPR32INX:$rs1)>;
260} // Predicates = [HasStdExtZdinx, IsRV32]
261
262// [u]int<->double conversion patterns must be gated on IsRV32 or IsRV64, so
263// are defined later.
264
265/// Float arithmetic operations
266
267foreach Ext = DExts in {
268  defm : PatFprFprDynFrm_m<any_fadd, FADD_D, Ext>;
269  defm : PatFprFprDynFrm_m<any_fsub, FSUB_D, Ext>;
270  defm : PatFprFprDynFrm_m<any_fmul, FMUL_D, Ext>;
271  defm : PatFprFprDynFrm_m<any_fdiv, FDIV_D, Ext>;
272}
273
274let Predicates = [HasStdExtD] in {
275def : Pat<(any_fsqrt FPR64:$rs1), (FSQRT_D FPR64:$rs1, FRM_DYN)>;
276
277def : Pat<(fneg FPR64:$rs1), (FSGNJN_D $rs1, $rs1)>;
278def : Pat<(fabs FPR64:$rs1), (FSGNJX_D $rs1, $rs1)>;
279
280def : Pat<(riscv_fpclass FPR64:$rs1), (FCLASS_D $rs1)>;
281
282def : PatFprFpr<fcopysign, FSGNJ_D, FPR64, f64>;
283def : Pat<(fcopysign FPR64:$rs1, (fneg FPR64:$rs2)), (FSGNJN_D $rs1, $rs2)>;
284def : Pat<(fcopysign FPR64:$rs1, FPR32:$rs2), (FSGNJ_D $rs1, (FCVT_D_S $rs2))>;
285def : Pat<(fcopysign FPR32:$rs1, FPR64:$rs2), (FSGNJ_S $rs1, (FCVT_S_D $rs2,
286                                                              FRM_DYN))>;
287
288// fmadd: rs1 * rs2 + rs3
289def : Pat<(any_fma FPR64:$rs1, FPR64:$rs2, FPR64:$rs3),
290          (FMADD_D $rs1, $rs2, $rs3, FRM_DYN)>;
291
292// fmsub: rs1 * rs2 - rs3
293def : Pat<(any_fma FPR64:$rs1, FPR64:$rs2, (fneg FPR64:$rs3)),
294          (FMSUB_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, FRM_DYN)>;
295
296// fnmsub: -rs1 * rs2 + rs3
297def : Pat<(any_fma (fneg FPR64:$rs1), FPR64:$rs2, FPR64:$rs3),
298          (FNMSUB_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, FRM_DYN)>;
299
300// fnmadd: -rs1 * rs2 - rs3
301def : Pat<(any_fma (fneg FPR64:$rs1), FPR64:$rs2, (fneg FPR64:$rs3)),
302          (FNMADD_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, FRM_DYN)>;
303
304// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
305def : Pat<(fneg (any_fma_nsz FPR64:$rs1, FPR64:$rs2, FPR64:$rs3)),
306          (FNMADD_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, FRM_DYN)>;
307} // Predicates = [HasStdExtD]
308
309let Predicates = [HasStdExtZdinx, IsRV64] in {
310def : Pat<(any_fsqrt FPR64INX:$rs1), (FSQRT_D_INX FPR64INX:$rs1, FRM_DYN)>;
311
312def : Pat<(fneg FPR64INX:$rs1), (FSGNJN_D_INX $rs1, $rs1)>;
313def : Pat<(fabs FPR64INX:$rs1), (FSGNJX_D_INX $rs1, $rs1)>;
314
315def : Pat<(riscv_fpclass FPR64INX:$rs1), (FCLASS_D_INX $rs1)>;
316
317def : PatFprFpr<fcopysign, FSGNJ_D_INX, FPR64INX, f64>;
318def : Pat<(fcopysign FPR64INX:$rs1, (fneg FPR64INX:$rs2)),
319          (FSGNJN_D_INX $rs1, $rs2)>;
320def : Pat<(fcopysign FPR64INX:$rs1, FPR32INX:$rs2),
321          (FSGNJ_D_INX $rs1, (FCVT_D_S_INX $rs2))>;
322def : Pat<(fcopysign FPR32INX:$rs1, FPR64INX:$rs2),
323          (FSGNJ_S_INX $rs1, (FCVT_S_D_INX $rs2, FRM_DYN))>;
324
325// fmadd: rs1 * rs2 + rs3
326def : Pat<(any_fma FPR64INX:$rs1, FPR64INX:$rs2, FPR64INX:$rs3),
327          (FMADD_D_INX $rs1, $rs2, $rs3, FRM_DYN)>;
328
329// fmsub: rs1 * rs2 - rs3
330def : Pat<(any_fma FPR64INX:$rs1, FPR64INX:$rs2, (fneg FPR64INX:$rs3)),
331          (FMSUB_D_INX FPR64INX:$rs1, FPR64INX:$rs2, FPR64INX:$rs3, FRM_DYN)>;
332
333// fnmsub: -rs1 * rs2 + rs3
334def : Pat<(any_fma (fneg FPR64INX:$rs1), FPR64INX:$rs2, FPR64INX:$rs3),
335          (FNMSUB_D_INX FPR64INX:$rs1, FPR64INX:$rs2, FPR64INX:$rs3, FRM_DYN)>;
336
337// fnmadd: -rs1 * rs2 - rs3
338def : Pat<(any_fma (fneg FPR64INX:$rs1), FPR64INX:$rs2, (fneg FPR64INX:$rs3)),
339          (FNMADD_D_INX FPR64INX:$rs1, FPR64INX:$rs2, FPR64INX:$rs3, FRM_DYN)>;
340
341// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
342def : Pat<(fneg (any_fma_nsz FPR64INX:$rs1, FPR64INX:$rs2, FPR64INX:$rs3)),
343          (FNMADD_D_INX FPR64INX:$rs1, FPR64INX:$rs2, FPR64INX:$rs3, FRM_DYN)>;
344} // Predicates = [HasStdExtZdinx, IsRV64]
345
346let Predicates = [HasStdExtZdinx, IsRV32] in {
347def : Pat<(any_fsqrt FPR64IN32X:$rs1), (FSQRT_D_IN32X FPR64IN32X:$rs1, FRM_DYN)>;
348
349def : Pat<(fneg FPR64IN32X:$rs1), (FSGNJN_D_IN32X $rs1, $rs1)>;
350def : Pat<(fabs FPR64IN32X:$rs1), (FSGNJX_D_IN32X $rs1, $rs1)>;
351
352def : Pat<(riscv_fpclass FPR64IN32X:$rs1), (FCLASS_D_IN32X $rs1)>;
353
354def : PatFprFpr<fcopysign, FSGNJ_D_IN32X, FPR64IN32X, f64>;
355def : Pat<(fcopysign FPR64IN32X:$rs1, (fneg FPR64IN32X:$rs2)),
356          (FSGNJN_D_IN32X $rs1, $rs2)>;
357def : Pat<(fcopysign FPR64IN32X:$rs1, FPR32INX:$rs2),
358          (FSGNJ_D_IN32X $rs1, (FCVT_D_S_INX $rs2))>;
359def : Pat<(fcopysign FPR32INX:$rs1, FPR64IN32X:$rs2),
360          (FSGNJ_S_INX $rs1, (FCVT_S_D_IN32X $rs2, FRM_DYN))>;
361
362// fmadd: rs1 * rs2 + rs3
363def : Pat<(any_fma FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3),
364          (FMADD_D_IN32X $rs1, $rs2, $rs3, FRM_DYN)>;
365
366// fmsub: rs1 * rs2 - rs3
367def : Pat<(any_fma FPR64IN32X:$rs1, FPR64IN32X:$rs2, (fneg FPR64IN32X:$rs3)),
368          (FMSUB_D_IN32X FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3, FRM_DYN)>;
369
370// fnmsub: -rs1 * rs2 + rs3
371def : Pat<(any_fma (fneg FPR64IN32X:$rs1), FPR64IN32X:$rs2, FPR64IN32X:$rs3),
372          (FNMSUB_D_IN32X FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3, FRM_DYN)>;
373
374// fnmadd: -rs1 * rs2 - rs3
375def : Pat<(any_fma (fneg FPR64IN32X:$rs1), FPR64IN32X:$rs2, (fneg FPR64IN32X:$rs3)),
376          (FNMADD_D_IN32X FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3, FRM_DYN)>;
377
378// fnmadd: -(rs1 * rs2 + rs3) (the nsz flag on the FMA)
379def : Pat<(fneg (any_fma_nsz FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3)),
380          (FNMADD_D_IN32X FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3, FRM_DYN)>;
381} // Predicates = [HasStdExtZdinx, IsRV32]
382
383// The ratified 20191213 ISA spec defines fmin and fmax in a way that matches
384// LLVM's fminnum and fmaxnum.
385// <https://github.com/riscv/riscv-isa-manual/commit/cd20cee7efd9bac7c5aa127ec3b451749d2b3cce>.
386foreach Ext = DExts in {
387  defm : PatFprFpr_m<fminnum, FMIN_D, Ext>;
388  defm : PatFprFpr_m<fmaxnum, FMAX_D, Ext>;
389  defm : PatFprFpr_m<riscv_fmin, FMIN_D, Ext>;
390  defm : PatFprFpr_m<riscv_fmax, FMAX_D, Ext>;
391}
392
393/// Setcc
394// FIXME: SETEQ/SETLT/SETLE imply nonans, can we pick better instructions for
395// strict versions of those.
396
397// Match non-signaling FEQ_D
398foreach Ext = DExts in {
399  defm : PatSetCC_m<any_fsetcc,    SETEQ,  FEQ_D,            Ext, f64>;
400  defm : PatSetCC_m<any_fsetcc,    SETOEQ, FEQ_D,            Ext, f64>;
401  defm : PatSetCC_m<strict_fsetcc, SETLT,  PseudoQuietFLT_D, Ext, f64>;
402  defm : PatSetCC_m<strict_fsetcc, SETOLT, PseudoQuietFLT_D, Ext, f64>;
403  defm : PatSetCC_m<strict_fsetcc, SETLE,  PseudoQuietFLE_D, Ext, f64>;
404  defm : PatSetCC_m<strict_fsetcc, SETOLE, PseudoQuietFLE_D, Ext, f64>;
405}
406
407let Predicates = [HasStdExtD] in {
408// Match signaling FEQ_D
409def : Pat<(XLenVT (strict_fsetccs FPR64:$rs1, FPR64:$rs2, SETEQ)),
410          (AND (FLE_D $rs1, $rs2),
411               (FLE_D $rs2, $rs1))>;
412def : Pat<(XLenVT (strict_fsetccs FPR64:$rs1, FPR64:$rs2, SETOEQ)),
413          (AND (FLE_D $rs1, $rs2),
414               (FLE_D $rs2, $rs1))>;
415// If both operands are the same, use a single FLE.
416def : Pat<(XLenVT (strict_fsetccs FPR64:$rs1, FPR64:$rs1, SETEQ)),
417          (FLE_D $rs1, $rs1)>;
418def : Pat<(XLenVT (strict_fsetccs FPR64:$rs1, FPR64:$rs1, SETOEQ)),
419          (FLE_D $rs1, $rs1)>;
420
421def : PatSetCC<FPR64, any_fsetccs, SETLT, FLT_D, f64>;
422def : PatSetCC<FPR64, any_fsetccs, SETOLT, FLT_D, f64>;
423def : PatSetCC<FPR64, any_fsetccs, SETLE, FLE_D, f64>;
424def : PatSetCC<FPR64, any_fsetccs, SETOLE, FLE_D, f64>;
425} // Predicates = [HasStdExtD]
426
427let Predicates = [HasStdExtZdinx, IsRV64] in {
428// Match signaling FEQ_D
429def : Pat<(XLenVT (strict_fsetccs (f64 FPR64INX:$rs1), FPR64INX:$rs2, SETEQ)),
430          (AND (FLE_D_INX $rs1, $rs2),
431               (FLE_D_INX $rs2, $rs1))>;
432def : Pat<(XLenVT (strict_fsetccs (f64 FPR64INX:$rs1), FPR64INX:$rs2, SETOEQ)),
433          (AND (FLE_D_INX $rs1, $rs2),
434               (FLE_D_INX $rs2, $rs1))>;
435// If both operands are the same, use a single FLE.
436def : Pat<(XLenVT (strict_fsetccs (f64 FPR64INX:$rs1), FPR64INX:$rs1, SETEQ)),
437          (FLE_D_INX $rs1, $rs1)>;
438def : Pat<(XLenVT (strict_fsetccs (f64 FPR64INX:$rs1), FPR64INX:$rs1, SETOEQ)),
439          (FLE_D_INX $rs1, $rs1)>;
440
441def : PatSetCC<FPR64INX, any_fsetccs, SETLT,  FLT_D_INX, f64>;
442def : PatSetCC<FPR64INX, any_fsetccs, SETOLT, FLT_D_INX, f64>;
443def : PatSetCC<FPR64INX, any_fsetccs, SETLE,  FLE_D_INX, f64>;
444def : PatSetCC<FPR64INX, any_fsetccs, SETOLE, FLE_D_INX, f64>;
445} // Predicates = [HasStdExtZdinx, IsRV64]
446
447let Predicates = [HasStdExtZdinx, IsRV32] in {
448// Match signaling FEQ_D
449def : Pat<(XLenVT (strict_fsetccs FPR64IN32X:$rs1, FPR64IN32X:$rs2, SETEQ)),
450          (AND (FLE_D_IN32X $rs1, $rs2),
451               (FLE_D_IN32X $rs2, $rs1))>;
452def : Pat<(XLenVT (strict_fsetccs FPR64IN32X:$rs1, FPR64IN32X:$rs2, SETOEQ)),
453          (AND (FLE_D_IN32X $rs1, $rs2),
454               (FLE_D_IN32X $rs2, $rs1))>;
455// If both operands are the same, use a single FLE.
456def : Pat<(XLenVT (strict_fsetccs FPR64IN32X:$rs1, FPR64IN32X:$rs1, SETEQ)),
457          (FLE_D_IN32X $rs1, $rs1)>;
458def : Pat<(XLenVT (strict_fsetccs FPR64IN32X:$rs1, FPR64IN32X:$rs1, SETOEQ)),
459          (FLE_D_IN32X $rs1, $rs1)>;
460
461def : PatSetCC<FPR64IN32X, any_fsetccs, SETLT,  FLT_D_IN32X, f64>;
462def : PatSetCC<FPR64IN32X, any_fsetccs, SETOLT, FLT_D_IN32X, f64>;
463def : PatSetCC<FPR64IN32X, any_fsetccs, SETLE,  FLE_D_IN32X, f64>;
464def : PatSetCC<FPR64IN32X, any_fsetccs, SETOLE, FLE_D_IN32X, f64>;
465} // Predicates = [HasStdExtZdinx, IsRV32]
466
467let Predicates = [HasStdExtD] in {
468defm Select_FPR64 : SelectCC_GPR_rrirr<FPR64, f64>;
469
470def PseudoFROUND_D : PseudoFROUND<FPR64, f64>;
471
472/// Loads
473
474def : LdPat<load, FLD, f64>;
475
476/// Stores
477
478def : StPat<store, FSD, FPR64, f64>;
479
480/// Pseudo-instructions needed for the soft-float ABI with RV32D
481
482// Moves two GPRs to an FPR.
483let usesCustomInserter = 1 in
484def BuildPairF64Pseudo
485    : Pseudo<(outs FPR64:$dst), (ins GPR:$src1, GPR:$src2),
486             [(set FPR64:$dst, (RISCVBuildPairF64 GPR:$src1, GPR:$src2))]>;
487
488// Moves an FPR to two GPRs.
489let usesCustomInserter = 1 in
490def SplitF64Pseudo
491    : Pseudo<(outs GPR:$dst1, GPR:$dst2), (ins FPR64:$src),
492             [(set GPR:$dst1, GPR:$dst2, (RISCVSplitF64 FPR64:$src))]>;
493
494} // Predicates = [HasStdExtD]
495
496let Predicates = [HasStdExtZdinx, IsRV64] in {
497defm Select_FPR64INX : SelectCC_GPR_rrirr<FPR64INX, f64>;
498
499def PseudoFROUND_D_INX : PseudoFROUND<FPR64INX, f64>;
500
501/// Loads
502def : LdPat<load, LD, f64>;
503
504/// Stores
505def : StPat<store, SD, GPR, f64>;
506} // Predicates = [HasStdExtZdinx, IsRV64]
507
508let Predicates = [HasStdExtZdinx, IsRV32] in {
509defm Select_FPR64IN32X : SelectCC_GPR_rrirr<FPR64IN32X, f64>;
510
511def PseudoFROUND_D_IN32X : PseudoFROUND<FPR64IN32X, f64>;
512
513/// Loads
514let isCall = 0, mayLoad = 1, mayStore = 0, Size = 8, isCodeGenOnly = 1 in
515def PseudoRV32ZdinxLD : Pseudo<(outs GPRPF64:$dst), (ins GPR:$rs1, simm12:$imm12), []>;
516def : Pat<(f64 (load (AddrRegImmINX (XLenVT GPR:$rs1), simm12:$imm12))),
517          (PseudoRV32ZdinxLD GPR:$rs1, simm12:$imm12)>;
518
519/// Stores
520let isCall = 0, mayLoad = 0, mayStore = 1, Size = 8, isCodeGenOnly = 1 in
521def PseudoRV32ZdinxSD : Pseudo<(outs), (ins GPRPF64:$rs2, GPRNoX0:$rs1, simm12:$imm12), []>;
522def : Pat<(store (f64 GPRPF64:$rs2), (AddrRegImmINX (XLenVT GPR:$rs1), simm12:$imm12)),
523          (PseudoRV32ZdinxSD GPRPF64:$rs2, GPR:$rs1, simm12:$imm12)>;
524
525/// Pseudo-instructions needed for the soft-float ABI with RV32D
526
527// Moves two GPRs to an FPR.
528let usesCustomInserter = 1 in
529def BuildPairF64Pseudo_INX
530    : Pseudo<(outs FPR64IN32X:$dst), (ins GPR:$src1, GPR:$src2),
531             [(set FPR64IN32X:$dst, (RISCVBuildPairF64 GPR:$src1, GPR:$src2))]>;
532
533// Moves an FPR to two GPRs.
534let usesCustomInserter = 1 in
535def SplitF64Pseudo_INX
536    : Pseudo<(outs GPR:$dst1, GPR:$dst2), (ins FPR64IN32X:$src),
537             [(set GPR:$dst1, GPR:$dst2, (RISCVSplitF64 FPR64IN32X:$src))]>;
538} // Predicates = [HasStdExtZdinx, IsRV32]
539
540let Predicates = [HasStdExtD, IsRV32] in {
541
542// double->[u]int. Round-to-zero must be used.
543def : Pat<(i32 (any_fp_to_sint FPR64:$rs1)), (FCVT_W_D FPR64:$rs1, FRM_RTZ)>;
544def : Pat<(i32 (any_fp_to_uint FPR64:$rs1)), (FCVT_WU_D FPR64:$rs1, FRM_RTZ)>;
545
546// Saturating double->[u]int32.
547def : Pat<(i32 (riscv_fcvt_x FPR64:$rs1, timm:$frm)), (FCVT_W_D $rs1, timm:$frm)>;
548def : Pat<(i32 (riscv_fcvt_xu FPR64:$rs1, timm:$frm)), (FCVT_WU_D $rs1, timm:$frm)>;
549
550// float->int32 with current rounding mode.
551def : Pat<(i32 (any_lrint FPR64:$rs1)), (FCVT_W_D $rs1, FRM_DYN)>;
552
553// float->int32 rounded to nearest with ties rounded away from zero.
554def : Pat<(i32 (any_lround FPR64:$rs1)), (FCVT_W_D $rs1, FRM_RMM)>;
555
556// [u]int->double.
557def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_D_W GPR:$rs1)>;
558def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_D_WU GPR:$rs1)>;
559} // Predicates = [HasStdExtD, IsRV32]
560
561let Predicates = [HasStdExtZdinx, IsRV32] in {
562
563// double->[u]int. Round-to-zero must be used.
564def : Pat<(i32 (any_fp_to_sint FPR64IN32X:$rs1)), (FCVT_W_D_IN32X FPR64IN32X:$rs1, FRM_RTZ)>;
565def : Pat<(i32 (any_fp_to_uint FPR64IN32X:$rs1)), (FCVT_WU_D_IN32X FPR64IN32X:$rs1, FRM_RTZ)>;
566
567// Saturating double->[u]int32.
568def : Pat<(i32 (riscv_fcvt_x FPR64IN32X:$rs1, timm:$frm)), (FCVT_W_D_IN32X $rs1, timm:$frm)>;
569def : Pat<(i32 (riscv_fcvt_xu FPR64IN32X:$rs1, timm:$frm)), (FCVT_WU_D_IN32X $rs1, timm:$frm)>;
570
571// float->int32 with current rounding mode.
572def : Pat<(i32 (any_lrint FPR64IN32X:$rs1)), (FCVT_W_D_IN32X $rs1, FRM_DYN)>;
573
574// float->int32 rounded to nearest with ties rounded away from zero.
575def : Pat<(i32 (any_lround FPR64IN32X:$rs1)), (FCVT_W_D_IN32X $rs1, FRM_RMM)>;
576
577// [u]int->double.
578def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_D_W_IN32X GPR:$rs1)>;
579def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_D_WU_IN32X GPR:$rs1)>;
580} // Predicates = [HasStdExtZdinx, IsRV32]
581
582let Predicates = [HasStdExtD, IsRV64] in {
583
584// Moves (no conversion)
585def : Pat<(bitconvert (i64 GPR:$rs1)), (FMV_D_X GPR:$rs1)>;
586def : Pat<(i64 (bitconvert FPR64:$rs1)), (FMV_X_D FPR64:$rs1)>;
587
588// Use target specific isd nodes to help us remember the result is sign
589// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be
590// duplicated if it has another user that didn't need the sign_extend.
591def : Pat<(riscv_any_fcvt_w_rv64 FPR64:$rs1, timm:$frm),  (FCVT_W_D $rs1, timm:$frm)>;
592def : Pat<(riscv_any_fcvt_wu_rv64 FPR64:$rs1, timm:$frm), (FCVT_WU_D $rs1, timm:$frm)>;
593
594// [u]int32->fp
595def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_D_W $rs1)>;
596def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_D_WU $rs1)>;
597
598// Saturating double->[u]int64.
599def : Pat<(i64 (riscv_fcvt_x FPR64:$rs1, timm:$frm)), (FCVT_L_D $rs1, timm:$frm)>;
600def : Pat<(i64 (riscv_fcvt_xu FPR64:$rs1, timm:$frm)), (FCVT_LU_D $rs1, timm:$frm)>;
601
602// double->[u]int64. Round-to-zero must be used.
603def : Pat<(i64 (any_fp_to_sint FPR64:$rs1)), (FCVT_L_D FPR64:$rs1, FRM_RTZ)>;
604def : Pat<(i64 (any_fp_to_uint FPR64:$rs1)), (FCVT_LU_D FPR64:$rs1, FRM_RTZ)>;
605
606// double->int64 with current rounding mode.
607def : Pat<(i64 (any_lrint FPR64:$rs1)), (FCVT_L_D $rs1, FRM_DYN)>;
608def : Pat<(i64 (any_llrint FPR64:$rs1)), (FCVT_L_D $rs1, FRM_DYN)>;
609
610// double->int64 rounded to nearest with ties rounded away from zero.
611def : Pat<(i64 (any_lround FPR64:$rs1)), (FCVT_L_D $rs1, FRM_RMM)>;
612def : Pat<(i64 (any_llround FPR64:$rs1)), (FCVT_L_D $rs1, FRM_RMM)>;
613
614// [u]int64->fp. Match GCC and default to using dynamic rounding mode.
615def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_D_L GPR:$rs1, FRM_DYN)>;
616def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_D_LU GPR:$rs1, FRM_DYN)>;
617} // Predicates = [HasStdExtD, IsRV64]
618
619let Predicates = [HasStdExtZdinx, IsRV64] in {
620
621// Moves (no conversion)
622def : Pat<(f64 (bitconvert (i64 GPR:$rs1))), (COPY_TO_REGCLASS GPR:$rs1, GPR)>;
623def : Pat<(i64 (bitconvert (f64 GPR:$rs1))), (COPY_TO_REGCLASS GPR:$rs1, GPR)>;
624
625// Use target specific isd nodes to help us remember the result is sign
626// extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be
627// duplicated if it has another user that didn't need the sign_extend.
628def : Pat<(riscv_any_fcvt_w_rv64 FPR64INX:$rs1, timm:$frm),  (FCVT_W_D_INX $rs1, timm:$frm)>;
629def : Pat<(riscv_any_fcvt_wu_rv64 FPR64INX:$rs1, timm:$frm), (FCVT_WU_D_INX $rs1, timm:$frm)>;
630
631// [u]int32->fp
632def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_D_W_INX $rs1)>;
633def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_D_WU_INX $rs1)>;
634
635// Saturating double->[u]int64.
636def : Pat<(i64 (riscv_fcvt_x FPR64INX:$rs1, timm:$frm)), (FCVT_L_D_INX $rs1, timm:$frm)>;
637def : Pat<(i64 (riscv_fcvt_xu FPR64INX:$rs1, timm:$frm)), (FCVT_LU_D_INX $rs1, timm:$frm)>;
638
639// double->[u]int64. Round-to-zero must be used.
640def : Pat<(i64 (any_fp_to_sint FPR64INX:$rs1)), (FCVT_L_D_INX FPR64INX:$rs1, FRM_RTZ)>;
641def : Pat<(i64 (any_fp_to_uint FPR64INX:$rs1)), (FCVT_LU_D_INX FPR64INX:$rs1, FRM_RTZ)>;
642
643// double->int64 with current rounding mode.
644def : Pat<(i64 (any_lrint FPR64INX:$rs1)), (FCVT_L_D_INX $rs1, FRM_DYN)>;
645def : Pat<(i64 (any_llrint FPR64INX:$rs1)), (FCVT_L_D_INX $rs1, FRM_DYN)>;
646
647// double->int64 rounded to nearest with ties rounded away from zero.
648def : Pat<(i64 (any_lround FPR64INX:$rs1)), (FCVT_L_D_INX $rs1, FRM_RMM)>;
649def : Pat<(i64 (any_llround FPR64INX:$rs1)), (FCVT_L_D_INX $rs1, FRM_RMM)>;
650
651// [u]int64->fp. Match GCC and default to using dynamic rounding mode.
652def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_D_L_INX GPR:$rs1, FRM_DYN)>;
653def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_D_LU_INX GPR:$rs1, FRM_DYN)>;
654} // Predicates = [HasStdExtZdinx, IsRV64]
655