]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/config/riscv/riscv-builtins.cc
RISC-V: Add RVV intrinsic basic framework.
[thirdparty/gcc.git] / gcc / config / riscv / riscv-builtins.cc
1 /* Subroutines used for expanding RISC-V builtins.
2 Copyright (C) 2011-2022 Free Software Foundation, Inc.
3 Contributed by Andrew Waterman (andrew@sifive.com).
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along 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 "tm.h"
27 #include "rtl.h"
28 #include "tree.h"
29 #include "gimple-expr.h"
30 #include "memmodel.h"
31 #include "expmed.h"
32 #include "profile-count.h"
33 #include "optabs.h"
34 #include "recog.h"
35 #include "diagnostic-core.h"
36 #include "stor-layout.h"
37 #include "stringpool.h"
38 #include "expr.h"
39 #include "langhooks.h"
40 #include "tm_p.h"
41
42 /* Macros to create an enumeration identifier for a function prototype. */
43 #define RISCV_FTYPE_NAME0(A) RISCV_##A##_FTYPE
44 #define RISCV_FTYPE_NAME1(A, B) RISCV_##A##_FTYPE_##B
45
46 /* Classifies the prototype of a built-in function. */
47 enum 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. */
55 enum 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. */
72 struct 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
90 AVAIL (hard_float, TARGET_HARD_FLOAT)
91
92
93 AVAIL (clean32, TARGET_ZICBOM && !TARGET_64BIT)
94 AVAIL (clean64, TARGET_ZICBOM && TARGET_64BIT)
95 AVAIL (flush32, TARGET_ZICBOM && !TARGET_64BIT)
96 AVAIL (flush64, TARGET_ZICBOM && TARGET_64BIT)
97 AVAIL (inval32, TARGET_ZICBOM && !TARGET_64BIT)
98 AVAIL (inval64, TARGET_ZICBOM && TARGET_64BIT)
99 AVAIL (zero32, TARGET_ZICBOZ && !TARGET_64BIT)
100 AVAIL (zero64, TARGET_ZICBOZ && TARGET_64BIT)
101 AVAIL (prefetchi32, TARGET_ZICBOP && !TARGET_64BIT)
102 AVAIL (prefetchi64, TARGET_ZICBOP && TARGET_64BIT)
103
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
136 #define RISCV_ATYPE_SI intSI_type_node
137 #define RISCV_ATYPE_DI intDI_type_node
138 #define RISCV_ATYPE_VOID_PTR ptr_type_node
139
140 /* RISCV_FTYPE_ATYPESN takes N RISCV_FTYPES-like type codes and lists
141 their associated RISCV_ATYPEs. */
142 #define RISCV_FTYPE_ATYPES0(A) \
143 RISCV_ATYPE_##A
144 #define RISCV_FTYPE_ATYPES1(A, B) \
145 RISCV_ATYPE_##A, RISCV_ATYPE_##B
146
147 static const struct riscv_builtin_description riscv_builtins[] = {
148 #include "riscv-cmo.def"
149
150 DIRECT_BUILTIN (frflags, RISCV_USI_FTYPE, hard_float),
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. */
156 static 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. */
160 static 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
165 tree riscv_float16_type_node = NULL_TREE;
166
167 /* Return the function type associated with function prototype TYPE. */
168
169 static tree
170 riscv_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
192 static void
193 riscv_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
211 /* Implement TARGET_INIT_BUILTINS. */
212
213 void
214 riscv_init_builtins (void)
215 {
216 riscv_init_builtin_types ();
217 riscv_vector::init_builtins ();
218
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]
226 = add_builtin_function (d->name, type,
227 (i << RISCV_BUILTIN_SHIFT)
228 + RISCV_BUILTIN_GENERAL,
229 BUILT_IN_MD, NULL, NULL);
230 riscv_builtin_decl_index[d->icode] = i;
231 }
232 }
233 }
234
235 /* Implement TARGET_BUILTIN_DECL. */
236
237 tree
238 riscv_builtin_decl (unsigned int code, bool initialize_p ATTRIBUTE_UNUSED)
239 {
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;
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
257 static void
258 riscv_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
271 static rtx
272 riscv_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
289 static rtx
290 riscv_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
311 rtx
312 riscv_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);
317 unsigned int fcode = DECL_MD_FUNCTION_CODE (fndecl);
318 unsigned int subcode = fcode >> RISCV_BUILTIN_SHIFT;
319 switch (fcode & RISCV_BUILTIN_CLASS)
320 {
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 }
335 }
336
337 gcc_unreachable ();
338 }
339
340 /* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */
341
342 void
343 riscv_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
344 {
345 if (!TARGET_HARD_FLOAT)
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
352 *hold = build4 (TARGET_EXPR, RISCV_ATYPE_USI, old_flags,
353 build_call_expr (frflags, 0), NULL_TREE, NULL_TREE);
354 *clear = build_call_expr (fsflags, 1, old_flags);
355 *update = NULL_TREE;
356 }