// This file is part of GCC. // GCC is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free // Software Foundation; either version 3, or (at your option) any later // version. // GCC is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License // for more details. // You should have received a copy of the GNU General Public License // along with GCC; see the file COPYING3. If not see // . #include "rust-diagnostics.h" #include "rust-system.h" #include "rust-builtins.h" #include "target.h" #include "stringpool.h" namespace Rust { namespace Compile { BuiltinsContext & BuiltinsContext::get () { static BuiltinsContext instance; return instance; } bool BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin) { auto *to_search = &name; auto it = rust_intrinsic_to_gcc_builtin.find (name); if (it != rust_intrinsic_to_gcc_builtin.end ()) to_search = &it->second; return lookup_gcc_builtin (*to_search, builtin); } BuiltinsContext::BuiltinsContext () { setup (); } /** * Define a function type according to `builtin-types.def` * * *Heavily* inspired by the D frontend's `def_fn_type` function */ void BuiltinsContext::define_function_type (Type def_idx, Type ret_idx, bool is_variadic, size_t n, ...) { va_list list; va_start (list, n); auto args = std::vector (); for (size_t i = 0; i < n; i++) { // The argument is an enum Type, but it's promoted to int when passed // though '...'. auto arg_idx = va_arg (list, int); auto arg_type = builtin_types[arg_idx]; args.emplace_back (arg_type); } auto return_type = builtin_types[ret_idx]; if (return_type == error_mark_node) { // Mark the builtin as not available. builtin_types[def_idx] = error_mark_node; va_end (list); return; } auto fn_type = NULL_TREE; if (is_variadic) fn_type = build_varargs_function_type_array (return_type, n, args.data ()); else fn_type = build_function_type_array (return_type, n, args.data ()); builtin_types[def_idx] = fn_type; va_end (list); } // Taken directly from the D frontend static void build_c_type_nodes (void) { string_type_node = build_pointer_type (char_type_node); const_string_type_node = build_pointer_type ( build_qualified_type (char_type_node, TYPE_QUAL_CONST)); if (strcmp (UINTMAX_TYPE, "unsigned int") == 0) { intmax_type_node = integer_type_node; uintmax_type_node = unsigned_type_node; } else if (strcmp (UINTMAX_TYPE, "long unsigned int") == 0) { intmax_type_node = long_integer_type_node; uintmax_type_node = long_unsigned_type_node; } else if (strcmp (UINTMAX_TYPE, "long long unsigned int") == 0) { intmax_type_node = long_long_integer_type_node; uintmax_type_node = long_long_unsigned_type_node; } else gcc_unreachable (); signed_size_type_node = signed_type_for (size_type_node); wint_type_node = unsigned_type_node; pid_type_node = integer_type_node; } /** * Define all builtin types in the `builtin_types` array */ void BuiltinsContext::define_builtin_types () { // This is taken directly from the D frontend's handling of builtins auto va_list_ref_type_node = build_reference_type (va_list_type_node); auto va_list_arg_type_node = va_list_type_node; build_c_type_nodes (); auto builtin_type_for_size = [] (int size, bool unsignedp) { tree type = lang_hooks.types.type_for_size (size, unsignedp); return type ? type : error_mark_node; }; #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) builtin_types[ENUM] = VALUE; #define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ define_function_type (ENUM, RETURN, 0, 0); #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, A1) \ define_function_type (ENUM, RETURN, 0, 1, A1); #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, A1, A2) \ define_function_type (ENUM, RETURN, 0, 2, A1, A2); #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, A1, A2, A3) \ define_function_type (ENUM, RETURN, 0, 3, A1, A2, A3); #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, A1, A2, A3, A4) \ define_function_type (ENUM, RETURN, 0, 4, A1, A2, A3, A4); #define DEF_FUNCTION_TYPE_5(ENUM, RETURN, A1, A2, A3, A4, A5) \ define_function_type (ENUM, RETURN, 0, 5, A1, A2, A3, A4, A5); #define DEF_FUNCTION_TYPE_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \ define_function_type (ENUM, RETURN, 0, 6, A1, A2, A3, A4, A5, A6); #define DEF_FUNCTION_TYPE_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \ define_function_type (ENUM, RETURN, 0, 7, A1, A2, A3, A4, A5, A6, A7); #define DEF_FUNCTION_TYPE_8(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8) \ define_function_type (ENUM, RETURN, 0, 8, A1, A2, A3, A4, A5, A6, A7, A8); #define DEF_FUNCTION_TYPE_9(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9) \ define_function_type (ENUM, RETURN, 0, 9, A1, A2, A3, A4, A5, A6, A7, A8, A9); #define DEF_FUNCTION_TYPE_10(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \ A10) \ define_function_type (ENUM, RETURN, 0, 10, A1, A2, A3, A4, A5, A6, A7, A8, \ A9, A10); #define DEF_FUNCTION_TYPE_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, A9, \ A10, A11) \ define_function_type (ENUM, RETURN, 0, 11, A1, A2, A3, A4, A5, A6, A7, A8, \ A9, A10, A11); #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ define_function_type (ENUM, RETURN, 1, 0); #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, A1) \ define_function_type (ENUM, RETURN, 1, 1, A1); #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, A1, A2) \ define_function_type (ENUM, RETURN, 1, 2, A1, A2); #define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, A1, A2, A3) \ define_function_type (ENUM, RETURN, 1, 3, A1, A2, A3); #define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, A1, A2, A3, A4) \ define_function_type (ENUM, RETURN, 1, 4, A1, A2, A3, A4); #define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, A1, A2, A3, A4, A5) \ define_function_type (ENUM, RETURN, 1, 5, A1, A2, A3, A4, A5); #define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, A1, A2, A3, A4, A5, A6) \ define_function_type (ENUM, RETURN, 1, 6, A1, A2, A3, A4, A5, A6); #define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7) \ define_function_type (ENUM, RETURN, 1, 7, A1, A2, A3, A4, A5, A6, A7); #define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, A1, A2, A3, A4, A5, A6, A7, A8, \ A9, A10, A11) \ define_function_type (ENUM, RETURN, 1, 11, A1, A2, A3, A4, A5, A6, A7, A8, \ A9, A10, A11); #define DEF_POINTER_TYPE(ENUM, TYPE) \ builtin_types[ENUM] = build_pointer_type (builtin_types[TYPE]); #include "builtin-types.def" #undef DEF_PRIMITIVE_TYPE #undef DEF_FUNCTION_TYPE_1 #undef DEF_FUNCTION_TYPE_2 #undef DEF_FUNCTION_TYPE_3 #undef DEF_FUNCTION_TYPE_4 #undef DEF_FUNCTION_TYPE_5 #undef DEF_FUNCTION_TYPE_6 #undef DEF_FUNCTION_TYPE_7 #undef DEF_FUNCTION_TYPE_8 #undef DEF_FUNCTION_TYPE_9 #undef DEF_FUNCTION_TYPE_10 #undef DEF_FUNCTION_TYPE_11 #undef DEF_FUNCTION_TYPE_VAR_0 #undef DEF_FUNCTION_TYPE_VAR_1 #undef DEF_FUNCTION_TYPE_VAR_2 #undef DEF_FUNCTION_TYPE_VAR_3 #undef DEF_FUNCTION_TYPE_VAR_4 #undef DEF_FUNCTION_TYPE_VAR_5 #undef DEF_FUNCTION_TYPE_VAR_6 #undef DEF_FUNCTION_TYPE_VAR_7 #undef DEF_FUNCTION_TYPE_VAR_11 #undef DEF_POINTER_TYPE builtin_types[Type::BT_LAST] = NULL_TREE; } /** * Define all builtin attributes in the `builtin_types` array */ void BuiltinsContext::define_builtin_attributes () { auto *built_in_attributes = builtin_attributes; #define DEF_ATTR_NULL_TREE(ENUM) built_in_attributes[(int) ENUM] = NULL_TREE; #define DEF_ATTR_INT(ENUM, VALUE) \ built_in_attributes[ENUM] = build_int_cst (NULL_TREE, VALUE); #define DEF_ATTR_STRING(ENUM, VALUE) \ built_in_attributes[ENUM] = build_string (strlen (VALUE), VALUE); #define DEF_ATTR_IDENT(ENUM, STRING) \ built_in_attributes[ENUM] = get_identifier (STRING); #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ built_in_attributes[ENUM] \ = tree_cons (built_in_attributes[PURPOSE], built_in_attributes[VALUE], \ built_in_attributes[CHAIN]); #include "builtin-attrs.def" #undef DEF_ATTR_NULL_TREE #undef DEF_ATTR_INT #undef DEF_ATTR_STRING #undef DEF_ATTR_IDENT #undef DEF_ATTR_TREE_LIST } /** * Define all builtin functions during the first initialization of the * `BuiltinsContext`. */ void BuiltinsContext::define_builtins () { auto *built_in_attributes = builtin_attributes; auto build_builtin = [this] (built_in_function fn_code, const char *fn_name, built_in_class fn_class, tree fn_type, bool both, bool fallback, tree attributes, bool implicit) { if (fn_type == error_mark_node) return; static auto to_skip = strlen ("__builtin_"); auto libname = fn_name + to_skip; auto decl = add_builtin_function (fn_name, fn_type, fn_code, fn_class, fallback ? libname : NULL, attributes); set_builtin_decl (fn_code, decl, implicit); builtin_functions.insert ({std::string (fn_name), decl}); }; #define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P, \ NONANSI_P, ATTRS, IMPLICIT, COND) \ if (NAME && COND) \ build_builtin (ENUM, NAME, CLASS, builtin_types[TYPE], BOTH_P, FALLBACK_P, \ built_in_attributes[ATTRS], IMPLICIT); #include "builtins.def" #undef DEF_BUILTIN } /** * Register direct mappings between Rust functions and GCC builtins */ void BuiltinsContext::register_rust_mappings () { rust_intrinsic_to_gcc_builtin = { {"unreachable", "__builtin_unreachable"}, {"abort", "__builtin_abort"}, // Math intrinsics {"sqrtf32", "__builtin_sqrtf"}, {"sqrtf64", "__builtin_sqrt"}, {"sinf32", "__builtin_sinf"}, {"sinf64", "__builtin_sin"}, {"cosf32", "__builtin_cosf"}, {"cosf64", "__builtin_cos"}, {"powf32", "__builtin_powf"}, {"powf64", "__builtin_pow"}, {"powif32", "__builtin_powif"}, {"powif64", "__builtin_powi"}, {"expf32", "__builtin_expf"}, {"expf64", "__builtin_exp"}, {"exp2f32", "__builtin_exp2f"}, {"exp2f64", "__builtin_exp2"}, {"logf32", "__builtin_logf"}, {"logf64", "__builtin_log"}, {"log10f32", "__builtin_log10f"}, {"log10f64", "__builtin_log10"}, {"log2f32", "__builtin_log2f"}, {"log2f64", "__builtin_log2"}, {"fmaf32", "__builtin_fmaf"}, {"fmaf64", "__builtin_fma"}, {"fabsf32", "__builtin_fabsf"}, {"fabsf64", "__builtin_fabs"}, {"minnumf32", "__builtin_fminf"}, {"minnumf64", "__builtin_fmin"}, {"maxnumf32", "__builtin_fmaxf"}, {"maxnumf64", "__builtin_fmax"}, {"copysignf32", "__builtin_copysignf"}, {"copysignf64", "__builtin_copysign"}, {"floorf32", "__builtin_floorf"}, {"floorf64", "__builtin_floor"}, {"ceilf32", "__builtin_ceilf"}, {"ceilf64", "__builtin_ceil"}, {"truncf32", "__builtin_truncf"}, {"truncf64", "__builtin_trunc"}, {"rintf32", "__builtin_rintf"}, {"rintf64", "__builtin_rint"}, {"nearbyintf32", "__builtin_nearbyintf"}, {"nearbyintf64", "__builtin_nearbyint"}, {"roundf32", "__builtin_roundf"}, {"roundf64", "__builtin_round"}, }; } void BuiltinsContext::setup () { define_builtin_types (); define_builtin_attributes (); define_builtins (); register_rust_mappings (); } bool BuiltinsContext::lookup_gcc_builtin (const std::string &name, tree *builtin) { auto it = builtin_functions.find (name); if (it == builtin_functions.end ()) return false; *builtin = it->second; return true; } } // namespace Compile } // namespace Rust