1// LoongArchFloat64InstrInfo.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<0x01010000, FPR64>;
21def FSUB_D : FP_ALU_3R<0x01030000, FPR64>;
22def FMUL_D : FP_ALU_3R<0x01050000, FPR64>;
23def FDIV_D : FP_ALU_3R<0x01070000, FPR64>;
24def FMADD_D  : FP_ALU_4R<0x08200000, FPR64>;
25def FMSUB_D  : FP_ALU_4R<0x08600000, FPR64>;
26def FNMADD_D : FP_ALU_4R<0x08a00000, FPR64>;
27def FNMSUB_D : FP_ALU_4R<0x08e00000, FPR64>;
28def FMAX_D  : FP_ALU_3R<0x01090000, FPR64>;
29def FMIN_D  : FP_ALU_3R<0x010b0000, FPR64>;
30def FMAXA_D : FP_ALU_3R<0x010d0000, FPR64>;
31def FMINA_D : FP_ALU_3R<0x010f0000, FPR64>;
32def FABS_D   : FP_ALU_2R<0x01140800, FPR64>;
33def FNEG_D   : FP_ALU_2R<0x01141800, FPR64>;
34def FSQRT_D  : FP_ALU_2R<0x01144800, FPR64>;
35def FRECIP_D : FP_ALU_2R<0x01145800, FPR64>;
36def FRSQRT_D : FP_ALU_2R<0x01146800, FPR64>;
37def FSCALEB_D : FP_ALU_3R<0x01110000, FPR64>;
38def FLOGB_D   : FP_ALU_2R<0x01142800, FPR64>;
39def FCOPYSIGN_D : FP_ALU_3R<0x01130000, FPR64>;
40def FCLASS_D  : FP_ALU_2R<0x01143800, FPR64>;
41
42// Comparison Instructions
43def FCMP_CAF_D  : FP_CMP<0x0c200000, FPR64>;
44def FCMP_CUN_D  : FP_CMP<0x0c240000, FPR64>;
45def FCMP_CEQ_D  : FP_CMP<0x0c220000, FPR64>;
46def FCMP_CUEQ_D : FP_CMP<0x0c260000, FPR64>;
47def FCMP_CLT_D  : FP_CMP<0x0c210000, FPR64>;
48def FCMP_CULT_D : FP_CMP<0x0c250000, FPR64>;
49def FCMP_CLE_D  : FP_CMP<0x0c230000, FPR64>;
50def FCMP_CULE_D : FP_CMP<0x0c270000, FPR64>;
51def FCMP_CNE_D  : FP_CMP<0x0c280000, FPR64>;
52def FCMP_COR_D  : FP_CMP<0x0c2a0000, FPR64>;
53def FCMP_CUNE_D : FP_CMP<0x0c2c0000, FPR64>;
54def FCMP_SAF_D  : FP_CMP<0x0c208000, FPR64>;
55def FCMP_SUN_D  : FP_CMP<0x0c248000, FPR64>;
56def FCMP_SEQ_D  : FP_CMP<0x0c228000, FPR64>;
57def FCMP_SUEQ_D : FP_CMP<0x0c268000, FPR64>;
58def FCMP_SLT_D  : FP_CMP<0x0c218000, FPR64>;
59def FCMP_SULT_D : FP_CMP<0x0c258000, FPR64>;
60def FCMP_SLE_D  : FP_CMP<0x0c238000, FPR64>;
61def FCMP_SULE_D : FP_CMP<0x0c278000, FPR64>;
62def FCMP_SNE_D  : FP_CMP<0x0c288000, FPR64>;
63def FCMP_SOR_D  : FP_CMP<0x0c2a8000, FPR64>;
64def FCMP_SUNE_D : FP_CMP<0x0c2c8000, FPR64>;
65
66// Conversion Instructions
67def FFINT_S_L : FP_CONV<0x011d1800, FPR32, FPR64>;
68def FTINT_L_S : FP_CONV<0x011b2400, FPR64, FPR32>;
69def FTINTRM_L_S : FP_CONV<0x011a2400, FPR64, FPR32>;
70def FTINTRP_L_S : FP_CONV<0x011a6400, FPR64, FPR32>;
71def FTINTRZ_L_S : FP_CONV<0x011aa400, FPR64, FPR32>;
72def FTINTRNE_L_S : FP_CONV<0x011ae400, FPR64, FPR32>;
73def FCVT_S_D : FP_CONV<0x01191800, FPR32, FPR64>;
74def FCVT_D_S : FP_CONV<0x01192400, FPR64, FPR32>;
75def FFINT_D_W : FP_CONV<0x011d2000, FPR64, FPR32>;
76def FFINT_D_L : FP_CONV<0x011d2800, FPR64, FPR64>;
77def FTINT_W_D : FP_CONV<0x011b0800, FPR32, FPR64>;
78def FTINT_L_D : FP_CONV<0x011b2800, FPR64, FPR64>;
79def FTINTRM_W_D : FP_CONV<0x011a0800, FPR32, FPR64>;
80def FTINTRM_L_D : FP_CONV<0x011a2800, FPR64, FPR64>;
81def FTINTRP_W_D : FP_CONV<0x011a4800, FPR32, FPR64>;
82def FTINTRP_L_D : FP_CONV<0x011a6800, FPR64, FPR64>;
83def FTINTRZ_W_D : FP_CONV<0x011a8800, FPR32, FPR64>;
84def FTINTRZ_L_D : FP_CONV<0x011aa800, FPR64, FPR64>;
85def FTINTRNE_W_D : FP_CONV<0x011ac800, FPR32, FPR64>;
86def FTINTRNE_L_D : FP_CONV<0x011ae800, FPR64, FPR64>;
87def FRINT_D : FP_CONV<0x011e4800, FPR64, FPR64>;
88
89// Move Instructions
90def FMOV_D        : FP_MOV<0x01149800, FPR64, FPR64>;
91def MOVFRH2GR_S   : FP_MOV<0x0114bc00, GPR, FPR64>;
92let isCodeGenOnly = 1 in {
93def MOVFR2GR_S_64 : FP_MOV<0x0114b400, GPR, FPR64>;
94def FSEL_xD : FP_SEL<0x0d000000, FPR64>;
95} // isCodeGenOnly = 1
96let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Constraints = "$dst = $out" in {
97def MOVGR2FRH_W : FPFmtMOV<0x0114ac00, (outs FPR64:$out),
98                           (ins FPR64:$dst, GPR:$src),
99                           "$dst, $src">;
100} // hasSideEffects = 0, mayLoad = 0, mayStore = 0, Constraints = "$dst = $out"
101
102// Common Memory Access Instructions
103def FLD_D : FP_LOAD_2RI12<0x2b800000, FPR64>;
104def FST_D : FP_STORE_2RI12<0x2bc00000, FPR64>;
105def FLDX_D : FP_LOAD_3R<0x38340000, FPR64>;
106def FSTX_D : FP_STORE_3R<0x383c0000, FPR64>;
107
108// Bound Check Memory Access Instructions
109def FLDGT_D : FP_LOAD_3R<0x38748000, FPR64>;
110def FLDLE_D : FP_LOAD_3R<0x38758000, FPR64>;
111def FSTGT_D : FP_STORE_3R<0x38768000, FPR64>;
112def FSTLE_D : FP_STORE_3R<0x38778000, FPR64>;
113
114} // Predicates = [HasBasicD]
115
116// Instructions only available on LA64
117let Predicates = [HasBasicD, IsLA64] in {
118def MOVGR2FR_D  : FP_MOV<0x0114a800, FPR64, GPR>;
119def MOVFR2GR_D  : FP_MOV<0x0114b800, GPR, FPR64>;
120} // Predicates = [HasBasicD, IsLA64]
121
122// Instructions only available on LA32
123let Predicates = [HasBasicD, IsLA32], isCodeGenOnly = 1 in {
124def MOVGR2FR_W_64 : FP_MOV<0x0114a400, FPR64, GPR>;
125} // Predicates = [HasBasicD, IsLA32], isCodeGenOnly = 1
126
127//===----------------------------------------------------------------------===//
128// Pseudo-instructions and codegen patterns
129//===----------------------------------------------------------------------===//
130
131let Predicates = [HasBasicD] in {
132
133/// Float arithmetic operations
134
135def : PatFprFpr<fadd, FADD_D, FPR64>;
136def : PatFprFpr<fsub, FSUB_D, FPR64>;
137def : PatFprFpr<fmul, FMUL_D, FPR64>;
138def : PatFprFpr<fdiv, FDIV_D, FPR64>;
139def : PatFprFpr<fcopysign, FCOPYSIGN_D, FPR64>;
140def : PatFprFpr<fmaxnum_ieee, FMAX_D, FPR64>;
141def : PatFprFpr<fminnum_ieee, FMIN_D, FPR64>;
142def : PatFpr<fneg, FNEG_D, FPR64>;
143def : PatFpr<fabs, FABS_D, FPR64>;
144def : PatFpr<fsqrt, FSQRT_D, FPR64>;
145def : Pat<(fdiv fpimm1, (fsqrt FPR64:$fj)), (FRSQRT_D FPR64:$fj)>;
146def : Pat<(fcopysign FPR64:$fj, FPR32:$fk),
147          (FCOPYSIGN_D FPR64:$fj, (FCVT_D_S FPR32:$fk))>;
148def : Pat<(fcopysign FPR32:$fj, FPR64:$fk),
149          (FCOPYSIGN_S FPR32:$fj, (FCVT_S_D FPR64:$fk))>;
150def : Pat<(fcanonicalize FPR64:$fj), (FMAX_D $fj, $fj)>;
151let Predicates = [IsLA32] in {
152def : Pat<(is_fpclass FPR64:$fj, (i32 timm:$mask)),
153          (SLTU R0, (ANDI (MOVFR2GR_S_64 (FCLASS_D FPR64:$fj)),
154                          (to_fclass_mask timm:$mask)))>;
155} // Predicates = [IsLA32]
156let Predicates = [IsLA64] in {
157def : Pat<(is_fpclass FPR64:$fj, (i32 timm:$mask)),
158          (SLTU R0, (ANDI (MOVFR2GR_D (FCLASS_D FPR64:$fj)),
159                          (to_fclass_mask timm:$mask)))>;
160} // Predicates = [IsLA64]
161
162/// Setcc
163
164// Match non-signaling comparison
165
166// SETOGT/SETOGE/SETUGT/SETUGE/SETGE/SETNE/SETGT will expand into
167// SETOLT/SETOLE/SETULT/SETULE/SETLE/SETEQ/SETLT.
168def : PatFPSetcc<SETOEQ, FCMP_CEQ_D,  FPR64>;
169def : PatFPSetcc<SETEQ,  FCMP_CEQ_D,  FPR64>;
170def : PatFPSetcc<SETOLT, FCMP_CLT_D,  FPR64>;
171def : PatFPSetcc<SETOLE, FCMP_CLE_D,  FPR64>;
172def : PatFPSetcc<SETLE,  FCMP_CLE_D,  FPR64>;
173def : PatFPSetcc<SETONE, FCMP_CNE_D,  FPR64>;
174def : PatFPSetcc<SETO,   FCMP_COR_D,  FPR64>;
175def : PatFPSetcc<SETUEQ, FCMP_CUEQ_D, FPR64>;
176def : PatFPSetcc<SETULT, FCMP_CULT_D, FPR64>;
177def : PatFPSetcc<SETULE, FCMP_CULE_D, FPR64>;
178def : PatFPSetcc<SETUNE, FCMP_CUNE_D, FPR64>;
179def : PatFPSetcc<SETUO,  FCMP_CUN_D,  FPR64>;
180def : PatFPSetcc<SETLT,  FCMP_CLT_D,  FPR64>;
181
182defm : PatFPBrcond<SETOEQ, FCMP_CEQ_D, FPR64>;
183defm : PatFPBrcond<SETOLT, FCMP_CLT_D, FPR64>;
184defm : PatFPBrcond<SETOLE, FCMP_CLE_D, FPR64>;
185defm : PatFPBrcond<SETONE, FCMP_CNE_D, FPR64>;
186defm : PatFPBrcond<SETO,   FCMP_COR_D, FPR64>;
187defm : PatFPBrcond<SETUEQ, FCMP_CUEQ_D, FPR64>;
188defm : PatFPBrcond<SETULT, FCMP_CULT_D, FPR64>;
189defm : PatFPBrcond<SETULE, FCMP_CULE_D, FPR64>;
190defm : PatFPBrcond<SETUNE, FCMP_CUNE_D, FPR64>;
191defm : PatFPBrcond<SETUO,  FCMP_CUN_D, FPR64>;
192defm : PatFPBrcond<SETLT,  FCMP_CLT_D, FPR64>;
193
194// Match signaling comparison
195
196def : PatStrictFsetccs<SETOEQ, FCMP_SEQ_D,  FPR64>;
197def : PatStrictFsetccs<SETOLT, FCMP_SLT_D,  FPR64>;
198def : PatStrictFsetccs<SETOLE, FCMP_SLE_D,  FPR64>;
199def : PatStrictFsetccs<SETONE, FCMP_SNE_D,  FPR64>;
200def : PatStrictFsetccs<SETO,   FCMP_SOR_D,  FPR64>;
201def : PatStrictFsetccs<SETUEQ, FCMP_SUEQ_D, FPR64>;
202def : PatStrictFsetccs<SETULT, FCMP_SULT_D, FPR64>;
203def : PatStrictFsetccs<SETULE, FCMP_SULE_D, FPR64>;
204def : PatStrictFsetccs<SETUNE, FCMP_SUNE_D, FPR64>;
205def : PatStrictFsetccs<SETUO,  FCMP_SUN_D,  FPR64>;
206def : PatStrictFsetccs<SETLT,  FCMP_SLT_D,  FPR64>;
207
208/// Select
209
210def : Pat<(select CFR:$cc, FPR64:$fk, FPR64:$fj),
211          (FSEL_xD FPR64:$fj, FPR64:$fk, CFR:$cc)>;
212
213/// Selectcc
214
215def : PatFPSelectcc<SETOEQ, FCMP_CEQ_D,  FSEL_xD, FPR64>;
216def : PatFPSelectcc<SETOLT, FCMP_CLT_D,  FSEL_xD, FPR64>;
217def : PatFPSelectcc<SETOLE, FCMP_CLE_D,  FSEL_xD, FPR64>;
218def : PatFPSelectcc<SETONE, FCMP_CNE_D,  FSEL_xD, FPR64>;
219def : PatFPSelectcc<SETO,   FCMP_COR_D,  FSEL_xD, FPR64>;
220def : PatFPSelectcc<SETUEQ, FCMP_CUEQ_D, FSEL_xD, FPR64>;
221def : PatFPSelectcc<SETULT, FCMP_CULT_D, FSEL_xD, FPR64>;
222def : PatFPSelectcc<SETULE, FCMP_CULE_D, FSEL_xD, FPR64>;
223def : PatFPSelectcc<SETUNE, FCMP_CUNE_D, FSEL_xD, FPR64>;
224def : PatFPSelectcc<SETUO,  FCMP_CUN_D,  FSEL_xD, FPR64>;
225
226/// Loads
227
228defm : LdPat<load, FLD_D, f64>;
229def : RegRegLdPat<load, FLDX_D, f64>;
230
231/// Stores
232
233defm : StPat<store, FST_D, FPR64, f64>;
234def : RegRegStPat<store, FSTX_D, FPR64, f64>;
235
236/// FP conversion operations
237
238def : Pat<(loongarch_ftint FPR64:$src), (FTINTRZ_W_D FPR64:$src)>;
239def : Pat<(f64 (loongarch_ftint FPR64:$src)), (FTINTRZ_L_D FPR64:$src)>;
240def : Pat<(loongarch_ftint FPR32:$src), (FTINTRZ_L_S FPR32:$src)>;
241
242// f64 -> f32
243def : Pat<(f32 (fpround FPR64:$src)), (FCVT_S_D FPR64:$src)>;
244// f32 -> f64
245def : Pat<(f64 (fpextend FPR32:$src)), (FCVT_D_S FPR32:$src)>;
246
247// FP reciprocal operation
248def : Pat<(fdiv fpimm1, FPR64:$src), (FRECIP_D $src)>;
249
250// fmadd.d: fj * fk + fa
251def : Pat<(fma FPR64:$fj, FPR64:$fk, FPR64:$fa), (FMADD_D $fj, $fk, $fa)>;
252
253// fmsub.d: fj * fk - fa
254def : Pat<(fma FPR64:$fj, FPR64:$fk, (fneg FPR64:$fa)),
255          (FMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
256
257// fnmadd.d: -(fj * fk + fa)
258def : Pat<(fneg (fma FPR64:$fj, FPR64:$fk, FPR64:$fa)),
259          (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
260
261// fnmadd.d: -fj * fk - fa (the nsz flag on the FMA)
262def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, (fneg FPR64:$fa)),
263          (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
264
265// fnmsub.d: -(fj * fk - fa)
266def : Pat<(fneg (fma FPR64:$fj, FPR64:$fk, (fneg FPR64:$fa))),
267          (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
268
269// fnmsub.d: -fj * fk + fa (the nsz flag on the FMA)
270def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, FPR64:$fa),
271          (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
272} // Predicates = [HasBasicD]
273
274/// Floating point constants
275
276let Predicates = [HasBasicD, IsLA64] in {
277def : Pat<(f64 fpimm0), (MOVGR2FR_D R0)>;
278def : Pat<(f64 fpimm0neg), (FNEG_D (MOVGR2FR_D R0))>;
279def : Pat<(f64 fpimm1), (FFINT_D_L (MOVGR2FR_D (ADDI_D R0, 1)))>;
280} // Predicates = [HasBasicD, IsLA64]
281let Predicates = [HasBasicD, IsLA32] in {
282def : Pat<(f64 fpimm0), (MOVGR2FRH_W (MOVGR2FR_W_64 R0), R0)>;
283def : Pat<(f64 fpimm0neg), (FNEG_D (MOVGR2FRH_W (MOVGR2FR_W_64 R0), R0))>;
284def : Pat<(f64 fpimm1), (FCVT_D_S (FFINT_S_W (MOVGR2FR_W (ADDI_W R0, 1))))>;
285} // Predicates = [HasBasicD, IsLA32]
286
287/// Convert int to FP
288
289let Predicates = [HasBasicD, IsLA64] in {
290def : Pat<(f32 (sint_to_fp GPR:$src)), (FFINT_S_L (MOVGR2FR_D GPR:$src))>;
291def : Pat<(f64 (sint_to_fp (i64 (sexti32 (i64 GPR:$src))))),
292          (FFINT_D_W (MOVGR2FR_W GPR:$src))>;
293def : Pat<(f64 (sint_to_fp GPR:$src)), (FFINT_D_L (MOVGR2FR_D GPR:$src))>;
294
295def : Pat<(bitconvert GPR:$src), (MOVGR2FR_D GPR:$src)>;
296} // Predicates = [HasBasicD, IsLA64]
297let Predicates = [HasBasicD, IsLA32] in {
298def : Pat<(f64 (sint_to_fp (i32 GPR:$src))), (FFINT_D_W (MOVGR2FR_W GPR:$src))>;
299} // Predicates = [HasBasicD, IsLA32]
300
301// Convert FP to int
302let Predicates = [HasBasicD, IsLA64] in {
303def : Pat<(bitconvert FPR64:$src), (MOVFR2GR_D FPR64:$src)>;
304} // Predicates = [HasBasicD, IsLA64]
305
306// FP Rounding
307let Predicates = [HasBasicD, IsLA64] in {
308def : PatFpr<frint, FRINT_D, FPR64>;
309} // Predicates = [HasBasicD, IsLA64]
310