]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/riscv/riscv-builtins.cc
Merge remote-tracking branch 'origin/master' into devel/c++-contracts
[thirdparty/gcc.git] / gcc / config / riscv / riscv-builtins.cc
CommitLineData
09cae750 1/* Subroutines used for expanding RISC-V builtins.
7adcbafe 2 Copyright (C) 2011-2022 Free Software Foundation, Inc.
09cae750
PD
3 Contributed by Andrew Waterman (andrew@sifive.com).
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
8fcc61f8
RS
21#define IN_TARGET_CODE 1
22
09cae750
PD
23#include "config.h"
24#include "system.h"
25#include "coretypes.h"
26#include "tm.h"
27#include "rtl.h"
28#include "tree.h"
29#include "gimple-expr.h"
30#include "memmodel.h"
31#include "expmed.h"
1b68a156 32#include "profile-count.h"
09cae750
PD
33#include "optabs.h"
34#include "recog.h"
35#include "diagnostic-core.h"
36#include "stor-layout.h"
27d68a60 37#include "stringpool.h"
09cae750
PD
38#include "expr.h"
39#include "langhooks.h"
7d935cdd 40#include "tm_p.h"
09cae750
PD
41
42/* Macros to create an enumeration identifier for a function prototype. */
33d9794b 43#define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE
09cae750
PD
44#define RISCV_FTYPE_NAME1(A, B) RISCV_##A##_FTYPE_##B
45
46/* Classifies the prototype of a built-in function. */
47enum riscv_function_type {
48#define DEF_RISCV_FTYPE(NARGS, LIST) RISCV_FTYPE_NAME##NARGS LIST,
49#include "config/riscv/riscv-ftypes.def"
50#undef DEF_RISCV_FTYPE
51 RISCV_MAX_FTYPE_MAX
52};
53
54/* Specifies how a built-in function should be converted into rtl. */
55enum riscv_builtin_type {
56 /* The function corresponds directly to an .md pattern. */
57 RISCV_BUILTIN_DIRECT,
58
59 /* Likewise, but with return type VOID. */
60 RISCV_BUILTIN_DIRECT_NO_TARGET
61};
62
63/* Declare an availability predicate for built-in functions. */
64#define AVAIL(NAME, COND) \
65 static unsigned int \
66 riscv_builtin_avail_##NAME (void) \
67 { \
68 return (COND); \
69 }
70
71/* This structure describes a single built-in function. */
72struct riscv_builtin_description {
73 /* The code of the main .md file instruction. See riscv_builtin_type
74 for more information. */
75 enum insn_code icode;
76
77 /* The name of the built-in function. */
78 const char *name;
79
80 /* Specifies how the function should be expanded. */
81 enum riscv_builtin_type builtin_type;
82
83 /* The function's prototype. */
84 enum riscv_function_type prototype;
85
86 /* Whether the function is available. */
87 unsigned int (*avail) (void);
88};
89
ac96e906 90AVAIL (hard_float, TARGET_HARD_FLOAT || TARGET_ZFINX)
09cae750 91
3df3ca90
S
92
93AVAIL (clean32, TARGET_ZICBOM && !TARGET_64BIT)
94AVAIL (clean64, TARGET_ZICBOM && TARGET_64BIT)
95AVAIL (flush32, TARGET_ZICBOM && !TARGET_64BIT)
96AVAIL (flush64, TARGET_ZICBOM && TARGET_64BIT)
97AVAIL (inval32, TARGET_ZICBOM && !TARGET_64BIT)
98AVAIL (inval64, TARGET_ZICBOM && TARGET_64BIT)
99AVAIL (zero32, TARGET_ZICBOZ && !TARGET_64BIT)
100AVAIL (zero64, TARGET_ZICBOZ && TARGET_64BIT)
101AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT)
102AVAIL (prefetchi64, TARGET_ZICBOP && TARGET_64BIT)
103
09cae750
PD
104/* Construct a riscv_builtin_description from the given arguments.
105
106 INSN is the name of the associated instruction pattern, without the
107 leading CODE_FOR_riscv_.
108
109 NAME is the name of the function itself, without the leading
110 "__builtin_riscv_".
111
112 BUILTIN_TYPE and FUNCTION_TYPE are riscv_builtin_description fields.
113
114 AVAIL is the name of the availability predicate, without the leading
115 riscv_builtin_avail_. */
116#define RISCV_BUILTIN(INSN, NAME, BUILTIN_TYPE, FUNCTION_TYPE, AVAIL) \
117 { CODE_FOR_riscv_ ## INSN, "__builtin_riscv_" NAME, \
118 BUILTIN_TYPE, FUNCTION_TYPE, riscv_builtin_avail_ ## AVAIL }
119
120/* Define __builtin_riscv_<INSN>, which is a RISCV_BUILTIN_DIRECT function
121 mapped to instruction CODE_FOR_riscv_<INSN>, FUNCTION_TYPE and AVAIL
122 are as for RISCV_BUILTIN. */
123#define DIRECT_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \
124 RISCV_BUILTIN (INSN, #INSN, RISCV_BUILTIN_DIRECT, FUNCTION_TYPE, AVAIL)
125
126/* Define __builtin_riscv_<INSN>, which is a RISCV_BUILTIN_DIRECT_NO_TARGET
127 function mapped to instruction CODE_FOR_riscv_<INSN>, FUNCTION_TYPE
128 and AVAIL are as for RISCV_BUILTIN. */
129#define DIRECT_NO_TARGET_BUILTIN(INSN, FUNCTION_TYPE, AVAIL) \
130 RISCV_BUILTIN (INSN, #INSN, RISCV_BUILTIN_DIRECT_NO_TARGET, \
131 FUNCTION_TYPE, AVAIL)
132
133/* Argument types. */
134#define RISCV_ATYPE_VOID void_type_node
135#define RISCV_ATYPE_USI unsigned_intSI_type_node
3df3ca90
S
136#define RISCV_ATYPE_SI intSI_type_node
137#define RISCV_ATYPE_DI intDI_type_node
970b03c0 138#define RISCV_ATYPE_VOID_PTR ptr_type_node
09cae750
PD
139
140/* RISCV_FTYPE_ATYPESN takes N RISCV_FTYPES-like type codes and lists
141 their associated RISCV_ATYPEs. */
33d9794b
KC
142#define RISCV_FTYPE_ATYPES0(A) \
143 RISCV_ATYPE_##A
09cae750
PD
144#define RISCV_FTYPE_ATYPES1(A, B) \
145 RISCV_ATYPE_##A, RISCV_ATYPE_##B
146
147static const struct riscv_builtin_description riscv_builtins[] = {
3df3ca90
S
148 #include "riscv-cmo.def"
149
33d9794b 150 DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float),
09cae750
PD
151 DIRECT_NO_TARGET_BUILTIN (fsflags, RISCV_VOID_FTYPE_USI, hard_float)
152};
153
154/* Index I is the function declaration for riscv_builtins[I], or null if the
155 function isn't defined on this target. */
156static GTY(()) tree riscv_builtin_decls[ARRAY_SIZE (riscv_builtins)];
157
158/* Get the index I of the function declaration for riscv_builtin_decls[I]
159 using the instruction code or return null if not defined for the target. */
160static GTY(()) int riscv_builtin_decl_index[NUM_INSN_CODES];
161
162#define GET_BUILTIN_DECL(CODE) \
163 riscv_builtin_decls[riscv_builtin_decl_index[(CODE)]]
164
27d68a60
KC
165tree riscv_float16_type_node = NULL_TREE;
166
09cae750
PD
167/* Return the function type associated with function prototype TYPE. */
168
169static tree
170riscv_build_function_type (enum riscv_function_type type)
171{
172 static tree types[(int) RISCV_MAX_FTYPE_MAX];
173
174 if (types[(int) type] == NULL_TREE)
175 switch (type)
176 {
177#define DEF_RISCV_FTYPE(NUM, ARGS) \
178 case RISCV_FTYPE_NAME##NUM ARGS: \
179 types[(int) type] \
180 = build_function_type_list (RISCV_FTYPE_ATYPES##NUM ARGS, \
181 NULL_TREE); \
182 break;
183#include "config/riscv/riscv-ftypes.def"
184#undef DEF_RISCV_FTYPE
185 default:
186 gcc_unreachable ();
187 }
188
189 return types[(int) type];
190}
191
27d68a60
KC
192static void
193riscv_init_builtin_types (void)
194{
195 /* Provide the _Float16 type and float16_type_node if needed. */
196 if (!float16_type_node)
197 {
198 riscv_float16_type_node = make_node (REAL_TYPE);
199 TYPE_PRECISION (riscv_float16_type_node) = 16;
200 SET_TYPE_MODE (riscv_float16_type_node, HFmode);
201 layout_type (riscv_float16_type_node);
202 }
203 else
204 riscv_float16_type_node = float16_type_node;
205
206 if (!maybe_get_identifier ("_Float16"))
207 lang_hooks.types.register_builtin_type (riscv_float16_type_node,
208 "_Float16");
209}
210
09cae750
PD
211/* Implement TARGET_INIT_BUILTINS. */
212
213void
214riscv_init_builtins (void)
215{
27d68a60 216 riscv_init_builtin_types ();
03f33657 217 riscv_vector::init_builtins ();
27d68a60 218
09cae750
PD
219 for (size_t i = 0; i < ARRAY_SIZE (riscv_builtins); i++)
220 {
221 const struct riscv_builtin_description *d = &riscv_builtins[i];
222 if (d->avail ())
223 {
224 tree type = riscv_build_function_type (d->prototype);
225 riscv_builtin_decls[i]
cbd50570
JZZ
226 = add_builtin_function (d->name, type,
227 (i << RISCV_BUILTIN_SHIFT)
228 + RISCV_BUILTIN_GENERAL,
229 BUILT_IN_MD, NULL, NULL);
09cae750
PD
230 riscv_builtin_decl_index[d->icode] = i;
231 }
232 }
233}
234
235/* Implement TARGET_BUILTIN_DECL. */
236
237tree
238riscv_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
239{
cbd50570
JZZ
240 unsigned int subcode = code >> RISCV_BUILTIN_SHIFT;
241 switch (code & RISCV_BUILTIN_CLASS)
242 {
243 case RISCV_BUILTIN_GENERAL:
244 if (subcode >= ARRAY_SIZE (riscv_builtins))
245 return error_mark_node;
246 return riscv_builtin_decls[subcode];
247
248 case RISCV_BUILTIN_VECTOR:
249 return riscv_vector::builtin_decl (subcode, initialize_p);
250 }
251 return error_mark_node;
09cae750
PD
252}
253
254/* Take argument ARGNO from EXP's argument list and convert it into
255 an expand operand. Store the operand in *OP. */
256
257static void
258riscv_prepare_builtin_arg (struct expand_operand *op, tree exp, unsigned argno)
259{
260 tree arg = CALL_EXPR_ARG (exp, argno);
261 create_input_operand (op, expand_normal (arg), TYPE_MODE (TREE_TYPE (arg)));
262}
263
264/* Expand instruction ICODE as part of a built-in function sequence.
265 Use the first NOPS elements of OPS as the instruction's operands.
266 HAS_TARGET_P is true if operand 0 is a target; it is false if the
267 instruction has no target.
268
269 Return the target rtx if HAS_TARGET_P, otherwise return const0_rtx. */
270
271static rtx
272riscv_expand_builtin_insn (enum insn_code icode, unsigned int n_ops,
273 struct expand_operand *ops, bool has_target_p)
274{
275 if (!maybe_expand_insn (icode, n_ops, ops))
276 {
277 error ("invalid argument to built-in function");
278 return has_target_p ? gen_reg_rtx (ops[0].mode) : const0_rtx;
279 }
280
281 return has_target_p ? ops[0].value : const0_rtx;
282}
283
284/* Expand a RISCV_BUILTIN_DIRECT or RISCV_BUILTIN_DIRECT_NO_TARGET function;
285 HAS_TARGET_P says which. EXP is the CALL_EXPR that calls the function
286 and ICODE is the code of the associated .md pattern. TARGET, if nonnull,
287 suggests a good place to put the result. */
288
289static rtx
290riscv_expand_builtin_direct (enum insn_code icode, rtx target, tree exp,
291 bool has_target_p)
292{
293 struct expand_operand ops[MAX_RECOG_OPERANDS];
294
295 /* Map any target to operand 0. */
296 int opno = 0;
297 if (has_target_p)
298 create_output_operand (&ops[opno++], target, TYPE_MODE (TREE_TYPE (exp)));
299
300 /* Map the arguments to the other operands. */
301 gcc_assert (opno + call_expr_nargs (exp)
302 == insn_data[icode].n_generator_args);
303 for (int argno = 0; argno < call_expr_nargs (exp); argno++)
304 riscv_prepare_builtin_arg (&ops[opno++], exp, argno);
305
306 return riscv_expand_builtin_insn (icode, opno, ops, has_target_p);
307}
308
309/* Implement TARGET_EXPAND_BUILTIN. */
310
311rtx
312riscv_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
313 machine_mode mode ATTRIBUTE_UNUSED,
314 int ignore ATTRIBUTE_UNUSED)
315{
316 tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
4d732405 317 unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
cbd50570
JZZ
318 unsigned int subcode = fcode >> RISCV_BUILTIN_SHIFT;
319 switch (fcode & RISCV_BUILTIN_CLASS)
09cae750 320 {
cbd50570
JZZ
321 case RISCV_BUILTIN_VECTOR:
322 return riscv_vector::expand_builtin (subcode, exp, target);
323 case RISCV_BUILTIN_GENERAL: {
324 const struct riscv_builtin_description *d = &riscv_builtins[subcode];
325
326 switch (d->builtin_type)
327 {
328 case RISCV_BUILTIN_DIRECT:
329 return riscv_expand_builtin_direct (d->icode, target, exp, true);
330
331 case RISCV_BUILTIN_DIRECT_NO_TARGET:
332 return riscv_expand_builtin_direct (d->icode, target, exp, false);
333 }
334 }
09cae750
PD
335 }
336
337 gcc_unreachable ();
338}
339
340/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */
341
342void
343riscv_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
344{
ac96e906 345 if (!(TARGET_HARD_FLOAT || TARGET_ZFINX))
09cae750
PD
346 return;
347
348 tree frflags = GET_BUILTIN_DECL (CODE_FOR_riscv_frflags);
349 tree fsflags = GET_BUILTIN_DECL (CODE_FOR_riscv_fsflags);
350 tree old_flags = create_tmp_var_raw (RISCV_ATYPE_USI);
351
b4ace720
JJ
352 *hold = build4 (TARGET_EXPR, RISCV_ATYPE_USI, old_flags,
353 build_call_expr (frflags, 0), NULL_TREE, NULL_TREE);
09cae750
PD
354 *clear = build_call_expr (fsflags, 1, old_flags);
355 *update = NULL_TREE;
356}