Move gcc_jit_result implementation to a new files jit-result.{h|c}
[gcc.git] / gcc / jit / jit-builtins.c
1 /* jit-builtins.c -- Handling of builtin functions during JIT-compilation.
2 Copyright (C) 2014 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
19
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "opts.h"
24 #include "tree.h"
25 #include "target.h"
26
27 #include "jit-common.h"
28 #include "jit-builtins.h"
29 #include "jit-recording.h"
30
31 namespace gcc {
32
33 namespace jit {
34
35 namespace recording {
36
37 const char *const prefix = "__builtin_";
38 const size_t prefix_len = strlen (prefix);
39
40 /* Create "builtin_data", a const table of the data within builtins.def. */
41 struct builtin_data
42 {
43 const char *name;
44 enum jit_builtin_type type;
45 bool both_p;
46 bool fallback_p;
47
48 const char *get_asm_name () const
49 {
50 if (both_p && fallback_p)
51 return name + prefix_len;
52 else
53 return name;
54 }
55 };
56
57 #define DEF_BUILTIN(X, NAME, C, TYPE, LT, BOTH_P, FALLBACK_P, NA, AT, IM, COND)\
58 {NAME, TYPE, BOTH_P, FALLBACK_P},
59 static const struct builtin_data builtin_data[] =
60 {
61 #include "builtins.def"
62 };
63 #undef DEF_BUILTIN
64
65 /* Helper function for find_builtin_by_name. */
66
67 static bool
68 matches_builtin (const char *in_name,
69 const struct builtin_data& bd)
70 {
71 const bool debug = 0;
72 gcc_assert (bd.name);
73
74 if (debug)
75 fprintf (stderr, "seen builtin: %s\n", bd.name);
76
77 if (0 == strcmp (bd.name, in_name))
78 {
79 return true;
80 }
81
82 if (bd.both_p)
83 {
84 /* Then the macros in builtins.def gave a "__builtin_"
85 prefix to bd.name, but we should also recognize the form
86 without the prefix. */
87 gcc_assert (0 == strncmp (bd.name, prefix, prefix_len));
88 if (debug)
89 fprintf (stderr, "testing without prefix as: %s\n",
90 bd.name + prefix_len);
91 if (0 == strcmp (bd.name + prefix_len, in_name))
92 {
93 return true;
94 }
95 }
96
97 return false;
98 }
99
100 /* Locate the built-in function that matches name IN_NAME,
101 writing the result to OUT_ID and returning true if found,
102 or returning false if not found. */
103
104 static bool
105 find_builtin_by_name (const char *in_name,
106 enum built_in_function *out_id)
107 {
108 /* Locate builtin. This currently works by performing repeated
109 strcmp against every possible candidate, which is likely to
110 inefficient.
111
112 We start at index 1 to skip the initial entry (BUILT_IN_NONE), which
113 has a NULL name. */
114 for (unsigned int i = 1;
115 i < sizeof (builtin_data) / sizeof (builtin_data[0]);
116 i++)
117 {
118 const struct builtin_data& bd = builtin_data[i];
119 if (matches_builtin (in_name, bd))
120 {
121 /* Found a match. */
122 *out_id = static_cast<enum built_in_function> (i);
123 return true;
124 }
125 }
126
127 /* Not found. */
128 return false;
129 }
130
131 // class builtins_manager
132
133 /* Constructor for gcc::jit::recording::builtins_manager. */
134
135 builtins_manager::builtins_manager (context *ctxt)
136 : m_ctxt (ctxt)
137 {
138 memset (m_types, 0, sizeof (m_types));
139 memset (m_builtin_functions, 0, sizeof (m_builtin_functions));
140 }
141
142 /* Locate a builtin function by name.
143 Create a recording::function of the appropriate type, reusing them
144 if they've already been seen. */
145
146 function *
147 builtins_manager::get_builtin_function (const char *name)
148 {
149 enum built_in_function builtin_id;
150 if (!find_builtin_by_name (name, &builtin_id))
151 {
152 m_ctxt->add_error (NULL, "builtin \"%s\" not found", name);
153 return NULL;
154 }
155
156 gcc_assert (builtin_id >= 0);
157 gcc_assert (builtin_id < END_BUILTINS);
158
159 /* Lazily build the functions, caching them so that repeated calls for
160 the same id on a context give back the same object. */
161 if (!m_builtin_functions[builtin_id])
162 {
163 m_builtin_functions[builtin_id] = make_builtin_function (builtin_id);
164 m_ctxt->record (m_builtin_functions[builtin_id]);
165 }
166
167 return m_builtin_functions[builtin_id];
168 }
169
170 /* Create the recording::function for a given builtin function, by ID. */
171
172 function *
173 builtins_manager::make_builtin_function (enum built_in_function builtin_id)
174 {
175 const struct builtin_data& bd = builtin_data[builtin_id];
176 enum jit_builtin_type type_id = bd.type;
177 function_type *func_type = get_type (type_id)->as_a_function_type ();
178 if (!func_type)
179 return NULL;
180
181 vec<type *> param_types = func_type->get_param_types ();
182 recording::param **params = new recording::param *[param_types.length ()];
183
184 int i;
185 type *param_type;
186 FOR_EACH_VEC_ELT (param_types, i, param_type)
187 {
188 char buf[16];
189 snprintf (buf, 16, "arg%d", i);
190 params[i] = m_ctxt->new_param (NULL,
191 param_type,
192 buf);
193 }
194 const char *asm_name = bd.get_asm_name ();
195 function *result =
196 new function (m_ctxt,
197 NULL,
198 GCC_JIT_FUNCTION_IMPORTED, // FIXME
199 func_type->get_return_type (),
200 m_ctxt->new_string (asm_name),
201 param_types.length (),
202 params,
203 func_type->is_variadic (),
204 builtin_id);
205 delete[] params;
206 return result;
207 }
208
209 /* Get the recording::type for a given type of builtin function,
210 by ID, creating it if it doesn't already exist. */
211
212 type *
213 builtins_manager::get_type (enum jit_builtin_type type_id)
214 {
215 if (!m_types[type_id])
216 m_types[type_id] = make_type (type_id);
217 return m_types[type_id];
218 }
219
220 /* Create the recording::type for a given type of builtin function. */
221
222 type *
223 builtins_manager::make_type (enum jit_builtin_type type_id)
224 {
225 /* Use builtin-types.def to construct a switch statement, with each
226 case deferring to one of the methods below:
227 - DEF_PRIMITIVE_TYPE is handled as a call to make_primitive_type.
228 - the various DEF_FUNCTION_TYPE_n are handled by variadic calls
229 to make_fn_type.
230 - similarly for DEF_FUNCTION_TYPE_VAR_n, but setting the
231 "is_variadic" argument.
232 - DEF_POINTER_TYPE is handled by make_ptr_type.
233 That should handle everything, but just in case we also suppy a
234 gcc_unreachable default clause. */
235 switch (type_id)
236 {
237 #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
238 case ENUM: return make_primitive_type (ENUM);
239 #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
240 case ENUM: return make_fn_type (ENUM, RETURN, 0, 0);
241 #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
242 case ENUM: return make_fn_type (ENUM, RETURN, 0, 1, ARG1);
243 #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
244 case ENUM: return make_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
245 #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
246 case ENUM: return make_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
247 #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
248 case ENUM: return make_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
249 #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
250 case ENUM: return make_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
251 #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
252 ARG6) \
253 case ENUM: return make_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
254 #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
255 ARG6, ARG7) \
256 case ENUM: return make_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
257 #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
258 ARG6, ARG7, ARG8) \
259 case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, \
260 ARG7, ARG8);
261 #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
262 case ENUM: return make_fn_type (ENUM, RETURN, 1, 0);
263 #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
264 case ENUM: return make_fn_type (ENUM, RETURN, 1, 1, ARG1);
265 #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
266 case ENUM: return make_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
267 #define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
268 case ENUM: return make_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
269 #define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
270 case ENUM: return make_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
271 #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
272 case ENUM: return make_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
273 #define DEF_POINTER_TYPE(ENUM, TYPE) \
274 case ENUM: return make_ptr_type (ENUM, TYPE);
275
276 #include "builtin-types.def"
277
278 #undef DEF_PRIMITIVE_TYPE
279 #undef DEF_FUNCTION_TYPE_1
280 #undef DEF_FUNCTION_TYPE_2
281 #undef DEF_FUNCTION_TYPE_3
282 #undef DEF_FUNCTION_TYPE_4
283 #undef DEF_FUNCTION_TYPE_5
284 #undef DEF_FUNCTION_TYPE_6
285 #undef DEF_FUNCTION_TYPE_VAR_0
286 #undef DEF_FUNCTION_TYPE_VAR_1
287 #undef DEF_FUNCTION_TYPE_VAR_2
288 #undef DEF_FUNCTION_TYPE_VAR_3
289 #undef DEF_FUNCTION_TYPE_VAR_4
290 #undef DEF_FUNCTION_TYPE_VAR_5
291 #undef DEF_POINTER_TYPE
292
293 default:
294 gcc_unreachable ();
295 }
296 }
297
298 /* Create the recording::type for a given primitive type within the
299 builtin system.
300
301 Only some types are currently supported. */
302
303 type*
304 builtins_manager::make_primitive_type (enum jit_builtin_type type_id)
305 {
306 switch (type_id)
307 {
308 default:
309 // only some of these types are implemented so far:
310 m_ctxt->add_error (NULL,
311 "unimplemented primitive type for builtin: %d", type_id);
312 return NULL;
313
314 case BT_VOID: return m_ctxt->get_type (GCC_JIT_TYPE_VOID);
315 case BT_BOOL: return m_ctxt->get_type (GCC_JIT_TYPE_BOOL);
316 case BT_INT: return m_ctxt->get_type (GCC_JIT_TYPE_INT);
317 case BT_UINT: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_INT);
318 case BT_LONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG);
319 case BT_ULONG: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG);
320 case BT_LONGLONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_LONG);
321 case BT_ULONGLONG:
322 return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
323 // case BT_INT128:
324 // case BT_UINT128:
325 // case BT_INTMAX:
326 // case BT_UINTMAX:
327 case BT_UINT16: return m_ctxt->get_int_type (2, false);
328 case BT_UINT32: return m_ctxt->get_int_type (4, false);
329 case BT_UINT64: return m_ctxt->get_int_type (8, false);
330 // case BT_WORD:
331 // case BT_UNWINDWORD:
332 case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT);
333 case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE);
334 case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE);
335 // case BT_COMPLEX_FLOAT:
336 // case BT_COMPLEX_DOUBLE:
337 // case BT_COMPLEX_LONGDOUBLE:
338 case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
339 case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR);
340 // case BT_CONST:
341 // case BT_VOLATILE_PTR:
342 // case BT_CONST_VOLATILE_PTR:
343 // case BT_PTRMODE:
344 // case BT_INT_PTR:
345 // case BT_FLOAT_PTR:
346 // case BT_DOUBLE_PTR:
347 // case BT_CONST_DOUBLE_PTR:
348 // case BT_LONGDOUBLE_PTR:
349 // case BT_PID:
350 // case BT_SIZE:
351 // case BT_SSIZE:
352 // case BT_WINT:
353 // case BT_STRING:
354 case BT_CONST_STRING: return m_ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR);
355 // case BT_DFLOAT32:
356 // case BT_DFLOAT64:
357 // case BT_DFLOAT128:
358 // case BT_DFLOAT32_PTR:
359 // case BT_DFLOAT64_PTR:
360 // case BT_DFLOAT128_PTR:
361 // case BT_VALIST_REF:
362 // case BT_VALIST_ARG:
363 // case BT_I1:
364 // case BT_I2:
365 // case BT_I4:
366 // case BT_I8:
367 // case BT_I16:
368 }
369 }
370
371 /* Create the recording::function_type for a given function type
372 signature. */
373
374 function_type *
375 builtins_manager::make_fn_type (enum jit_builtin_type,
376 enum jit_builtin_type return_type_id,
377 bool is_variadic,
378 int num_args, ...)
379 {
380 va_list list;
381 int i;
382 type **param_types = new type *[num_args];
383 type *return_type = NULL;
384 function_type *result = NULL;
385
386 va_start (list, num_args);
387 for (i = 0; i < num_args; ++i)
388 {
389 enum jit_builtin_type arg_type_id =
390 (enum jit_builtin_type) va_arg (list, int);
391 param_types[i] = get_type (arg_type_id);
392 if (!param_types[i])
393 goto error;
394 }
395 va_end (list);
396
397 return_type = get_type (return_type_id);
398 if (!return_type)
399 goto error;
400
401 result = m_ctxt->new_function_type (return_type,
402 num_args,
403 param_types,
404 is_variadic);
405
406 error:
407 delete[] param_types;
408 return result;
409 }
410
411 /* Handler for DEF_POINTER_TYPE within builtins_manager::make_type. */
412
413 type *
414 builtins_manager::make_ptr_type (enum jit_builtin_type,
415 enum jit_builtin_type other_type_id)
416 {
417 type *base_type = get_type (other_type_id);
418 return base_type->get_pointer ();
419 }
420
421 } // namespace recording
422 } // namespace jit
423 } // namespace gcc