]> gcc.gnu.org Git - gcc.git/blame - gcc/config/loongarch/loongarch-builtins.cc
LoongArch: Add Loongson SX base instruction support.
[gcc.git] / gcc / config / loongarch / loongarch-builtins.cc
CommitLineData
2aca9d5b 1/* Subroutines used for expanding LoongArch builtins.
83ffe9cd 2 Copyright (C) 2021-2023 Free Software Foundation, Inc.
2aca9d5b 3 Contributed by Loongson Ltd.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#define IN_TARGET_CODE 1
22
23#include "config.h"
24#include "system.h"
25#include "coretypes.h"
26#include "backend.h"
27#include "target.h"
28#include "rtl.h"
29#include "tree.h"
30#include "memmodel.h"
31#include "gimple.h"
32#include "tm_p.h"
33#include "optabs.h"
34#include "recog.h"
35#include "diagnostic.h"
36#include "fold-const.h"
37#include "expr.h"
38#include "langhooks.h"
c9b4c79e 39#include "emit-rtl.h"
2aca9d5b 40
41/* Macros to create an enumeration identifier for a function prototype. */
42#define LARCH_FTYPE_NAME1(A, B) LARCH_##A##_FTYPE_##B
43#define LARCH_FTYPE_NAME2(A, B, C) LARCH_##A##_FTYPE_##B##_##C
44#define LARCH_FTYPE_NAME3(A, B, C, D) LARCH_##A##_FTYPE_##B##_##C##_##D
45
46/* Classifies the prototype of a built-in function. */
47enum loongarch_function_type
48{
49#define DEF_LARCH_FTYPE(NARGS, LIST) LARCH_FTYPE_NAME##NARGS LIST,
50#include "config/loongarch/loongarch-ftypes.def"
51#undef DEF_LARCH_FTYPE
52 LARCH_MAX_FTYPE_MAX
53};
54
55/* Specifies how a built-in function should be converted into rtl. */
56enum loongarch_builtin_type
57{
58 /* The function corresponds directly to an .md pattern. The return
59 value is mapped to operand 0 and the arguments are mapped to
60 operands 1 and above. */
61 LARCH_BUILTIN_DIRECT,
62
63 /* The function corresponds directly to an .md pattern. There is no return
64 value and the arguments are mapped to operands 0 and above. */
65 LARCH_BUILTIN_DIRECT_NO_TARGET,
66
67};
68
69/* Declare an availability predicate for built-in functions that require
70 * COND to be true. NAME is the main part of the predicate's name. */
71#define AVAIL_ALL(NAME, COND) \
72 static unsigned int \
73 loongarch_builtin_avail_##NAME (void) \
74 { \
75 return (COND) ? 1 : 0; \
76 }
77
78static unsigned int
79loongarch_builtin_avail_default (void)
80{
81 return 1;
82}
83/* This structure describes a single built-in function. */
84struct loongarch_builtin_description
85{
86 /* The code of the main .md file instruction. See loongarch_builtin_type
87 for more information. */
88 enum insn_code icode;
89
90 /* The name of the built-in function. */
91 const char *name;
92
93 /* Specifies how the function should be expanded. */
94 enum loongarch_builtin_type builtin_type;
95
96 /* The function's prototype. */
97 enum loongarch_function_type function_type;
98
99 /* Whether the function is available. */
100 unsigned int (*avail) (void);
101};
102
103AVAIL_ALL (hard_float, TARGET_HARD_FLOAT_ABI)
104
105/* Construct a loongarch_builtin_description from the given arguments.
106
107 INSN is the name of the associated instruction pattern, without the
108 leading CODE_FOR_loongarch_.
109
110 CODE is the floating-point condition code associated with the
111 function. It can be 'f' if the field is not applicable.
112
113 NAME is the name of the function itself, without the leading
114 "__builtin_loongarch_".
115
116 BUILTIN_TYPE and FUNCTION_TYPE are loongarch_builtin_description fields.
117
118 AVAIL is the name of the availability predicate, without the leading
119 loongarch_builtin_avail_. */
120#define LARCH_BUILTIN(INSN, NAME, BUILTIN_TYPE, FUNCTION_TYPE, AVAIL) \
121 { \
122 CODE_FOR_loongarch_##INSN, "__builtin_loongarch_" NAME, \
123 BUILTIN_TYPE, FUNCTION_TYPE, \
124 loongarch_builtin_avail_##AVAIL \
125 }
126
127/* Define __builtin_loongarch_<INSN>, which is a LARCH_BUILTIN_DIRECT function
128 mapped to instruction CODE_FOR_loongarch_<INSN>, FUNCTION_TYPE and AVAIL
129 are as for LARCH_BUILTIN. */
130#define DIRECT_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \
131 LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT, FUNCTION_TYPE, AVAIL)
132
133/* Define __builtin_loongarch_<INSN>, which is a LARCH_BUILTIN_DIRECT_NO_TARGET
134 function mapped to instruction CODE_FOR_loongarch_<INSN>, FUNCTION_TYPE
135 and AVAIL are as for LARCH_BUILTIN. */
136#define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \
137 LARCH_BUILTIN (INSN, #INSN, LARCH_BUILTIN_DIRECT_NO_TARGET, \
138 FUNCTION_TYPE, AVAIL)
139
140static const struct loongarch_builtin_description loongarch_builtins[] = {
141#define LARCH_MOVFCSR2GR 0
142 DIRECT_BUILTIN (movfcsr2gr, LARCH_USI_FTYPE_UQI, hard_float),
143#define LARCH_MOVGR2FCSR 1
144 DIRECT_NO_TARGET_BUILTIN (movgr2fcsr, LARCH_VOID_FTYPE_UQI_USI, hard_float),
145
146 DIRECT_NO_TARGET_BUILTIN (cacop_w, LARCH_VOID_FTYPE_USI_USI_SI, default),
147 DIRECT_NO_TARGET_BUILTIN (cacop_d, LARCH_VOID_FTYPE_USI_UDI_SI, default),
148 DIRECT_NO_TARGET_BUILTIN (dbar, LARCH_VOID_FTYPE_USI, default),
149 DIRECT_NO_TARGET_BUILTIN (ibar, LARCH_VOID_FTYPE_USI, default),
150
151 DIRECT_BUILTIN (lddir_d, LARCH_DI_FTYPE_DI_UQI, default),
152 DIRECT_BUILTIN (lddir_w, LARCH_SI_FTYPE_SI_UQI, default),
153 DIRECT_NO_TARGET_BUILTIN (ldpte_d, LARCH_VOID_FTYPE_DI_UQI, default),
154 DIRECT_NO_TARGET_BUILTIN (ldpte_w, LARCH_VOID_FTYPE_SI_UQI, default),
155
156 /* CRC Instrinsic */
157
158 DIRECT_BUILTIN (crc_w_b_w, LARCH_SI_FTYPE_QI_SI, default),
159 DIRECT_BUILTIN (crc_w_h_w, LARCH_SI_FTYPE_HI_SI, default),
160 DIRECT_BUILTIN (crc_w_w_w, LARCH_SI_FTYPE_SI_SI, default),
161 DIRECT_BUILTIN (crc_w_d_w, LARCH_SI_FTYPE_DI_SI, default),
162 DIRECT_BUILTIN (crcc_w_b_w, LARCH_SI_FTYPE_QI_SI, default),
163 DIRECT_BUILTIN (crcc_w_h_w, LARCH_SI_FTYPE_HI_SI, default),
164 DIRECT_BUILTIN (crcc_w_w_w, LARCH_SI_FTYPE_SI_SI, default),
165 DIRECT_BUILTIN (crcc_w_d_w, LARCH_SI_FTYPE_DI_SI, default),
166
167 DIRECT_BUILTIN (csrrd_w, LARCH_USI_FTYPE_USI, default),
168 DIRECT_BUILTIN (csrrd_d, LARCH_UDI_FTYPE_USI, default),
169 DIRECT_BUILTIN (csrwr_w, LARCH_USI_FTYPE_USI_USI, default),
170 DIRECT_BUILTIN (csrwr_d, LARCH_UDI_FTYPE_UDI_USI, default),
171 DIRECT_BUILTIN (csrxchg_w, LARCH_USI_FTYPE_USI_USI_USI, default),
172 DIRECT_BUILTIN (csrxchg_d, LARCH_UDI_FTYPE_UDI_UDI_USI, default),
173 DIRECT_BUILTIN (iocsrrd_b, LARCH_UQI_FTYPE_USI, default),
174 DIRECT_BUILTIN (iocsrrd_h, LARCH_UHI_FTYPE_USI, default),
175 DIRECT_BUILTIN (iocsrrd_w, LARCH_USI_FTYPE_USI, default),
176 DIRECT_BUILTIN (iocsrrd_d, LARCH_UDI_FTYPE_USI, default),
177 DIRECT_NO_TARGET_BUILTIN (iocsrwr_b, LARCH_VOID_FTYPE_UQI_USI, default),
178 DIRECT_NO_TARGET_BUILTIN (iocsrwr_h, LARCH_VOID_FTYPE_UHI_USI, default),
179 DIRECT_NO_TARGET_BUILTIN (iocsrwr_w, LARCH_VOID_FTYPE_USI_USI, default),
180 DIRECT_NO_TARGET_BUILTIN (iocsrwr_d, LARCH_VOID_FTYPE_UDI_USI, default),
181
182 DIRECT_BUILTIN (cpucfg, LARCH_USI_FTYPE_USI, default),
183 DIRECT_NO_TARGET_BUILTIN (asrtle_d, LARCH_VOID_FTYPE_DI_DI, default),
184 DIRECT_NO_TARGET_BUILTIN (asrtgt_d, LARCH_VOID_FTYPE_DI_DI, default),
185 DIRECT_NO_TARGET_BUILTIN (syscall, LARCH_VOID_FTYPE_USI, default),
186 DIRECT_NO_TARGET_BUILTIN (break, LARCH_VOID_FTYPE_USI, default),
187};
188
189/* Index I is the function declaration for loongarch_builtins[I], or null if
190 the function isn't defined on this target. */
191static GTY (()) tree loongarch_builtin_decls[ARRAY_SIZE (loongarch_builtins)];
192/* Get the index I of the function declaration for loongarch_builtin_decls[I]
193 using the instruction code or return null if not defined for the target. */
194static GTY (()) int loongarch_get_builtin_decl_index[NUM_INSN_CODES];
195
196/* Source-level argument types. */
197#define LARCH_ATYPE_VOID void_type_node
198#define LARCH_ATYPE_INT integer_type_node
199#define LARCH_ATYPE_POINTER ptr_type_node
200
201/* Standard mode-based argument types. */
202#define LARCH_ATYPE_QI intQI_type_node
203#define LARCH_ATYPE_UQI unsigned_intQI_type_node
204#define LARCH_ATYPE_HI intHI_type_node
205#define LARCH_ATYPE_UHI unsigned_intHI_type_node
206#define LARCH_ATYPE_SI intSI_type_node
207#define LARCH_ATYPE_USI unsigned_intSI_type_node
208#define LARCH_ATYPE_DI intDI_type_node
209#define LARCH_ATYPE_UDI unsigned_intDI_type_node
210#define LARCH_ATYPE_SF float_type_node
211#define LARCH_ATYPE_DF double_type_node
212
213/* LARCH_FTYPE_ATYPESN takes N LARCH_FTYPES-like type codes and lists
214 their associated LARCH_ATYPEs. */
215#define LARCH_FTYPE_ATYPES1(A, B) LARCH_ATYPE_##A, LARCH_ATYPE_##B
216
217#define LARCH_FTYPE_ATYPES2(A, B, C) \
218 LARCH_ATYPE_##A, LARCH_ATYPE_##B, LARCH_ATYPE_##C
219
220#define LARCH_FTYPE_ATYPES3(A, B, C, D) \
221 LARCH_ATYPE_##A, LARCH_ATYPE_##B, LARCH_ATYPE_##C, LARCH_ATYPE_##D
222
223#define LARCH_FTYPE_ATYPES4(A, B, C, D, E) \
224 LARCH_ATYPE_##A, LARCH_ATYPE_##B, LARCH_ATYPE_##C, LARCH_ATYPE_##D, \
225 LARCH_ATYPE_##E
226
227/* Return the function type associated with function prototype TYPE. */
228
229static tree
230loongarch_build_function_type (enum loongarch_function_type type)
231{
232 static tree types[(int) LARCH_MAX_FTYPE_MAX];
233
234 if (types[(int) type] == NULL_TREE)
235 switch (type)
236 {
237#define DEF_LARCH_FTYPE(NUM, ARGS) \
238 case LARCH_FTYPE_NAME##NUM ARGS: \
239 types[(int) type] \
240 = build_function_type_list (LARCH_FTYPE_ATYPES##NUM ARGS, NULL_TREE); \
241 break;
242#include "config/loongarch/loongarch-ftypes.def"
243#undef DEF_LARCH_FTYPE
244 default:
245 gcc_unreachable ();
246 }
247
248 return types[(int) type];
249}
250
251/* Implement TARGET_INIT_BUILTINS. */
252
253void
254loongarch_init_builtins (void)
255{
256 const struct loongarch_builtin_description *d;
257 unsigned int i;
258 tree type;
259
4e2d53c9 260 /* Register the type float128_type_node as a built-in type and
261 give it an alias "__float128". */
262 (*lang_hooks.types.register_builtin_type) (float128_type_node,
263 "__float128");
264
2aca9d5b 265 /* Iterate through all of the bdesc arrays, initializing all of the
266 builtin functions. */
267 for (i = 0; i < ARRAY_SIZE (loongarch_builtins); i++)
268 {
269 d = &loongarch_builtins[i];
270 if (d->avail ())
271 {
272 type = loongarch_build_function_type (d->function_type);
273 loongarch_builtin_decls[i]
274 = add_builtin_function (d->name, type, i, BUILT_IN_MD, NULL,
275 NULL);
276 loongarch_get_builtin_decl_index[d->icode] = i;
277 }
278 }
279}
280
281/* Implement TARGET_BUILTIN_DECL. */
282
283tree
284loongarch_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
285{
286 if (code >= ARRAY_SIZE (loongarch_builtins))
287 return error_mark_node;
288 return loongarch_builtin_decls[code];
289}
290
291/* Take argument ARGNO from EXP's argument list and convert it into
292 an expand operand. Store the operand in *OP. */
293
294static void
295loongarch_prepare_builtin_arg (struct expand_operand *op, tree exp,
296 unsigned int argno)
297{
298 tree arg;
299 rtx value;
300
301 arg = CALL_EXPR_ARG (exp, argno);
302 value = expand_normal (arg);
303 create_input_operand (op, value, TYPE_MODE (TREE_TYPE (arg)));
304}
305
c9b4c79e
LC
306/* Return a const_int vector of VAL with mode MODE. */
307
308rtx
309loongarch_gen_const_int_vector (machine_mode mode, HOST_WIDE_INT val)
310{
311 rtx c = gen_int_mode (val, GET_MODE_INNER (mode));
312 return gen_const_vec_duplicate (mode, c);
313}
314
2aca9d5b 315/* Expand instruction ICODE as part of a built-in function sequence.
316 Use the first NOPS elements of OPS as the instruction's operands.
317 HAS_TARGET_P is true if operand 0 is a target; it is false if the
318 instruction has no target.
319
320 Return the target rtx if HAS_TARGET_P, otherwise return const0_rtx. */
321
322static rtx
323loongarch_expand_builtin_insn (enum insn_code icode, unsigned int nops,
324 struct expand_operand *ops, bool has_target_p)
325{
326 if (!maybe_expand_insn (icode, nops, ops))
327 {
328 error ("invalid argument to built-in function");
329 return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx;
330 }
331 return has_target_p ? ops[0].value : const0_rtx;
332}
333
334/* Expand a LARCH_BUILTIN_DIRECT or LARCH_BUILTIN_DIRECT_NO_TARGET function;
335 HAS_TARGET_P says which. EXP is the CALL_EXPR that calls the function
336 and ICODE is the code of the associated .md pattern. TARGET, if nonnull,
337 suggests a good place to put the result. */
338
339static rtx
340loongarch_expand_builtin_direct (enum insn_code icode, rtx target, tree exp,
341 bool has_target_p)
342{
343 struct expand_operand ops[MAX_RECOG_OPERANDS];
344 int opno, argno;
345
346 /* Map any target to operand 0. */
347 opno = 0;
348 if (has_target_p)
349 create_output_operand (&ops[opno++], target, TYPE_MODE (TREE_TYPE (exp)));
350
351 /* Map the arguments to the other operands. */
352 gcc_assert (opno + call_expr_nargs (exp)
353 == insn_data[icode].n_generator_args);
354 for (argno = 0; argno < call_expr_nargs (exp); argno++)
355 loongarch_prepare_builtin_arg (&ops[opno++], exp, argno);
356
357 return loongarch_expand_builtin_insn (icode, opno, ops, has_target_p);
358}
359
360/* Implement TARGET_EXPAND_BUILTIN. */
361
362rtx
363loongarch_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
364 machine_mode mode ATTRIBUTE_UNUSED,
365 int ignore ATTRIBUTE_UNUSED)
366{
367 tree fndecl;
368 unsigned int fcode, avail;
369 const struct loongarch_builtin_description *d;
370
371 fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
372 fcode = DECL_MD_FUNCTION_CODE (fndecl);
373 gcc_assert (fcode < ARRAY_SIZE (loongarch_builtins));
374 d = &loongarch_builtins[fcode];
375 avail = d->avail ();
376 gcc_assert (avail != 0);
377 switch (d->builtin_type)
378 {
379 case LARCH_BUILTIN_DIRECT:
380 return loongarch_expand_builtin_direct (d->icode, target, exp, true);
381
382 case LARCH_BUILTIN_DIRECT_NO_TARGET:
383 return loongarch_expand_builtin_direct (d->icode, target, exp, false);
384 }
385 gcc_unreachable ();
386}
387
388/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */
389
390void
391loongarch_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
392{
393 if (!TARGET_HARD_FLOAT_ABI)
394 return;
395 tree exceptions_var = create_tmp_var_raw (LARCH_ATYPE_USI);
396 tree fcsr_orig_var = create_tmp_var_raw (LARCH_ATYPE_USI);
397 tree fcsr_mod_var = create_tmp_var_raw (LARCH_ATYPE_USI);
398 tree const0 = build_int_cst (LARCH_ATYPE_UQI, 0);
399 tree get_fcsr = loongarch_builtin_decls[LARCH_MOVFCSR2GR];
400 tree set_fcsr = loongarch_builtin_decls[LARCH_MOVGR2FCSR];
401 tree get_fcsr_hold_call = build_call_expr (get_fcsr, 1, const0);
402 tree hold_assign_orig = build4 (TARGET_EXPR, LARCH_ATYPE_USI,
403 fcsr_orig_var, get_fcsr_hold_call,
404 NULL, NULL);
405 tree hold_mod_val = build2 (BIT_AND_EXPR, LARCH_ATYPE_USI, fcsr_orig_var,
406 build_int_cst (LARCH_ATYPE_USI, 0xffe0ffe0));
407 tree hold_assign_mod = build4 (TARGET_EXPR, LARCH_ATYPE_USI,
408 fcsr_mod_var, hold_mod_val, NULL, NULL);
409 tree set_fcsr_hold_call = build_call_expr (set_fcsr, 2, const0,
410 fcsr_mod_var);
411 tree hold_all = build2 (COMPOUND_EXPR, LARCH_ATYPE_USI, hold_assign_orig,
412 hold_assign_mod);
413 *hold = build2 (COMPOUND_EXPR, void_type_node, hold_all, set_fcsr_hold_call);
414
415 *clear = build_call_expr (set_fcsr, 2, const0, fcsr_mod_var);
416
417 tree get_fcsr_update_call = build_call_expr (get_fcsr, 1, const0);
418 *update = build4 (TARGET_EXPR, LARCH_ATYPE_USI, exceptions_var,
419 get_fcsr_update_call, NULL, NULL);
420 tree set_fcsr_update_call = build_call_expr (set_fcsr, 2, const0,
421 fcsr_orig_var);
422 *update = build2 (COMPOUND_EXPR, void_type_node, *update,
423 set_fcsr_update_call);
424 tree atomic_feraiseexcept
425 = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
426 tree int_exceptions_var = fold_convert (integer_type_node, exceptions_var);
427 tree atomic_feraiseexcept_call = build_call_expr (atomic_feraiseexcept, 1,
428 int_exceptions_var);
429 *update = build2 (COMPOUND_EXPR, void_type_node, *update,
430 atomic_feraiseexcept_call);
431}
432
433/* Implement TARGET_BUILTIN_VA_LIST. */
434
435tree
436loongarch_build_builtin_va_list (void)
437{
438 return ptr_type_node;
439}
This page took 0.581134 seconds and 5 git commands to generate.