1/* jit-builtins.c -- Handling of builtin functions during JIT-compilation. 2 Copyright (C) 2014-2015 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License 17along 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 "target.h" 24#include "stringpool.h" 25 26#include "jit-common.h" 27#include "jit-builtins.h" 28#include "jit-recording.h" 29#include "jit-playback.h" 30 31namespace gcc { 32 33namespace jit { 34 35const char *const prefix = "__builtin_"; 36const size_t prefix_len = strlen (prefix); 37 38/* Create "builtin_data", a const table of the data within builtins.def. */ 39struct builtin_data 40{ 41 const char *name; 42 enum built_in_class fnclass; 43 enum jit_builtin_type type; 44 bool both_p; 45 bool fallback_p; 46 enum built_in_attribute attr; 47 bool implicit_p; 48 49 const char *get_asm_name () const 50 { 51 if (both_p && fallback_p) 52 return name + prefix_len; 53 else 54 return name; 55 } 56}; 57 58#define DEF_BUILTIN(X, NAME, CLASS, TYPE, LT, BOTH_P, FALLBACK_P, \ 59 NONANSI_P, ATTRS, IMPLICIT, COND) \ 60 {NAME, CLASS, TYPE, BOTH_P, FALLBACK_P, ATTRS, IMPLICIT}, 61static const struct builtin_data builtin_data[] = 62{ 63#include "builtins.def" 64}; 65#undef DEF_BUILTIN 66 67/* Helper function for find_builtin_by_name. */ 68 69static bool 70matches_builtin (const char *in_name, 71 const struct builtin_data& bd) 72{ 73 const bool debug = 0; 74 gcc_assert (bd.name); 75 76 if (debug) 77 fprintf (stderr, "seen builtin: %s\n", bd.name); 78 79 if (0 == strcmp (bd.name, in_name)) 80 { 81 return true; 82 } 83 84 if (bd.both_p) 85 { 86 /* Then the macros in builtins.def gave a "__builtin_" 87 prefix to bd.name, but we should also recognize the form 88 without the prefix. */ 89 gcc_assert (0 == strncmp (bd.name, prefix, prefix_len)); 90 if (debug) 91 fprintf (stderr, "testing without prefix as: %s\n", 92 bd.name + prefix_len); 93 if (0 == strcmp (bd.name + prefix_len, in_name)) 94 { 95 return true; 96 } 97 } 98 99 return false; 100} 101 102/* Locate the built-in function that matches name IN_NAME, 103 writing the result to OUT_ID and returning true if found, 104 or returning false if not found. */ 105 106static bool 107find_builtin_by_name (const char *in_name, 108 enum built_in_function *out_id) 109{ 110 /* Locate builtin. This currently works by performing repeated 111 strcmp against every possible candidate, which is likely to 112 inefficient. 113 114 We start at index 1 to skip the initial entry (BUILT_IN_NONE), which 115 has a NULL name. */ 116 for (unsigned int i = 1; 117 i < sizeof (builtin_data) / sizeof (builtin_data[0]); 118 i++) 119 { 120 const struct builtin_data& bd = builtin_data[i]; 121 if (matches_builtin (in_name, bd)) 122 { 123 /* Found a match. */ 124 *out_id = static_cast<enum built_in_function> (i); 125 return true; 126 } 127 } 128 129 /* Not found. */ 130 return false; 131} 132 133// class builtins_manager 134 135/* Constructor for gcc::jit::builtins_manager. */ 136 137builtins_manager::builtins_manager (recording::context *ctxt) 138 : m_ctxt (ctxt) 139{ 140 memset (m_types, 0, sizeof (m_types)); 141 memset (m_builtin_functions, 0, sizeof (m_builtin_functions)); 142 memset (m_attributes, 0, sizeof (m_attributes)); 143} 144 145/* Locate a builtin function by name. 146 Create a recording::function of the appropriate type, reusing them 147 if they've already been seen. */ 148 149recording::function * 150builtins_manager::get_builtin_function (const char *name) 151{ 152 enum built_in_function builtin_id; 153 if (!find_builtin_by_name (name, &builtin_id)) 154 { 155 m_ctxt->add_error (NULL, "builtin \"%s\" not found", name); 156 return NULL; 157 } 158 159 return get_builtin_function_by_id (builtin_id); 160} 161 162/* Locate a builtin function by id. 163 Create a recording::function of the appropriate type, reusing them 164 if they've already been seen. */ 165 166recording::function * 167builtins_manager::get_builtin_function_by_id (enum built_in_function builtin_id) 168{ 169 gcc_assert (builtin_id >= 0); 170 gcc_assert (builtin_id < END_BUILTINS); 171 172 /* Lazily build the functions, caching them so that repeated calls for 173 the same id on a context give back the same object. */ 174 if (!m_builtin_functions[builtin_id]) 175 { 176 recording::function *fn = make_builtin_function (builtin_id); 177 if (fn) 178 { 179 m_builtin_functions[builtin_id] = fn; 180 m_ctxt->record (fn); 181 } 182 } 183 184 return m_builtin_functions[builtin_id]; 185} 186 187/* Create the recording::function for a given builtin function, by ID. */ 188 189recording::function * 190builtins_manager::make_builtin_function (enum built_in_function builtin_id) 191{ 192 const struct builtin_data& bd = builtin_data[builtin_id]; 193 enum jit_builtin_type type_id = bd.type; 194 recording::type *t = get_type (type_id); 195 if (!t) 196 return NULL; 197 recording::function_type *func_type = t->as_a_function_type (); 198 if (!func_type) 199 return NULL; 200 201 vec<recording::type *> param_types = func_type->get_param_types (); 202 recording::param **params = new recording::param *[param_types.length ()]; 203 204 int i; 205 recording::type *param_type; 206 FOR_EACH_VEC_ELT (param_types, i, param_type) 207 { 208 char buf[16]; 209 snprintf (buf, 16, "arg%d", i); 210 params[i] = m_ctxt->new_param (NULL, 211 param_type, 212 buf); 213 } 214 const char *asm_name = bd.get_asm_name (); 215 recording::function *result = 216 new recording::function (m_ctxt, 217 NULL, 218 GCC_JIT_FUNCTION_IMPORTED, // FIXME 219 func_type->get_return_type (), 220 m_ctxt->new_string (asm_name), 221 param_types.length (), 222 params, 223 func_type->is_variadic (), 224 builtin_id); 225 delete[] params; 226 227 /* PR/64020 - If the client code is using builtin cos or sin, 228 tree-ssa-math-opt.c's execute_cse_sincos_1 may attempt 229 to optimize them to use __builtin_cexpi; for this, 230 BUILT_IN_CEXPI needs to exist. 231 232 Hence query the cache for BUILT_IN_CEXPI to ensure it gets 233 built. */ 234 if (builtin_id == BUILT_IN_COS || builtin_id == BUILT_IN_SIN) 235 (void)get_builtin_function_by_id (BUILT_IN_CEXPI); 236 237 /* builtins.c:expand_builtin_cexpi can optimize the various 238 CEXP builtins to SINCOS builtins, and hence we may require 239 SINCOS builtins latter. 240 241 Ensure the appropriate SINCOS builtin exists. */ 242 if (builtin_id == BUILT_IN_CEXPIF) 243 (void)get_builtin_function_by_id (BUILT_IN_SINCOSF); 244 else if (builtin_id == BUILT_IN_CEXPI) 245 (void)get_builtin_function_by_id (BUILT_IN_SINCOS); 246 else if (builtin_id == BUILT_IN_CEXPIL) 247 (void)get_builtin_function_by_id (BUILT_IN_SINCOSL); 248 249 return result; 250} 251 252/* Get the recording::type for a given type of builtin function, 253 by ID, creating it if it doesn't already exist. */ 254 255recording::type * 256builtins_manager::get_type (enum jit_builtin_type type_id) 257{ 258 if (!m_types[type_id]) 259 m_types[type_id] = make_type (type_id); 260 return m_types[type_id]; 261} 262 263/* Create the recording::type for a given type of builtin function. */ 264 265recording::type * 266builtins_manager::make_type (enum jit_builtin_type type_id) 267{ 268 /* Use builtin-types.def to construct a switch statement, with each 269 case deferring to one of the methods below: 270 - DEF_PRIMITIVE_TYPE is handled as a call to make_primitive_type. 271 - the various DEF_FUNCTION_TYPE_n are handled by variadic calls 272 to make_fn_type. 273 - similarly for DEF_FUNCTION_TYPE_VAR_n, but setting the 274 "is_variadic" argument. 275 - DEF_POINTER_TYPE is handled by make_ptr_type. 276 That should handle everything, but just in case we also suppy a 277 gcc_unreachable default clause. */ 278 switch (type_id) 279 { 280#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ 281 case ENUM: return make_primitive_type (ENUM); 282#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ 283 case ENUM: return make_fn_type (ENUM, RETURN, 0, 0); 284#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ 285 case ENUM: return make_fn_type (ENUM, RETURN, 0, 1, ARG1); 286#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ 287 case ENUM: return make_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); 288#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ 289 case ENUM: return make_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); 290#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ 291 case ENUM: return make_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, \ 292 ARG4); 293#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ 294 case ENUM: return make_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, \ 295 ARG4, ARG5); 296#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ 297 ARG6) \ 298 case ENUM: return make_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, \ 299 ARG4, ARG5, ARG6); 300#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ 301 ARG6, ARG7) \ 302 case ENUM: return make_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, \ 303 ARG4, ARG5, ARG6, ARG7); 304#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ 305 ARG6, ARG7, ARG8) \ 306 case ENUM: return make_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, \ 307 ARG4, ARG5, ARG6, ARG7, ARG8); 308#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ 309 case ENUM: return make_fn_type (ENUM, RETURN, 1, 0); 310#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ 311 case ENUM: return make_fn_type (ENUM, RETURN, 1, 1, ARG1); 312#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ 313 case ENUM: return make_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); 314#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ 315 case ENUM: return make_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); 316#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ 317 case ENUM: return make_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, \ 318 ARG4); 319#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ 320 case ENUM: return make_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, \ 321 ARG4, ARG5); 322#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ 323 ARG6, ARG7) \ 324 case ENUM: return make_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, \ 325 ARG4, ARG5, ARG6, ARG7); 326#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ 327 ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) \ 328 case ENUM: return make_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, \ 329 ARG4, ARG5, ARG6, ARG7, ARG8, ARG9, \ 330 ARG10, ARG11); 331#define DEF_POINTER_TYPE(ENUM, TYPE) \ 332 case ENUM: return make_ptr_type (ENUM, TYPE); 333 334#include "builtin-types.def" 335 336#undef DEF_PRIMITIVE_TYPE 337#undef DEF_FUNCTION_TYPE_0 338#undef DEF_FUNCTION_TYPE_1 339#undef DEF_FUNCTION_TYPE_2 340#undef DEF_FUNCTION_TYPE_3 341#undef DEF_FUNCTION_TYPE_4 342#undef DEF_FUNCTION_TYPE_5 343#undef DEF_FUNCTION_TYPE_6 344#undef DEF_FUNCTION_TYPE_7 345#undef DEF_FUNCTION_TYPE_8 346#undef DEF_FUNCTION_TYPE_VAR_0 347#undef DEF_FUNCTION_TYPE_VAR_1 348#undef DEF_FUNCTION_TYPE_VAR_2 349#undef DEF_FUNCTION_TYPE_VAR_3 350#undef DEF_FUNCTION_TYPE_VAR_4 351#undef DEF_FUNCTION_TYPE_VAR_5 352#undef DEF_FUNCTION_TYPE_VAR_7 353#undef DEF_FUNCTION_TYPE_VAR_11 354#undef DEF_POINTER_TYPE 355 356 default: 357 gcc_unreachable (); 358 } 359} 360 361/* Create the recording::type for a given primitive type within the 362 builtin system. 363 364 Only some types are currently supported. */ 365 366recording::type* 367builtins_manager::make_primitive_type (enum jit_builtin_type type_id) 368{ 369 switch (type_id) 370 { 371 default: 372 // only some of these types are implemented so far: 373 m_ctxt->add_error (NULL, 374 "unimplemented primitive type for builtin: %d", type_id); 375 return NULL; 376 377 case BT_VOID: return m_ctxt->get_type (GCC_JIT_TYPE_VOID); 378 case BT_BOOL: return m_ctxt->get_type (GCC_JIT_TYPE_BOOL); 379 case BT_INT: return m_ctxt->get_type (GCC_JIT_TYPE_INT); 380 case BT_UINT: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_INT); 381 case BT_LONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG); 382 case BT_ULONG: return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG); 383 case BT_LONGLONG: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_LONG); 384 case BT_ULONGLONG: 385 return m_ctxt->get_type (GCC_JIT_TYPE_UNSIGNED_LONG_LONG); 386 // case BT_INT128: 387 // case BT_UINT128: 388 // case BT_INTMAX: 389 // case BT_UINTMAX: 390 case BT_UINT16: return m_ctxt->get_int_type (2, false); 391 case BT_UINT32: return m_ctxt->get_int_type (4, false); 392 case BT_UINT64: return m_ctxt->get_int_type (8, false); 393 // case BT_WORD: 394 // case BT_UNWINDWORD: 395 case BT_FLOAT: return m_ctxt->get_type (GCC_JIT_TYPE_FLOAT); 396 case BT_DOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE); 397 case BT_LONGDOUBLE: return m_ctxt->get_type (GCC_JIT_TYPE_LONG_DOUBLE); 398 case BT_COMPLEX_FLOAT: 399 return m_ctxt->get_type (GCC_JIT_TYPE_COMPLEX_FLOAT); 400 case BT_COMPLEX_DOUBLE: 401 return m_ctxt->get_type (GCC_JIT_TYPE_COMPLEX_DOUBLE); 402 case BT_COMPLEX_LONGDOUBLE: 403 return m_ctxt->get_type (GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE); 404 case BT_PTR: return m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR); 405 case BT_FILEPTR: return m_ctxt->get_type (GCC_JIT_TYPE_FILE_PTR); 406 // case BT_CONST: 407 // case BT_VOLATILE_PTR: 408 // case BT_CONST_VOLATILE_PTR: 409 // case BT_PTRMODE: 410 // case BT_INT_PTR: 411 // case BT_FLOAT_PTR: 412 case BT_DOUBLE_PTR: 413 return m_ctxt->get_type (GCC_JIT_TYPE_DOUBLE)->get_pointer (); 414 // case BT_CONST_DOUBLE_PTR: 415 // case BT_LONGDOUBLE_PTR: 416 // case BT_PID: 417 // case BT_SIZE: 418 // case BT_SSIZE: 419 // case BT_WINT: 420 // case BT_STRING: 421 case BT_CONST_STRING: return m_ctxt->get_type (GCC_JIT_TYPE_CONST_CHAR_PTR); 422 // case BT_DFLOAT32: 423 // case BT_DFLOAT64: 424 // case BT_DFLOAT128: 425 // case BT_DFLOAT32_PTR: 426 // case BT_DFLOAT64_PTR: 427 // case BT_DFLOAT128_PTR: 428 // case BT_VALIST_REF: 429 // case BT_VALIST_ARG: 430 // case BT_I1: 431 // case BT_I2: 432 // case BT_I4: 433 // case BT_I8: 434 // case BT_I16: 435 } 436} 437 438/* Create the recording::function_type for a given function type 439 signature. */ 440 441recording::function_type * 442builtins_manager::make_fn_type (enum jit_builtin_type, 443 enum jit_builtin_type return_type_id, 444 bool is_variadic, 445 int num_args, ...) 446{ 447 va_list list; 448 int i; 449 recording::type **param_types = new recording::type *[num_args]; 450 recording::type *return_type = NULL; 451 recording::function_type *result = NULL; 452 453 va_start (list, num_args); 454 for (i = 0; i < num_args; ++i) 455 { 456 enum jit_builtin_type arg_type_id = 457 (enum jit_builtin_type) va_arg (list, int); 458 param_types[i] = get_type (arg_type_id); 459 if (!param_types[i]) 460 goto error; 461 } 462 va_end (list); 463 464 return_type = get_type (return_type_id); 465 if (!return_type) 466 goto error; 467 468 result = m_ctxt->new_function_type (return_type, 469 num_args, 470 param_types, 471 is_variadic); 472 473 error: 474 delete[] param_types; 475 return result; 476} 477 478/* Handler for DEF_POINTER_TYPE within builtins_manager::make_type. */ 479 480recording::type * 481builtins_manager::make_ptr_type (enum jit_builtin_type, 482 enum jit_builtin_type other_type_id) 483{ 484 recording::type *base_type = get_type (other_type_id); 485 return base_type->get_pointer (); 486} 487 488/* Playback support. */ 489 490/* A builtins_manager is associated with a recording::context 491 and might be reused for multiple compiles on various 492 playback::contexts, perhaps with different options. 493 494 Purge any playback state. Currently this is just the table of 495 attributes. */ 496 497void 498builtins_manager::finish_playback (void) 499{ 500 memset (m_attributes, 0, sizeof (m_attributes)); 501} 502 503/* Get the enum built_in_class for BUILTIN_ID. */ 504 505enum built_in_class 506builtins_manager::get_class (enum built_in_function builtin_id) 507{ 508 return builtin_data[builtin_id].fnclass; 509} 510 511/* Is BUILTIN_ID implicit? */ 512 513bool 514builtins_manager::implicit_p (enum built_in_function builtin_id) 515{ 516 return builtin_data[builtin_id].implicit_p; 517} 518 519/* Get any attributes (in tree form) for the function declaration 520 for BUILTIN_ID. 521 522 These are created on-demand, and cached within the m_attributes 523 array, until finish_playback. */ 524 525tree 526builtins_manager::get_attrs_tree (enum built_in_function builtin_id) 527{ 528 enum built_in_attribute attr = builtin_data[builtin_id].attr; 529 return get_attrs_tree (attr); 530} 531 532/* As above, but for an enum built_in_attribute. */ 533 534tree 535builtins_manager::get_attrs_tree (enum built_in_attribute attr) 536{ 537 gcc_assert (attr < ATTR_LAST); 538 if (!m_attributes [attr]) 539 m_attributes [attr] = make_attrs_tree (attr); 540 return m_attributes [attr]; 541} 542 543/* Handle a cache-miss within the m_attributes array by 544 generating the attributes for enum built_in_attribute 545 in tree form. */ 546 547tree 548builtins_manager::make_attrs_tree (enum built_in_attribute attr) 549{ 550 switch (attr) 551 { 552 /* Generate cases from builtin-attrs.def. */ 553#define DEF_ATTR_NULL_TREE(ENUM) \ 554 case ENUM: return NULL_TREE; 555#define DEF_ATTR_INT(ENUM, VALUE) \ 556 case ENUM: return build_int_cst (integer_type_node, VALUE); 557#define DEF_ATTR_STRING(ENUM, VALUE) \ 558 case ENUM: return build_string (strlen (VALUE), VALUE); 559#define DEF_ATTR_IDENT(ENUM, STRING) \ 560 case ENUM: return get_identifier (STRING); 561#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ 562 case ENUM: return tree_cons (get_attrs_tree (PURPOSE), \ 563 get_attrs_tree (VALUE), \ 564 get_attrs_tree (CHAIN)); 565#include "builtin-attrs.def" 566#undef DEF_ATTR_NULL_TREE 567#undef DEF_ATTR_INT 568#undef DEF_ATTR_IDENT 569#undef DEF_ATTR_TREE_LIST 570 571 default: 572 /* We somehow got a value not covered by the autogenerated 573 cases. */ 574 gcc_unreachable (); 575 return NULL; 576 } 577} 578 579} // namespace jit 580} // namespace gcc 581