]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
Merge llvm-project main llvmorg-14-init-13186-g0c553cc1af2e
[FreeBSD/FreeBSD.git] / contrib / llvm-project / llvm / lib / Target / RISCV / RISCVInstrInfoD.td
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
18 def SDT_RISCVBuildPairF64 : SDTypeProfile<1, 2, [SDTCisVT<0, f64>,
19                                                  SDTCisVT<1, i32>,
20                                                  SDTCisSameAs<1, 2>]>;
21 def SDT_RISCVSplitF64     : SDTypeProfile<2, 1, [SDTCisVT<0, i32>,
22                                                  SDTCisVT<1, i32>,
23                                                  SDTCisVT<2, f64>]>;
24
25 def RISCVBuildPairF64 : SDNode<"RISCVISD::BuildPairF64", SDT_RISCVBuildPairF64>;
26 def RISCVSplitF64     : SDNode<"RISCVISD::SplitF64", SDT_RISCVSplitF64>;
27
28 //===----------------------------------------------------------------------===//
29 // Instructions
30 //===----------------------------------------------------------------------===//
31
32 let Predicates = [HasStdExtD] in {
33
34 let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
35 def FLD : RVInstI<0b011, OPC_LOAD_FP, (outs FPR64:$rd),
36                   (ins GPR:$rs1, simm12:$imm12),
37                   "fld", "$rd, ${imm12}(${rs1})">,
38           Sched<[WriteFLD64, ReadFMemBase]>;
39
40 // Operands for stores are in the order srcreg, base, offset rather than
41 // reflecting the order these fields are specified in the instruction
42 // encoding.
43 let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
44 def FSD : RVInstS<0b011, OPC_STORE_FP, (outs),
45                   (ins FPR64:$rs2, GPR:$rs1, simm12:$imm12),
46                    "fsd", "$rs2, ${imm12}(${rs1})">,
47           Sched<[WriteFST64, ReadStoreData, ReadFMemBase]>;
48
49 let SchedRW = [WriteFMA64, ReadFMA64, ReadFMA64, ReadFMA64] in {
50 def FMADD_D  : FPFMA_rrr_frm<OPC_MADD,  0b01, "fmadd.d",  FPR64>;
51 def FMSUB_D  : FPFMA_rrr_frm<OPC_MSUB,  0b01, "fmsub.d",  FPR64>;
52 def FNMSUB_D : FPFMA_rrr_frm<OPC_NMSUB, 0b01, "fnmsub.d", FPR64>;
53 def FNMADD_D : FPFMA_rrr_frm<OPC_NMADD, 0b01, "fnmadd.d", FPR64>;
54 }
55
56 def : FPFMADynFrmAlias<FMADD_D,  "fmadd.d",  FPR64>;
57 def : FPFMADynFrmAlias<FMSUB_D,  "fmsub.d",  FPR64>;
58 def : FPFMADynFrmAlias<FNMSUB_D, "fnmsub.d", FPR64>;
59 def : FPFMADynFrmAlias<FNMADD_D, "fnmadd.d", FPR64>;
60
61 def FADD_D : FPALU_rr_frm<0b0000001, "fadd.d", FPR64>,
62              Sched<[WriteFALU64, ReadFALU64, ReadFALU64]>;
63 def FSUB_D : FPALU_rr_frm<0b0000101, "fsub.d", FPR64>,
64              Sched<[WriteFALU64, ReadFALU64, ReadFALU64]>;
65 def FMUL_D : FPALU_rr_frm<0b0001001, "fmul.d", FPR64>,
66              Sched<[WriteFMul64, ReadFMul64, ReadFMul64]>;
67 def FDIV_D : FPALU_rr_frm<0b0001101, "fdiv.d", FPR64>,
68              Sched<[WriteFDiv64, ReadFDiv64, ReadFDiv64]>;
69
70 def        : FPALUDynFrmAlias<FADD_D, "fadd.d", FPR64>;
71 def        : FPALUDynFrmAlias<FSUB_D, "fsub.d", FPR64>;
72 def        : FPALUDynFrmAlias<FMUL_D, "fmul.d", FPR64>;
73 def        : FPALUDynFrmAlias<FDIV_D, "fdiv.d", FPR64>;
74
75 def FSQRT_D : FPUnaryOp_r_frm<0b0101101, 0b00000, FPR64, FPR64, "fsqrt.d">,
76               Sched<[WriteFSqrt64, ReadFSqrt64]>;
77 def         : FPUnaryOpDynFrmAlias<FSQRT_D, "fsqrt.d", FPR64, FPR64>;
78
79 let SchedRW = [WriteFSGNJ64, ReadFSGNJ64, ReadFSGNJ64],
80     mayRaiseFPException = 0 in {
81 def FSGNJ_D  : FPALU_rr<0b0010001, 0b000, "fsgnj.d", FPR64>;
82 def FSGNJN_D : FPALU_rr<0b0010001, 0b001, "fsgnjn.d", FPR64>;
83 def FSGNJX_D : FPALU_rr<0b0010001, 0b010, "fsgnjx.d", FPR64>;
84 }
85
86 let SchedRW = [WriteFMinMax64, ReadFMinMax64, ReadFMinMax64] in {
87 def FMIN_D   : FPALU_rr<0b0010101, 0b000, "fmin.d", FPR64>;
88 def FMAX_D   : FPALU_rr<0b0010101, 0b001, "fmax.d", FPR64>;
89 }
90
91 def FCVT_S_D : FPUnaryOp_r_frm<0b0100000, 0b00001, FPR32, FPR64, "fcvt.s.d">,
92                Sched<[WriteFCvtF64ToF32, ReadFCvtF64ToF32]>;
93 def          : FPUnaryOpDynFrmAlias<FCVT_S_D, "fcvt.s.d", FPR32, FPR64>;
94
95 def FCVT_D_S : FPUnaryOp_r<0b0100001, 0b00000, 0b000, FPR64, FPR32, "fcvt.d.s">,
96                Sched<[WriteFCvtF32ToF64, ReadFCvtF32ToF64]>;
97
98 let SchedRW = [WriteFCmp64, ReadFCmp64, ReadFCmp64] in {
99 def FEQ_D : FPCmp_rr<0b1010001, 0b010, "feq.d", FPR64>;
100 def FLT_D : FPCmp_rr<0b1010001, 0b001, "flt.d", FPR64>;
101 def FLE_D : FPCmp_rr<0b1010001, 0b000, "fle.d", FPR64>;
102 }
103
104 let mayRaiseFPException = 0 in
105 def FCLASS_D : FPUnaryOp_r<0b1110001, 0b00000, 0b001, GPR, FPR64, "fclass.d">,
106                Sched<[WriteFClass64, ReadFClass64]>;
107
108 def FCVT_W_D : FPUnaryOp_r_frm<0b1100001, 0b00000, GPR, FPR64, "fcvt.w.d">,
109                Sched<[WriteFCvtF64ToI32, ReadFCvtF64ToI32]>;
110 def          : FPUnaryOpDynFrmAlias<FCVT_W_D, "fcvt.w.d", GPR, FPR64>;
111
112 def FCVT_WU_D : FPUnaryOp_r_frm<0b1100001, 0b00001, GPR, FPR64, "fcvt.wu.d">,
113                 Sched<[WriteFCvtF64ToI32, ReadFCvtF64ToI32]>;
114 def           : FPUnaryOpDynFrmAlias<FCVT_WU_D, "fcvt.wu.d", GPR, FPR64>;
115
116 def FCVT_D_W : FPUnaryOp_r<0b1101001, 0b00000, 0b000, FPR64, GPR, "fcvt.d.w">,
117                Sched<[WriteFCvtI32ToF64, ReadFCvtI32ToF64]>;
118
119 def FCVT_D_WU : FPUnaryOp_r<0b1101001, 0b00001, 0b000, FPR64, GPR, "fcvt.d.wu">,
120                 Sched<[WriteFCvtI32ToF64, ReadFCvtI32ToF64]>;
121 } // Predicates = [HasStdExtD]
122
123 let Predicates = [HasStdExtD, IsRV64] in {
124 def FCVT_L_D : FPUnaryOp_r_frm<0b1100001, 0b00010, GPR, FPR64, "fcvt.l.d">,
125                Sched<[WriteFCvtF64ToI64, ReadFCvtF64ToI64]>;
126 def          : FPUnaryOpDynFrmAlias<FCVT_L_D, "fcvt.l.d", GPR, FPR64>;
127
128 def FCVT_LU_D : FPUnaryOp_r_frm<0b1100001, 0b00011, GPR, FPR64, "fcvt.lu.d">,
129                 Sched<[WriteFCvtF64ToI64, ReadFCvtF64ToI64]>;
130 def           : FPUnaryOpDynFrmAlias<FCVT_LU_D, "fcvt.lu.d", GPR, FPR64>;
131
132 let mayRaiseFPException = 0 in
133 def FMV_X_D : FPUnaryOp_r<0b1110001, 0b00000, 0b000, GPR, FPR64, "fmv.x.d">,
134               Sched<[WriteFMovF64ToI64, ReadFMovF64ToI64]>;
135
136 def FCVT_D_L : FPUnaryOp_r_frm<0b1101001, 0b00010, FPR64, GPR, "fcvt.d.l">,
137                Sched<[WriteFCvtI64ToF64, ReadFCvtI64ToF64]>;
138 def          : FPUnaryOpDynFrmAlias<FCVT_D_L, "fcvt.d.l", FPR64, GPR>;
139
140 def FCVT_D_LU : FPUnaryOp_r_frm<0b1101001, 0b00011, FPR64, GPR, "fcvt.d.lu">,
141                 Sched<[WriteFCvtI64ToF64, ReadFCvtI64ToF64]>;
142 def           : FPUnaryOpDynFrmAlias<FCVT_D_LU, "fcvt.d.lu", FPR64, GPR>;
143
144 let mayRaiseFPException = 0 in
145 def FMV_D_X : FPUnaryOp_r<0b1111001, 0b00000, 0b000, FPR64, GPR, "fmv.d.x">,
146               Sched<[WriteFMovI64ToF64, ReadFMovI64ToF64]>;
147 } // Predicates = [HasStdExtD, IsRV64]
148
149 //===----------------------------------------------------------------------===//
150 // Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
151 //===----------------------------------------------------------------------===//
152
153 let Predicates = [HasStdExtD] in {
154 def : InstAlias<"fld $rd, (${rs1})",  (FLD FPR64:$rd,  GPR:$rs1, 0), 0>;
155 def : InstAlias<"fsd $rs2, (${rs1})", (FSD FPR64:$rs2, GPR:$rs1, 0), 0>;
156
157 def : InstAlias<"fmv.d $rd, $rs",  (FSGNJ_D  FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
158 def : InstAlias<"fabs.d $rd, $rs", (FSGNJX_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
159 def : InstAlias<"fneg.d $rd, $rs", (FSGNJN_D FPR64:$rd, FPR64:$rs, FPR64:$rs)>;
160
161 // fgt.d/fge.d are recognised by the GNU assembler but the canonical
162 // flt.d/fle.d forms will always be printed. Therefore, set a zero weight.
163 def : InstAlias<"fgt.d $rd, $rs, $rt",
164                 (FLT_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
165 def : InstAlias<"fge.d $rd, $rs, $rt",
166                 (FLE_D GPR:$rd, FPR64:$rt, FPR64:$rs), 0>;
167
168 def PseudoFLD  : PseudoFloatLoad<"fld", FPR64>;
169 def PseudoFSD  : PseudoStore<"fsd", FPR64>;
170 } // Predicates = [HasStdExtD]
171
172 //===----------------------------------------------------------------------===//
173 // Pseudo-instructions and codegen patterns
174 //===----------------------------------------------------------------------===//
175
176 class PatFpr64Fpr64<SDPatternOperator OpNode, RVInstR Inst>
177     : Pat<(OpNode FPR64:$rs1, FPR64:$rs2), (Inst $rs1, $rs2)>;
178
179 class PatFpr64Fpr64DynFrm<SDPatternOperator OpNode, RVInstRFrm Inst>
180     : Pat<(OpNode FPR64:$rs1, FPR64:$rs2), (Inst $rs1, $rs2, 0b111)>;
181
182 let Predicates = [HasStdExtD] in {
183
184 /// Float conversion operations
185
186 // f64 -> f32, f32 -> f64
187 def : Pat<(any_fpround FPR64:$rs1), (FCVT_S_D FPR64:$rs1, 0b111)>;
188 def : Pat<(any_fpextend FPR32:$rs1), (FCVT_D_S FPR32:$rs1)>;
189
190 // [u]int<->double conversion patterns must be gated on IsRV32 or IsRV64, so
191 // are defined later.
192
193 /// Float arithmetic operations
194
195 def : PatFpr64Fpr64DynFrm<any_fadd, FADD_D>;
196 def : PatFpr64Fpr64DynFrm<any_fsub, FSUB_D>;
197 def : PatFpr64Fpr64DynFrm<any_fmul, FMUL_D>;
198 def : PatFpr64Fpr64DynFrm<any_fdiv, FDIV_D>;
199
200 def : Pat<(any_fsqrt FPR64:$rs1), (FSQRT_D FPR64:$rs1, 0b111)>;
201
202 def : Pat<(fneg FPR64:$rs1), (FSGNJN_D $rs1, $rs1)>;
203 def : Pat<(fabs FPR64:$rs1), (FSGNJX_D $rs1, $rs1)>;
204
205 def : PatFpr64Fpr64<fcopysign, FSGNJ_D>;
206 def : Pat<(fcopysign FPR64:$rs1, (fneg FPR64:$rs2)), (FSGNJN_D $rs1, $rs2)>;
207 def : Pat<(fcopysign FPR64:$rs1, FPR32:$rs2), (FSGNJ_D $rs1, (FCVT_D_S $rs2))>;
208 def : Pat<(fcopysign FPR32:$rs1, FPR64:$rs2), (FSGNJ_S $rs1, (FCVT_S_D $rs2,
209                                                               0b111))>;
210
211 // fmadd: rs1 * rs2 + rs3
212 def : Pat<(any_fma FPR64:$rs1, FPR64:$rs2, FPR64:$rs3),
213           (FMADD_D $rs1, $rs2, $rs3, 0b111)>;
214
215 // fmsub: rs1 * rs2 - rs3
216 def : Pat<(any_fma FPR64:$rs1, FPR64:$rs2, (fneg FPR64:$rs3)),
217           (FMSUB_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
218
219 // fnmsub: -rs1 * rs2 + rs3
220 def : Pat<(any_fma (fneg FPR64:$rs1), FPR64:$rs2, FPR64:$rs3),
221           (FNMSUB_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
222
223 // fnmadd: -rs1 * rs2 - rs3
224 def : Pat<(any_fma (fneg FPR64:$rs1), FPR64:$rs2, (fneg FPR64:$rs3)),
225           (FNMADD_D FPR64:$rs1, FPR64:$rs2, FPR64:$rs3, 0b111)>;
226
227 // The ratified 20191213 ISA spec defines fmin and fmax in a way that matches
228 // LLVM's fminnum and fmaxnum.
229 // <https://github.com/riscv/riscv-isa-manual/commit/cd20cee7efd9bac7c5aa127ec3b451749d2b3cce>.
230 def : PatFpr64Fpr64<fminnum, FMIN_D>;
231 def : PatFpr64Fpr64<fmaxnum, FMAX_D>;
232
233 /// Setcc
234
235 def : PatFpr64Fpr64<seteq, FEQ_D>;
236 def : PatFpr64Fpr64<setoeq, FEQ_D>;
237 def : PatFpr64Fpr64<setlt, FLT_D>;
238 def : PatFpr64Fpr64<setolt, FLT_D>;
239 def : PatFpr64Fpr64<setle, FLE_D>;
240 def : PatFpr64Fpr64<setole, FLE_D>;
241
242 def Select_FPR64_Using_CC_GPR : SelectCC_rrirr<FPR64, GPR>;
243
244 /// Loads
245
246 defm : LdPat<load, FLD, f64>;
247
248 /// Stores
249
250 defm : StPat<store, FSD, FPR64, f64>;
251
252 /// Pseudo-instructions needed for the soft-float ABI with RV32D
253
254 // Moves two GPRs to an FPR.
255 let usesCustomInserter = 1 in
256 def BuildPairF64Pseudo
257     : Pseudo<(outs FPR64:$dst), (ins GPR:$src1, GPR:$src2),
258              [(set FPR64:$dst, (RISCVBuildPairF64 GPR:$src1, GPR:$src2))]>;
259
260 // Moves an FPR to two GPRs.
261 let usesCustomInserter = 1 in
262 def SplitF64Pseudo
263     : Pseudo<(outs GPR:$dst1, GPR:$dst2), (ins FPR64:$src),
264              [(set GPR:$dst1, GPR:$dst2, (RISCVSplitF64 FPR64:$src))]>;
265
266 } // Predicates = [HasStdExtD]
267
268 let Predicates = [HasStdExtD, IsRV32] in {
269
270 /// Float constants
271 def : Pat<(f64 (fpimm0)), (FCVT_D_W (i32 X0))>;
272
273 // double->[u]int. Round-to-zero must be used.
274 def : Pat<(i32 (any_fp_to_sint FPR64:$rs1)), (FCVT_W_D FPR64:$rs1, 0b001)>;
275 def : Pat<(i32 (any_fp_to_uint FPR64:$rs1)), (FCVT_WU_D FPR64:$rs1, 0b001)>;
276
277 // Saturating double->[u]int32.
278 def : Pat<(i32 (riscv_fcvt_x_rtz FPR64:$rs1)), (FCVT_W_D $rs1, 0b001)>;
279 def : Pat<(i32 (riscv_fcvt_xu_rtz FPR64:$rs1)), (FCVT_WU_D $rs1, 0b001)>;
280
281 // float->int32 with current rounding mode.
282 def : Pat<(i32 (lrint FPR64:$rs1)), (FCVT_W_D $rs1, 0b111)>;
283
284 // float->int32 rounded to nearest with ties rounded away from zero.
285 def : Pat<(i32 (lround FPR64:$rs1)), (FCVT_W_D $rs1, 0b100)>;
286
287 // [u]int->double.
288 def : Pat<(any_sint_to_fp (i32 GPR:$rs1)), (FCVT_D_W GPR:$rs1)>;
289 def : Pat<(any_uint_to_fp (i32 GPR:$rs1)), (FCVT_D_WU GPR:$rs1)>;
290 } // Predicates = [HasStdExtD, IsRV32]
291
292 let Predicates = [HasStdExtD, IsRV64] in {
293
294 /// Float constants
295 def : Pat<(f64 (fpimm0)), (FMV_D_X (i64 X0))>;
296
297 // Moves (no conversion)
298 def : Pat<(bitconvert (i64 GPR:$rs1)), (FMV_D_X GPR:$rs1)>;
299 def : Pat<(i64 (bitconvert FPR64:$rs1)), (FMV_X_D FPR64:$rs1)>;
300
301 // Use target specific isd nodes to help us remember the result is sign
302 // extended. Matching sext_inreg+fptoui/fptosi may cause the conversion to be
303 // duplicated if it has another user that didn't need the sign_extend.
304 def : Pat<(riscv_any_fcvt_w_rtz_rv64 FPR64:$rs1),  (FCVT_W_D $rs1, 0b001)>;
305 def : Pat<(riscv_any_fcvt_wu_rtz_rv64 FPR64:$rs1), (FCVT_WU_D $rs1, 0b001)>;
306
307 // [u]int32->fp
308 def : Pat<(any_sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_D_W $rs1)>;
309 def : Pat<(any_uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_D_WU $rs1)>;
310
311 // Saturating double->[u]int64.
312 def : Pat<(i64 (riscv_fcvt_x_rtz FPR64:$rs1)), (FCVT_L_D $rs1, 0b001)>;
313 def : Pat<(i64 (riscv_fcvt_xu_rtz FPR64:$rs1)), (FCVT_LU_D $rs1, 0b001)>;
314
315 // double->[u]int64. Round-to-zero must be used.
316 def : Pat<(i64 (any_fp_to_sint FPR64:$rs1)), (FCVT_L_D FPR64:$rs1, 0b001)>;
317 def : Pat<(i64 (any_fp_to_uint FPR64:$rs1)), (FCVT_LU_D FPR64:$rs1, 0b001)>;
318
319 // double->int64 with current rounding mode.
320 def : Pat<(i64 (lrint FPR64:$rs1)), (FCVT_L_D $rs1, 0b111)>;
321 def : Pat<(i64 (llrint FPR64:$rs1)), (FCVT_L_D $rs1, 0b111)>;
322
323 // double->int64 rounded to nearest with ties rounded away from zero.
324 def : Pat<(i64 (lround FPR64:$rs1)), (FCVT_L_D $rs1, 0b100)>;
325 def : Pat<(i64 (llround FPR64:$rs1)), (FCVT_L_D $rs1, 0b100)>;
326
327 // [u]int64->fp. Match GCC and default to using dynamic rounding mode.
328 def : Pat<(any_sint_to_fp (i64 GPR:$rs1)), (FCVT_D_L GPR:$rs1, 0b111)>;
329 def : Pat<(any_uint_to_fp (i64 GPR:$rs1)), (FCVT_D_LU GPR:$rs1, 0b111)>;
330 } // Predicates = [HasStdExtD, IsRV64]