xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td (revision 6ba2210ee039f2f12878c217bcf058e9c8b26b29)
1//===-- RISCVInstrInfoFH.td - RISC-V 'FH' 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 'Zfh'
10// half-precision floating-point extension, version 0.1.
11// This version is still experimental as the 'Zfh' extension hasn't been
12// ratified yet.
13//
14//===----------------------------------------------------------------------===//
15
16//===----------------------------------------------------------------------===//
17// RISC-V specific DAG Nodes.
18//===----------------------------------------------------------------------===//
19
20def SDT_RISCVFMV_H_X
21    : SDTypeProfile<1, 1, [SDTCisVT<0, f16>, SDTCisVT<1, XLenVT>]>;
22def SDT_RISCVFMV_X_ANYEXTH
23    : SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisVT<1, f16>]>;
24
25def riscv_fmv_h_x
26    : SDNode<"RISCVISD::FMV_H_X", SDT_RISCVFMV_H_X>;
27def riscv_fmv_x_anyexth
28    : SDNode<"RISCVISD::FMV_X_ANYEXTH", SDT_RISCVFMV_X_ANYEXTH>;
29
30//===----------------------------------------------------------------------===//
31// Instruction class templates
32//===----------------------------------------------------------------------===//
33
34let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
35class FPFMAH_rrr_frm<RISCVOpcode opcode, string opcodestr>
36    : RVInstR4<0b10, opcode, (outs FPR16:$rd),
37               (ins FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, frmarg:$funct3),
38                opcodestr, "$rd, $rs1, $rs2, $rs3, $funct3">;
39
40class FPFMAHDynFrmAlias<FPFMAH_rrr_frm Inst, string OpcodeStr>
41    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2, $rs3",
42                (Inst FPR16:$rd, FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
43
44let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
45class FPALUH_rr<bits<7> funct7, bits<3> funct3, string opcodestr>
46    : RVInstR<funct7, funct3, OPC_OP_FP, (outs FPR16:$rd),
47              (ins FPR16:$rs1, FPR16:$rs2), opcodestr, "$rd, $rs1, $rs2">;
48
49let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
50class FPALUH_rr_frm<bits<7> funct7, string opcodestr>
51    : RVInstRFrm<funct7, OPC_OP_FP, (outs FPR16:$rd),
52                 (ins FPR16:$rs1, FPR16:$rs2, frmarg:$funct3), opcodestr,
53                  "$rd, $rs1, $rs2, $funct3">;
54
55class FPALUHDynFrmAlias<FPALUH_rr_frm Inst, string OpcodeStr>
56    : InstAlias<OpcodeStr#" $rd, $rs1, $rs2",
57                (Inst FPR16:$rd, FPR16:$rs1, FPR16:$rs2, 0b111)>;
58
59let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
60class FPCmpH_rr<bits<3> funct3, string opcodestr>
61    : RVInstR<0b1010010, funct3, OPC_OP_FP, (outs GPR:$rd),
62              (ins FPR16:$rs1, FPR16:$rs2), opcodestr, "$rd, $rs1, $rs2">,
63      Sched<[]>;
64
65//===----------------------------------------------------------------------===//
66// Instructions
67//===----------------------------------------------------------------------===//
68
69let Predicates = [HasStdExtZfh] in {
70let hasSideEffects = 0, mayLoad = 1, mayStore = 0 in
71def FLH : RVInstI<0b001, OPC_LOAD_FP, (outs FPR16:$rd),
72                  (ins GPR:$rs1, simm12:$imm12),
73                   "flh", "$rd, ${imm12}(${rs1})">,
74          Sched<[]>;
75
76// Operands for stores are in the order srcreg, base, offset rather than
77// reflecting the order these fields are specified in the instruction
78// encoding.
79let hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
80def FSH : RVInstS<0b001, OPC_STORE_FP, (outs),
81                  (ins FPR16:$rs2, GPR:$rs1, simm12:$imm12),
82                   "fsh", "$rs2, ${imm12}(${rs1})">,
83          Sched<[]>;
84
85def FMADD_H  : FPFMAH_rrr_frm<OPC_MADD, "fmadd.h">,
86               Sched<[]>;
87def          : FPFMAHDynFrmAlias<FMADD_H, "fmadd.h">;
88def FMSUB_H  : FPFMAH_rrr_frm<OPC_MSUB, "fmsub.h">,
89               Sched<[]>;
90def          : FPFMAHDynFrmAlias<FMSUB_H, "fmsub.h">;
91def FNMSUB_H : FPFMAH_rrr_frm<OPC_NMSUB, "fnmsub.h">,
92               Sched<[]>;
93def          : FPFMAHDynFrmAlias<FNMSUB_H, "fnmsub.h">;
94def FNMADD_H : FPFMAH_rrr_frm<OPC_NMADD, "fnmadd.h">,
95               Sched<[]>;
96def          : FPFMAHDynFrmAlias<FNMADD_H, "fnmadd.h">;
97
98def FADD_H : FPALUH_rr_frm<0b0000010, "fadd.h">,
99             Sched<[]>;
100def        : FPALUHDynFrmAlias<FADD_H, "fadd.h">;
101def FSUB_H : FPALUH_rr_frm<0b0000110, "fsub.h">,
102             Sched<[]>;
103def        : FPALUHDynFrmAlias<FSUB_H, "fsub.h">;
104def FMUL_H : FPALUH_rr_frm<0b0001010, "fmul.h">,
105             Sched<[]>;
106def        : FPALUHDynFrmAlias<FMUL_H, "fmul.h">;
107def FDIV_H : FPALUH_rr_frm<0b0001110, "fdiv.h">,
108             Sched<[]>;
109def        : FPALUHDynFrmAlias<FDIV_H, "fdiv.h">;
110
111def FSQRT_H : FPUnaryOp_r_frm<0b0101110, FPR16, FPR16, "fsqrt.h">,
112              Sched<[]> {
113  let rs2 = 0b00000;
114}
115def         : FPUnaryOpDynFrmAlias<FSQRT_H, "fsqrt.h", FPR16, FPR16>;
116
117def FSGNJ_H  : FPALUH_rr<0b0010010, 0b000, "fsgnj.h">,
118               Sched<[]>;
119def FSGNJN_H : FPALUH_rr<0b0010010, 0b001, "fsgnjn.h">,
120               Sched<[]>;
121def FSGNJX_H : FPALUH_rr<0b0010010, 0b010, "fsgnjx.h">,
122               Sched<[]>;
123
124def FMIN_H   : FPALUH_rr<0b0010110, 0b000, "fmin.h">,
125               Sched<[]>;
126def FMAX_H   : FPALUH_rr<0b0010110, 0b001, "fmax.h">,
127               Sched<[]>;
128
129def FCVT_W_H : FPUnaryOp_r_frm<0b1100010, GPR, FPR16, "fcvt.w.h">,
130               Sched<[]> {
131  let rs2 = 0b00000;
132}
133def          : FPUnaryOpDynFrmAlias<FCVT_W_H, "fcvt.w.h", GPR, FPR16>;
134
135def FCVT_WU_H : FPUnaryOp_r_frm<0b1100010, GPR, FPR16, "fcvt.wu.h">,
136                Sched<[]> {
137  let rs2 = 0b00001;
138}
139def           : FPUnaryOpDynFrmAlias<FCVT_WU_H, "fcvt.wu.h", GPR, FPR16>;
140
141def FCVT_H_W : FPUnaryOp_r_frm<0b1101010, FPR16, GPR, "fcvt.h.w">,
142               Sched<[]> {
143  let rs2 = 0b00000;
144}
145def          : FPUnaryOpDynFrmAlias<FCVT_H_W, "fcvt.h.w", FPR16, GPR>;
146
147def FCVT_H_WU : FPUnaryOp_r_frm<0b1101010, FPR16, GPR, "fcvt.h.wu">,
148                Sched<[]> {
149  let rs2 = 0b00001;
150}
151def           : FPUnaryOpDynFrmAlias<FCVT_H_WU, "fcvt.h.wu", FPR16, GPR>;
152
153def FCVT_H_S : FPUnaryOp_r_frm<0b0100010, FPR16, FPR32, "fcvt.h.s">,
154               Sched<[]> {
155  let rs2 = 0b00000;
156}
157def          : FPUnaryOpDynFrmAlias<FCVT_H_S, "fcvt.h.s", FPR16, FPR32>;
158
159def FCVT_S_H : FPUnaryOp_r<0b0100000, 0b000, FPR32, FPR16, "fcvt.s.h">,
160               Sched<[]> {
161  let rs2 = 0b00010;
162}
163
164def FMV_X_H : FPUnaryOp_r<0b1110010, 0b000, GPR, FPR16, "fmv.x.h">,
165              Sched<[]> {
166  let rs2 = 0b00000;
167}
168
169def FMV_H_X : FPUnaryOp_r<0b1111010, 0b000, FPR16, GPR, "fmv.h.x">,
170              Sched<[]> {
171  let rs2 = 0b00000;
172}
173
174def FEQ_H : FPCmpH_rr<0b010, "feq.h">;
175def FLT_H : FPCmpH_rr<0b001, "flt.h">;
176def FLE_H : FPCmpH_rr<0b000, "fle.h">;
177
178def FCLASS_H : FPUnaryOp_r<0b1110010, 0b001, GPR, FPR16, "fclass.h">,
179               Sched<[]> {
180  let rs2 = 0b00000;
181}
182} // Predicates = [HasStdExtZfh]
183
184let Predicates = [HasStdExtZfh, IsRV64] in {
185def FCVT_L_H  : FPUnaryOp_r_frm<0b1100010, GPR, FPR16, "fcvt.l.h">,
186                Sched<[]> {
187  let rs2 = 0b00010;
188}
189def           : FPUnaryOpDynFrmAlias<FCVT_L_H, "fcvt.l.h", GPR, FPR16>;
190
191def FCVT_LU_H  : FPUnaryOp_r_frm<0b1100010, GPR, FPR16, "fcvt.lu.h">,
192                 Sched<[]> {
193  let rs2 = 0b00011;
194}
195def            : FPUnaryOpDynFrmAlias<FCVT_LU_H, "fcvt.lu.h", GPR, FPR16>;
196
197def FCVT_H_L : FPUnaryOp_r_frm<0b1101010, FPR16, GPR, "fcvt.h.l">,
198               Sched<[]> {
199  let rs2 = 0b00010;
200}
201def          : FPUnaryOpDynFrmAlias<FCVT_H_L, "fcvt.h.l", FPR16, GPR>;
202
203def FCVT_H_LU : FPUnaryOp_r_frm<0b1101010, FPR16, GPR, "fcvt.h.lu">,
204                Sched<[]> {
205  let rs2 = 0b00011;
206}
207def           : FPUnaryOpDynFrmAlias<FCVT_H_LU, "fcvt.h.lu", FPR16, GPR>;
208} // Predicates = [HasStdExtZfh, IsRV64]
209
210let Predicates = [HasStdExtZfh, HasStdExtD] in {
211def FCVT_H_D : FPUnaryOp_r_frm<0b0100010, FPR16, FPR64, "fcvt.h.d">,
212               Sched<[]> {
213  let rs2 = 0b00001;
214}
215def          : FPUnaryOpDynFrmAlias<FCVT_H_D, "fcvt.h.d", FPR16, FPR64>;
216
217def FCVT_D_H : FPUnaryOp_r<0b0100001, 0b000, FPR64, FPR16, "fcvt.d.h">,
218               Sched<[]> {
219  let rs2 = 0b00010;
220}
221} // Predicates = [HasStdExtZfh, HasStdExtD]
222
223//===----------------------------------------------------------------------===//
224// Assembler Pseudo Instructions (User-Level ISA, Version 2.2, Chapter 20)
225//===----------------------------------------------------------------------===//
226
227let Predicates = [HasStdExtZfh] in {
228def : InstAlias<"flh $rd, (${rs1})",  (FLH FPR16:$rd,  GPR:$rs1, 0), 0>;
229def : InstAlias<"fsh $rs2, (${rs1})", (FSH FPR16:$rs2, GPR:$rs1, 0), 0>;
230
231def : InstAlias<"fmv.h $rd, $rs",  (FSGNJ_H  FPR16:$rd, FPR16:$rs, FPR16:$rs)>;
232def : InstAlias<"fabs.h $rd, $rs", (FSGNJX_H FPR16:$rd, FPR16:$rs, FPR16:$rs)>;
233def : InstAlias<"fneg.h $rd, $rs", (FSGNJN_H FPR16:$rd, FPR16:$rs, FPR16:$rs)>;
234
235// fgt.h/fge.h are recognised by the GNU assembler but the canonical
236// flt.h/fle.h forms will always be printed. Therefore, set a zero weight.
237def : InstAlias<"fgt.h $rd, $rs, $rt",
238                (FLT_H GPR:$rd, FPR16:$rt, FPR16:$rs), 0>;
239def : InstAlias<"fge.h $rd, $rs, $rt",
240                (FLE_H GPR:$rd, FPR16:$rt, FPR16:$rs), 0>;
241
242def PseudoFLH  : PseudoFloatLoad<"flh", FPR16>;
243def PseudoFSH  : PseudoStore<"fsh", FPR16>;
244} // Predicates = [HasStdExtZfh]
245
246//===----------------------------------------------------------------------===//
247// Pseudo-instructions and codegen patterns
248//===----------------------------------------------------------------------===//
249
250/// Generic pattern classes
251class PatFpr16Fpr16<SDPatternOperator OpNode, RVInstR Inst>
252    : Pat<(OpNode FPR16:$rs1, FPR16:$rs2), (Inst $rs1, $rs2)>;
253
254class PatFpr16Fpr16DynFrm<SDPatternOperator OpNode, RVInstRFrm Inst>
255    : Pat<(OpNode FPR16:$rs1, FPR16:$rs2), (Inst $rs1, $rs2, 0b111)>;
256
257let Predicates = [HasStdExtZfh] in {
258
259/// Float constants
260def : Pat<(f16 (fpimm0)), (FMV_H_X X0)>;
261
262/// Float conversion operations
263
264// [u]int32<->float conversion patterns must be gated on IsRV32 or IsRV64, so
265// are defined later.
266
267/// Float arithmetic operations
268
269def : PatFpr16Fpr16DynFrm<fadd, FADD_H>;
270def : PatFpr16Fpr16DynFrm<fsub, FSUB_H>;
271def : PatFpr16Fpr16DynFrm<fmul, FMUL_H>;
272def : PatFpr16Fpr16DynFrm<fdiv, FDIV_H>;
273
274def : Pat<(fsqrt FPR16:$rs1), (FSQRT_H FPR16:$rs1, 0b111)>;
275
276def : Pat<(fneg FPR16:$rs1), (FSGNJN_H $rs1, $rs1)>;
277def : Pat<(fabs FPR16:$rs1), (FSGNJX_H $rs1, $rs1)>;
278
279def : PatFpr16Fpr16<fcopysign, FSGNJ_H>;
280def : Pat<(fcopysign FPR16:$rs1, (fneg FPR16:$rs2)), (FSGNJN_H $rs1, $rs2)>;
281def : Pat<(fcopysign FPR16:$rs1, FPR32:$rs2),
282          (FSGNJ_H $rs1, (FCVT_H_S $rs2, 0b111))>;
283def : Pat<(fcopysign FPR16:$rs1, FPR64:$rs2),
284          (FSGNJ_H $rs1, (FCVT_H_D $rs2, 0b111))>;
285def : Pat<(fcopysign FPR32:$rs1, FPR16:$rs2), (FSGNJ_S $rs1, (FCVT_S_H $rs2))>;
286def : Pat<(fcopysign FPR64:$rs1, FPR16:$rs2), (FSGNJ_D $rs1, (FCVT_D_H $rs2))>;
287
288// fmadd: rs1 * rs2 + rs3
289def : Pat<(fma FPR16:$rs1, FPR16:$rs2, FPR16:$rs3),
290          (FMADD_H $rs1, $rs2, $rs3, 0b111)>;
291
292// fmsub: rs1 * rs2 - rs3
293def : Pat<(fma FPR16:$rs1, FPR16:$rs2, (fneg FPR16:$rs3)),
294          (FMSUB_H FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
295
296// fnmsub: -rs1 * rs2 + rs3
297def : Pat<(fma (fneg FPR16:$rs1), FPR16:$rs2, FPR16:$rs3),
298          (FNMSUB_H FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
299
300// fnmadd: -rs1 * rs2 - rs3
301def : Pat<(fma (fneg FPR16:$rs1), FPR16:$rs2, (fneg FPR16:$rs3)),
302          (FNMADD_H FPR16:$rs1, FPR16:$rs2, FPR16:$rs3, 0b111)>;
303
304def : PatFpr16Fpr16<fminnum, FMIN_H>;
305def : PatFpr16Fpr16<fmaxnum, FMAX_H>;
306
307/// Setcc
308
309def : PatFpr16Fpr16<seteq, FEQ_H>;
310def : PatFpr16Fpr16<setoeq, FEQ_H>;
311def : PatFpr16Fpr16<setlt, FLT_H>;
312def : PatFpr16Fpr16<setolt, FLT_H>;
313def : PatFpr16Fpr16<setle, FLE_H>;
314def : PatFpr16Fpr16<setole, FLE_H>;
315
316def Select_FPR16_Using_CC_GPR : SelectCC_rrirr<FPR16, GPR>;
317
318/// Loads
319
320defm : LdPat<load, FLH>;
321
322/// Stores
323
324defm : StPat<store, FSH, FPR16>;
325
326/// Float conversion operations
327
328// f32 -> f16, f16 -> f32
329def : Pat<(fpround FPR32:$rs1), (FCVT_H_S FPR32:$rs1, 0b111)>;
330def : Pat<(fpextend FPR16:$rs1), (FCVT_S_H FPR16:$rs1)>;
331
332// Moves (no conversion)
333def : Pat<(riscv_fmv_h_x GPR:$src), (FMV_H_X GPR:$src)>;
334def : Pat<(riscv_fmv_x_anyexth FPR16:$src), (FMV_X_H FPR16:$src)>;
335} // Predicates = [HasStdExtZfh]
336
337let Predicates = [HasStdExtZfh, IsRV32] in {
338// float->[u]int. Round-to-zero must be used.
339def : Pat<(fp_to_sint FPR16:$rs1), (FCVT_W_H $rs1, 0b001)>;
340def : Pat<(fp_to_uint FPR16:$rs1), (FCVT_WU_H $rs1, 0b001)>;
341
342// [u]int->float. Match GCC and default to using dynamic rounding mode.
343def : Pat<(sint_to_fp GPR:$rs1), (FCVT_H_W $rs1, 0b111)>;
344def : Pat<(uint_to_fp GPR:$rs1), (FCVT_H_WU $rs1, 0b111)>;
345} // Predicates = [HasStdExtZfh, IsRV32]
346
347let Predicates = [HasStdExtZfh, IsRV64] in {
348// FP->[u]int32 is mostly handled by the FP->[u]int64 patterns. This is safe
349// because fpto[u|s]i produces poison if the value can't fit into the target.
350// We match the single case below because fcvt.wu.s sign-extends its result so
351// is cheaper than fcvt.lu.h+sext.w.
352def : Pat<(sext_inreg (assertzexti32 (fp_to_uint FPR16:$rs1)), i32),
353          (FCVT_WU_H $rs1, 0b001)>;
354
355// FP->[u]int64
356def : Pat<(fp_to_sint FPR16:$rs1), (FCVT_L_H $rs1, 0b001)>;
357def : Pat<(fp_to_uint FPR16:$rs1), (FCVT_LU_H $rs1, 0b001)>;
358
359// [u]int->fp. Match GCC and default to using dynamic rounding mode.
360def : Pat<(sint_to_fp (sexti32 GPR:$rs1)), (FCVT_H_W $rs1, 0b111)>;
361def : Pat<(uint_to_fp (zexti32 GPR:$rs1)), (FCVT_H_WU $rs1, 0b111)>;
362def : Pat<(sint_to_fp GPR:$rs1), (FCVT_H_L $rs1, 0b111)>;
363def : Pat<(uint_to_fp GPR:$rs1), (FCVT_H_LU $rs1, 0b111)>;
364} // Predicates = [HasStdExtZfh, IsRV64]
365
366let Predicates = [HasStdExtZfh, HasStdExtD] in {
367/// Float conversion operations
368// f64 -> f16, f16 -> f64
369def : Pat<(fpround FPR64:$rs1), (FCVT_H_D FPR64:$rs1, 0b111)>;
370def : Pat<(fpextend FPR16:$rs1), (FCVT_D_H FPR16:$rs1)>;
371}
372