1//=-- LoongArchInstrInfoD.td - Double-Precision Float instr -*- 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 basic double-precision floating-point instructions.
10//
11//===----------------------------------------------------------------------===//
12
13//===----------------------------------------------------------------------===//
14// Instructions
15//===----------------------------------------------------------------------===//
16
17let Predicates = [HasBasicD] in {
18
19// Arithmetic Operation Instructions
20def FADD_D : FP_ALU_3R<0b00000001000000010, "fadd.d", FPR64>;
21def FSUB_D : FP_ALU_3R<0b00000001000000110, "fsub.d", FPR64>;
22def FMUL_D : FP_ALU_3R<0b00000001000001010, "fmul.d", FPR64>;
23def FDIV_D : FP_ALU_3R<0b00000001000001110, "fdiv.d", FPR64>;
24def FMADD_D  : FP_ALU_4R<0b000010000010, "fmadd.d", FPR64>;
25def FMSUB_D  : FP_ALU_4R<0b000010000110, "fmsub.d", FPR64>;
26def FNMADD_D : FP_ALU_4R<0b000010001010, "fnmadd.d", FPR64>;
27def FNMSUB_D : FP_ALU_4R<0b000010001110, "fnmsub.d", FPR64>;
28def FMAX_D  : FP_ALU_3R<0b00000001000010010, "fmax.d", FPR64>;
29def FMIN_D  : FP_ALU_3R<0b00000001000010110, "fmin.d", FPR64>;
30def FMAXA_D : FP_ALU_3R<0b00000001000011010, "fmaxa.d", FPR64>;
31def FMINA_D : FP_ALU_3R<0b00000001000011110, "fmina.d", FPR64>;
32def FABS_D   : FP_ALU_2R<0b0000000100010100000010, "fabs.d", FPR64>;
33def FNEG_D   : FP_ALU_2R<0b0000000100010100000110, "fneg.d", FPR64>;
34def FSQRT_D  : FP_ALU_2R<0b0000000100010100010010, "fsqrt.d", FPR64>;
35def FRECIP_D : FP_ALU_2R<0b0000000100010100010110, "frecip.d", FPR64>;
36def FRSQRT_D : FP_ALU_2R<0b0000000100010100011010, "frsqrt.d", FPR64>;
37def FSCALEB_D : FP_ALU_3R<0b00000001000100010, "fscaleb.d", FPR64>;
38def FLOGB_D   : FP_ALU_2R<0b0000000100010100001010, "flogb.d", FPR64>;
39def FCOPYSIGN_D : FP_ALU_3R<0b00000001000100110, "fcopysign.d", FPR64>;
40def FCLASS_D  : FP_ALU_2R<0b0000000100010100001110, "fclass.d", FPR64>;
41
42// Comparison Instructions
43def FCMP_CAF_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CAF, "fcmp.caf.d", FPR64>;
44def FCMP_CUN_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CUN, "fcmp.cun.d", FPR64>;
45def FCMP_CEQ_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CEQ, "fcmp.ceq.d", FPR64>;
46def FCMP_CUEQ_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CUEQ, "fcmp.cueq.d", FPR64>;
47def FCMP_CLT_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CLT, "fcmp.clt.d", FPR64>;
48def FCMP_CULT_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CULT, "fcmp.cult.d", FPR64>;
49def FCMP_CLE_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CLE, "fcmp.cle.d", FPR64>;
50def FCMP_CULE_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CULE, "fcmp.cule.d", FPR64>;
51def FCMP_CNE_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CNE, "fcmp.cne.d", FPR64>;
52def FCMP_COR_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_COR, "fcmp.cor.d", FPR64>;
53def FCMP_CUNE_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_CUNE, "fcmp.cune.d", FPR64>;
54def FCMP_SAF_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SAF, "fcmp.saf.d", FPR64>;
55def FCMP_SUN_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SUN, "fcmp.sun.d", FPR64>;
56def FCMP_SEQ_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SEQ, "fcmp.seq.d", FPR64>;
57def FCMP_SUEQ_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SUEQ, "fcmp.sueq.d", FPR64>;
58def FCMP_SLT_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SLT, "fcmp.slt.d", FPR64>;
59def FCMP_SULT_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SULT, "fcmp.sult.d", FPR64>;
60def FCMP_SLE_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SLE, "fcmp.sle.d", FPR64>;
61def FCMP_SULE_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SULE, "fcmp.sule.d", FPR64>;
62def FCMP_SNE_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SNE, "fcmp.sne.d", FPR64>;
63def FCMP_SOR_D  : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SOR, "fcmp.sor.d", FPR64>;
64def FCMP_SUNE_D : FP_CMP<FPCMP_OPC_D, FPCMP_COND_SUNE, "fcmp.sune.d", FPR64>;
65
66// Conversion Instructions
67def FFINT_S_L : FP_CONV<0b0000000100011101000110, "ffint.s.l", FPR32, FPR64>;
68def FTINT_L_S : FP_CONV<0b0000000100011011001001, "ftint.l.s", FPR64, FPR32>;
69def FTINTRM_L_S : FP_CONV<0b0000000100011010001001, "ftintrm.l.s", FPR64,
70                          FPR32>;
71def FTINTRP_L_S : FP_CONV<0b0000000100011010011001, "ftintrp.l.s", FPR64,
72                          FPR32>;
73def FTINTRZ_L_S : FP_CONV<0b0000000100011010101001, "ftintrz.l.s", FPR64,
74                          FPR32>;
75def FTINTRNE_L_S : FP_CONV<0b0000000100011010111001, "ftintrne.l.s", FPR64,
76                           FPR32>;
77def FCVT_S_D : FP_CONV<0b0000000100011001000110, "fcvt.s.d", FPR32, FPR64>;
78def FCVT_D_S : FP_CONV<0b0000000100011001001001, "fcvt.d.s", FPR64, FPR32>;
79def FFINT_D_W : FP_CONV<0b0000000100011101001000, "ffint.d.w", FPR64, FPR32>;
80def FFINT_D_L : FP_CONV<0b0000000100011101001010, "ffint.d.l", FPR64, FPR64>;
81def FTINT_W_D : FP_CONV<0b0000000100011011000010, "ftint.w.d", FPR32, FPR64>;
82def FTINT_L_D : FP_CONV<0b0000000100011011001010, "ftint.l.d", FPR64, FPR64>;
83def FTINTRM_W_D : FP_CONV<0b0000000100011010000010, "ftintrm.w.d", FPR32,
84                          FPR64>;
85def FTINTRM_L_D : FP_CONV<0b0000000100011010001010, "ftintrm.l.d", FPR64,
86                          FPR64>;
87def FTINTRP_W_D : FP_CONV<0b0000000100011010010010, "ftintrp.w.d", FPR32,
88                          FPR64>;
89def FTINTRP_L_D : FP_CONV<0b0000000100011010011010, "ftintrp.l.d", FPR64,
90                          FPR64>;
91def FTINTRZ_W_D : FP_CONV<0b0000000100011010100010, "ftintrz.w.d", FPR32,
92                          FPR64>;
93def FTINTRZ_L_D : FP_CONV<0b0000000100011010101010, "ftintrz.l.d", FPR64,
94                          FPR64>;
95def FTINTRNE_W_D : FP_CONV<0b0000000100011010110010, "ftintrne.w.d", FPR32,
96                           FPR64>;
97def FTINTRNE_L_D : FP_CONV<0b0000000100011010111010, "ftintrne.l.d", FPR64,
98                           FPR64>;
99def FRINT_D : FP_CONV<0b0000000100011110010010, "frint.d", FPR64, FPR64>;
100
101// Move Instructions
102def FMOV_D        : FP_MOV<0b0000000100010100100110, "fmov.d", FPR64, FPR64>;
103def MOVFRH2GR_S   : FP_MOV<0b0000000100010100101111, "movfrh2gr.s", GPR, FPR64>;
104let isCodeGenOnly = 1 in {
105def MOVFR2GR_S_64 : FP_MOV<0b0000000100010100101101, "movfr2gr.s", GPR, FPR64>;
106def FSEL_D : FP_SEL<0b00001101000000, "fsel", FPR64>;
107} // isCodeGenOnly = 1
108let Constraints = "$dst = $out" in {
109def MOVGR2FRH_W : FPFmtMOV<0b0000000100010100101011, (outs FPR64:$out),
110                           (ins FPR64:$dst, GPR:$src), "movgr2frh.w",
111                           "$dst, $src">;
112} // Constraints = "$dst = $out"
113
114// Common Memory Access Instructions
115def FLD_D : FP_LOAD_2RI12<0b0010101110, "fld.d", FPR64>;
116def FST_D : FP_STORE_2RI12<0b0010101111, "fst.d", FPR64>;
117def FLDX_D : FP_LOAD_3R<0b00111000001101000, "fldx.d", FPR64>;
118def FSTX_D : FP_STORE_3R<0b00111000001111000, "fstx.d", FPR64>;
119
120// Bound Check Memory Access Instructions
121def FLDGT_D : FP_LOAD_3R<0b00111000011101001, "fldgt.d", FPR64>;
122def FLDLE_D : FP_LOAD_3R<0b00111000011101011, "fldle.d", FPR64>;
123def FSTGT_D : FP_STORE_3R<0b00111000011101101, "fstgt.d", FPR64>;
124def FSTLE_D : FP_STORE_3R<0b00111000011101111, "fstle.d", FPR64>;
125
126} // Predicates = [HasBasicD]
127
128// Instructions only available on LA64
129let Predicates = [HasBasicD, IsLA64] in {
130def MOVGR2FR_D  : FP_MOV<0b0000000100010100101010, "movgr2fr.d", FPR64, GPR>;
131def MOVFR2GR_D  : FP_MOV<0b0000000100010100101110, "movfr2gr.d", GPR, FPR64>;
132} // Predicates = [HasBasicD, IsLA64]
133
134// Instructions only available on LA32
135let Predicates = [HasBasicD, IsLA32], isCodeGenOnly = 1 in {
136def MOVGR2FR_W_64 : FP_MOV<0b0000000100010100101001, "movgr2fr.w", FPR64, GPR>;
137} // Predicates = [HasBasicD, IsLA32], isCodeGenOnly = 1
138
139//===----------------------------------------------------------------------===//
140// Pseudo-instructions and codegen patterns
141//===----------------------------------------------------------------------===//
142
143let Predicates = [HasBasicD] in {
144
145/// Float arithmetic operations
146
147def : PatFprFpr<fadd, FADD_D, FPR64>;
148def : PatFprFpr<fsub, FSUB_D, FPR64>;
149def : PatFprFpr<fmul, FMUL_D, FPR64>;
150def : PatFprFpr<fdiv, FDIV_D, FPR64>;
151def : PatFprFpr<fcopysign, FCOPYSIGN_D, FPR64>;
152def : PatFprFpr<fmaxnum_ieee, FMAX_D, FPR64>;
153def : PatFprFpr<fminnum_ieee, FMIN_D, FPR64>;
154def : PatFpr<fneg, FNEG_D, FPR64>;
155def : PatFpr<fabs, FABS_D, FPR64>;
156def : PatFpr<fsqrt, FSQRT_D, FPR64>;
157
158def : Pat<(fdiv fpimm1, (fsqrt FPR64:$fj)), (FRSQRT_D FPR64:$fj)>;
159
160def : Pat<(fcopysign FPR64:$fj, FPR32:$fk),
161          (FCOPYSIGN_D FPR64:$fj, (FCVT_D_S FPR32:$fk))>;
162def : Pat<(fcopysign FPR32:$fj, FPR64:$fk),
163          (FCOPYSIGN_S FPR32:$fj, (FCVT_S_D FPR64:$fk))>;
164
165def : Pat<(fcanonicalize FPR64:$fj), (FMAX_D $fj, $fj)>;
166
167/// Setcc
168
169// Match non-signaling comparison
170
171// SETOGT/SETOGE/SETUGT/SETUGE/SETGE/SETNE/SETGT will expand into
172// SETOLT/SETOLE/SETULT/SETULE/SETLE/SETEQ/SETLT.
173def : PatFPSetcc<SETOEQ, FCMP_CEQ_D,  FPR64>;
174def : PatFPSetcc<SETEQ,  FCMP_CEQ_D,  FPR64>;
175def : PatFPSetcc<SETOLT, FCMP_CLT_D,  FPR64>;
176def : PatFPSetcc<SETOLE, FCMP_CLE_D,  FPR64>;
177def : PatFPSetcc<SETLE,  FCMP_CLE_D,  FPR64>;
178def : PatFPSetcc<SETONE, FCMP_CNE_D,  FPR64>;
179def : PatFPSetcc<SETO,   FCMP_COR_D,  FPR64>;
180def : PatFPSetcc<SETUEQ, FCMP_CUEQ_D, FPR64>;
181def : PatFPSetcc<SETULT, FCMP_CULT_D, FPR64>;
182def : PatFPSetcc<SETULE, FCMP_CULE_D, FPR64>;
183def : PatFPSetcc<SETUNE, FCMP_CUNE_D, FPR64>;
184def : PatFPSetcc<SETUO,  FCMP_CUN_D,  FPR64>;
185def : PatFPSetcc<SETLT,  FCMP_CLT_D,  FPR64>;
186
187defm : PatFPBrcond<SETOEQ, FCMP_CEQ_D, FPR64>;
188defm : PatFPBrcond<SETOLT, FCMP_CLT_D, FPR64>;
189defm : PatFPBrcond<SETOLE, FCMP_CLE_D, FPR64>;
190defm : PatFPBrcond<SETONE, FCMP_CNE_D, FPR64>;
191defm : PatFPBrcond<SETO,   FCMP_COR_D, FPR64>;
192defm : PatFPBrcond<SETUEQ, FCMP_CUEQ_D, FPR64>;
193defm : PatFPBrcond<SETULT, FCMP_CULT_D, FPR64>;
194defm : PatFPBrcond<SETULE, FCMP_CULE_D, FPR64>;
195defm : PatFPBrcond<SETUNE, FCMP_CUNE_D, FPR64>;
196defm : PatFPBrcond<SETUO,  FCMP_CUN_D, FPR64>;
197defm : PatFPBrcond<SETLT,  FCMP_CLT_D, FPR64>;
198
199// Match signaling comparison
200
201def : PatStrictFsetccs<SETOEQ, FCMP_SEQ_D,  FPR64>;
202def : PatStrictFsetccs<SETOLT, FCMP_SLT_D,  FPR64>;
203def : PatStrictFsetccs<SETOLE, FCMP_SLE_D,  FPR64>;
204def : PatStrictFsetccs<SETONE, FCMP_SNE_D,  FPR64>;
205def : PatStrictFsetccs<SETO,   FCMP_SOR_D,  FPR64>;
206def : PatStrictFsetccs<SETUEQ, FCMP_SUEQ_D, FPR64>;
207def : PatStrictFsetccs<SETULT, FCMP_SULT_D, FPR64>;
208def : PatStrictFsetccs<SETULE, FCMP_SULE_D, FPR64>;
209def : PatStrictFsetccs<SETUNE, FCMP_SUNE_D, FPR64>;
210def : PatStrictFsetccs<SETUO,  FCMP_SUN_D,  FPR64>;
211def : PatStrictFsetccs<SETLT,  FCMP_SLT_D,  FPR64>;
212
213/// Select
214
215def : Pat<(select CFR:$cc, FPR64:$fk, FPR64:$fj),
216          (FSEL_D FPR64:$fj, FPR64:$fk, CFR:$cc)>;
217
218/// Selectcc
219
220def : PatFPSelectcc<SETOEQ, FCMP_CEQ_D,  FSEL_D, FPR64>;
221def : PatFPSelectcc<SETOLT, FCMP_CLT_D,  FSEL_D, FPR64>;
222def : PatFPSelectcc<SETOLE, FCMP_CLE_D,  FSEL_D, FPR64>;
223def : PatFPSelectcc<SETONE, FCMP_CNE_D,  FSEL_D, FPR64>;
224def : PatFPSelectcc<SETO,   FCMP_COR_D,  FSEL_D, FPR64>;
225def : PatFPSelectcc<SETUEQ, FCMP_CUEQ_D, FSEL_D, FPR64>;
226def : PatFPSelectcc<SETULT, FCMP_CULT_D, FSEL_D, FPR64>;
227def : PatFPSelectcc<SETULE, FCMP_CULE_D, FSEL_D, FPR64>;
228def : PatFPSelectcc<SETUNE, FCMP_CUNE_D, FSEL_D, FPR64>;
229def : PatFPSelectcc<SETUO,  FCMP_CUN_D,  FSEL_D, FPR64>;
230
231/// Loads
232
233defm : LdPat<load, FLD_D, f64>;
234def : RegRegLdPat<load, FLDX_D, f64>;
235
236/// Stores
237
238defm : StPat<store, FST_D, FPR64, f64>;
239def : RegRegStPat<store, FSTX_D, FPR64, f64>;
240
241/// FP conversion operations
242
243def : Pat<(loongarch_ftint FPR64:$src), (FTINTRZ_W_D FPR64:$src)>;
244def : Pat<(f64 (loongarch_ftint FPR64:$src)), (FTINTRZ_L_D FPR64:$src)>;
245def : Pat<(loongarch_ftint FPR32:$src), (FTINTRZ_L_S FPR32:$src)>;
246
247// f64 -> f32
248def : Pat<(f32 (fpround FPR64:$src)), (FCVT_S_D FPR64:$src)>;
249// f32 -> f64
250def : Pat<(f64 (fpextend FPR32:$src)), (FCVT_D_S FPR32:$src)>;
251
252// FP reciprocal operation
253def : Pat<(fdiv fpimm1, FPR64:$src), (FRECIP_D $src)>;
254
255// fmadd.d: fj * fk + fa
256def : Pat<(fma FPR64:$fj, FPR64:$fk, FPR64:$fa), (FMADD_D $fj, $fk, $fa)>;
257
258// fmsub.d: fj * fk - fa
259def : Pat<(fma FPR64:$fj, FPR64:$fk, (fneg FPR64:$fa)),
260          (FMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
261
262// fnmadd.d: -(fj * fk + fa)
263def : Pat<(fneg (fma FPR64:$fj, FPR64:$fk, FPR64:$fa)),
264          (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
265
266// fnmadd.d: -fj * fk - fa (the nsz flag on the FMA)
267def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, (fneg FPR64:$fa)),
268          (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
269
270// fnmsub.d: -(fj * fk - fa)
271def : Pat<(fma (fneg FPR64:$fj), FPR64:$fk, FPR64:$fa),
272          (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
273} // Predicates = [HasBasicD]
274
275/// Floating point constants
276
277let Predicates = [HasBasicD, IsLA64] in {
278def : Pat<(f64 fpimm0), (MOVGR2FR_D R0)>;
279def : Pat<(f64 fpimm0neg), (FNEG_D (MOVGR2FR_D R0))>;
280def : Pat<(f64 fpimm1), (FFINT_D_L (MOVGR2FR_D (ADDI_D R0, 1)))>;
281} // Predicates = [HasBasicD, IsLA64]
282let Predicates = [HasBasicD, IsLA32] in {
283def : Pat<(f64 fpimm0), (MOVGR2FRH_W (MOVGR2FR_W_64 R0), R0)>;
284def : Pat<(f64 fpimm0neg), (FNEG_D (MOVGR2FRH_W (MOVGR2FR_W_64 R0), R0))>;
285def : Pat<(f64 fpimm1), (FCVT_D_S (FFINT_S_W (MOVGR2FR_W (ADDI_W R0, 1))))>;
286} // Predicates = [HasBasicD, IsLA32]
287
288/// Convert int to FP
289
290let Predicates = [HasBasicD, IsLA64] in {
291def : Pat<(f32 (sint_to_fp GPR:$src)), (FFINT_S_L (MOVGR2FR_D GPR:$src))>;
292def : Pat<(f64 (sint_to_fp (i64 (sexti32 (i64 GPR:$src))))),
293          (FFINT_D_W (MOVGR2FR_W GPR:$src))>;
294def : Pat<(f64 (sint_to_fp GPR:$src)), (FFINT_D_L (MOVGR2FR_D GPR:$src))>;
295
296def : Pat<(bitconvert GPR:$src), (MOVGR2FR_D GPR:$src)>;
297} // Predicates = [HasBasicD, IsLA64]
298let Predicates = [HasBasicD, IsLA32] in {
299def : Pat<(f64 (sint_to_fp (i32 GPR:$src))), (FFINT_D_W (MOVGR2FR_W GPR:$src))>;
300} // Predicates = [HasBasicD, IsLA32]
301
302// Convert FP to int
303let Predicates = [HasBasicD, IsLA64] in {
304def : Pat<(bitconvert FPR64:$src), (MOVFR2GR_D FPR64:$src)>;
305} // Predicates = [HasBasicD, IsLA64]
306
307// FP Rounding
308let Predicates = [HasBasicD, IsLA64] in {
309def : PatFpr<frint, FRINT_D, FPR64>;
310} // Predicates = [HasBasicD, IsLA64]
311