diff --git a/gcc/rust/backend/rust-builtins.cc b/gcc/rust/backend/rust-builtins.cc index cd06379fcb00..ee3e42e6b534 100644 --- a/gcc/rust/backend/rust-builtins.cc +++ b/gcc/rust/backend/rust-builtins.cc @@ -14,8 +14,13 @@ // 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 { @@ -33,280 +38,275 @@ BuiltinsContext::get () 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 ()) - return false; + if (it != rust_intrinsic_to_gcc_builtin.end ()) + to_search = &it->second; - return lookup_gcc_builtin (it->second, builtin); + 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::setup_overflow_fns () +BuiltinsContext::define_function_type (Type def_idx, Type ret_idx, + bool is_variadic, size_t n, ...) { - tree overflow_type - = build_varargs_function_type_list (boolean_type_node, NULL_TREE); - - define_builtin ("add_overflow", BUILT_IN_ADD_OVERFLOW, - "__builtin_add_overflow", "add_overflow", overflow_type, 0); - define_builtin ("sub_overflow", BUILT_IN_SUB_OVERFLOW, - "__builtin_sub_overflow", "sub_overflow", overflow_type, 0); - define_builtin ("mul_overflow", BUILT_IN_MUL_OVERFLOW, - "__builtin_mul_overflow", "mul_overflow", overflow_type, 0); + va_list list; + va_start (list, n); + + auto args = std::vector (); + + for (size_t i = 0; i < n; i++) + { + auto arg_idx = va_arg (list, size_t); + 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) + { + 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); } -void -BuiltinsContext::setup_math_fns () +// Taken directly from the D frontend +static void +build_c_type_nodes (void) { - tree fn_type_f32_to_f32 - = build_function_type_list (float_type_node, float_type_node, NULL_TREE); - tree fn_type_f64_to_f64 - = build_function_type_list (double_type_node, double_type_node, NULL_TREE); - tree fn_type_f32_f32_to_f32 - = build_function_type_list (float_type_node, float_type_node, - float_type_node, NULL_TREE); - tree fn_type_f64_f64_to_f64 - = build_function_type_list (double_type_node, double_type_node, - double_type_node, NULL_TREE); - tree fn_type_f32_i32_to_f32 - = build_function_type_list (float_type_node, float_type_node, - integer_type_node, NULL_TREE); - tree fn_type_f64_i32_to_f64 - = build_function_type_list (double_type_node, double_type_node, - integer_type_node, NULL_TREE); - - define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("sqrtf64", BUILT_IN_SQRT, "__builtin_sqrt", "sqrt", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("powif32", BUILT_IN_POWIF, "__builtin_powif", "powif", - fn_type_f32_i32_to_f32, builtin_const); - define_builtin ("powif64", BUILT_IN_POWI, "__builtin_powi", "powi", - fn_type_f64_i32_to_f64, builtin_const); - - define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("sinf64", BUILT_IN_SIN, "__builtin_sin", "sin", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("cosf32", BUILT_IN_COSF, "__builtin_cosf", "cosf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("cosf64", BUILT_IN_COS, "__builtin_cos", "cos", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("powf32", BUILT_IN_POWF, "__builtin_powf", "powf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("powf64", BUILT_IN_POW, "__builtin_pow", "pow", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("expf32", BUILT_IN_EXPF, "__builtin_expf", "expf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("expf64", BUILT_IN_EXP, "__builtin_exp", "exp", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("exp2f32", BUILT_IN_EXP2F, "__builtin_exp2f", "exp2f", - fn_type_f32_to_f32, builtin_const); - define_builtin ("exp2f64", BUILT_IN_EXP2, "__builtin_exp2", "exp2", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("logf32", BUILT_IN_LOGF, "__builtin_logf", "logf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("logf64", BUILT_IN_LOG, "__builtin_log", "log", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("log10f32", BUILT_IN_LOG10F, "__builtin_log10f", "log10f", - fn_type_f32_to_f32, builtin_const); - define_builtin ("log10f64", BUILT_IN_LOG10, "__builtin_log10", "log10", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("log2f32", BUILT_IN_LOG2F, "__builtin_log2f", "log2f", - fn_type_f32_to_f32, builtin_const); - define_builtin ("log2f64", BUILT_IN_LOG2, "__builtin_log2", "log2", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("fmaf32", BUILT_IN_FMAF, "__builtin_fmaf", "fmaf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("fmaf64", BUILT_IN_FMA, "__builtin_fma", "fma", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("fabsf32", BUILT_IN_FABSF, "__builtin_fabsf", "fabsf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("fabsf64", BUILT_IN_FABS, "__builtin_fabs", "fabs", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("minnumf32", BUILT_IN_FMINF, "__builtin_fminf", "fminf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("minnumf64", BUILT_IN_FMIN, "__builtin_fmin", "fmin", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("maxnumf32", BUILT_IN_FMAXF, "__builtin_fmaxf", "fmaxf", - fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("maxnumf64", BUILT_IN_FMAX, "__builtin_fmax", "fmax", - fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("copysignf32", BUILT_IN_COPYSIGNF, "__builtin_copysignf", - "copysignf", fn_type_f32_f32_to_f32, builtin_const); - define_builtin ("copysignf64", BUILT_IN_COPYSIGN, "__builtin_copysign", - "copysign", fn_type_f64_f64_to_f64, builtin_const); - - define_builtin ("floorf32", BUILT_IN_FLOORF, "__builtin_floorf", "floorf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("floorf64", BUILT_IN_FLOOR, "__builtin_floor", "floor", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("ceilf32", BUILT_IN_CEILF, "__builtin_ceilf", "ceilf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("ceilf64", BUILT_IN_CEIL, "__builtin_ceil", "ceil", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("truncf32", BUILT_IN_TRUNCF, "__builtin_truncf", "truncf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("truncf64", BUILT_IN_TRUNC, "__builtin_trunc", "trunc", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("rintf32", BUILT_IN_RINTF, "__builtin_rintf", "rintf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("rintf64", BUILT_IN_RINT, "__builtin_rint", "rint", - fn_type_f64_to_f64, builtin_const); - - define_builtin ("nearbyintf32", BUILT_IN_NEARBYINTF, "__builtin_nearbyintf", - "nearbyintf", fn_type_f32_to_f32, builtin_const); - define_builtin ("nearbyintf64", BUILT_IN_NEARBYINT, "__builtin_nearbyint", - "nearbyint", fn_type_f64_to_f64, builtin_const); - - define_builtin ("roundf32", BUILT_IN_ROUNDF, "__builtin_roundf", "roundf", - fn_type_f32_to_f32, builtin_const); - define_builtin ("roundf64", BUILT_IN_ROUND, "__builtin_round", "round", - fn_type_f64_to_f64, builtin_const); + 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::setup_atomic_fns () +BuiltinsContext::define_builtin_types () { - auto atomic_store_type - = build_varargs_function_type_list (void_type_node, NULL_TREE); - auto atomic_load_type = [] (tree ret_type_node) { - return build_function_type_list (ret_type_node, - ptr_type_node, // const_ptr_type_node? - integer_type_node, NULL_TREE); + // 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; }; - // FIXME: These should be the definition for the generic version of the - // atomic_store builtins, but I cannot get them to work properly. Revisit - // later. define_builtin ("atomic_store", BUILT_IN_ATOMIC_STORE, - // "__atomic_store", NULL, - // atomic_store_type, 0); - // define_builtin ("atomic_store_n", BUILT_IN_ATOMIC_STORE_N, - // "__atomic_store_n", - // NULL, atomic_store_type, 0); - - define_builtin ("atomic_store_1", BUILT_IN_ATOMIC_STORE_1, "__atomic_store_1", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_2", BUILT_IN_ATOMIC_STORE_2, "__atomic_store_2", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_4", BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_8", BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", - NULL, atomic_store_type, 0); - define_builtin ("atomic_store_16", BUILT_IN_ATOMIC_STORE_16, - "__atomic_store_16", NULL, atomic_store_type, 0); - - define_builtin ("atomic_load_1", BUILT_IN_ATOMIC_LOAD_1, "__atomic_load_1", - NULL, atomic_load_type (integer_type_node), 0); - define_builtin ("atomic_load_2", BUILT_IN_ATOMIC_LOAD_2, "__atomic_load_2", - NULL, atomic_load_type (integer_type_node), 0); - define_builtin ("atomic_load_4", BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", - NULL, atomic_load_type (integer_type_node), 0); - define_builtin ("atomic_load_8", BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", - NULL, atomic_load_type (integer_type_node), 0); +#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::setup () +BuiltinsContext::define_builtin_attributes () + { - setup_math_fns (); - setup_overflow_fns (); - setup_atomic_fns (); - - define_builtin ("unreachable", BUILT_IN_UNREACHABLE, "__builtin_unreachable", - NULL, build_function_type (void_type_node, void_list_node), - builtin_const | builtin_noreturn); - - define_builtin ("abort", BUILT_IN_ABORT, "__builtin_abort", "abort", - build_function_type (void_type_node, void_list_node), - builtin_const | builtin_noreturn); - - define_builtin ("breakpoint", BUILT_IN_TRAP, "__builtin_trap", "breakpoint", - build_function_type (void_type_node, void_list_node), - builtin_const | builtin_noreturn); - - define_builtin ("expect", BUILT_IN_EXPECT, "__builtin_expect", "expect", - build_function_type_list (long_integer_type_node, - long_integer_type_node, - long_integer_type_node, NULL_TREE), - builtin_const); - - define_builtin ("memcpy", BUILT_IN_MEMCPY, "__builtin_memcpy", "memcpy", - build_function_type_list (build_pointer_type (void_type_node), - build_pointer_type (void_type_node), - build_pointer_type (void_type_node), - size_type_node, NULL_TREE), - 0); - - define_builtin ("memset", BUILT_IN_MEMSET, "__builtin_memset", "memset", - build_function_type_list (void_type_node, ptr_type_node, - integer_type_node, size_type_node, - NULL_TREE), - 0); - - define_builtin ("prefetch", BUILT_IN_PREFETCH, "__builtin_prefetch", - "prefetch", - build_varargs_function_type_list ( - build_pointer_type (const_ptr_type_node), NULL_TREE), - builtin_const); + 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 } -static void -handle_flags (tree decl, int flags) +/** + * Define all builtin functions during the first initialization of the + * `BuiltinsContext`. + */ +void +BuiltinsContext::define_builtins () { - if (flags & builtin_const) - TREE_READONLY (decl) = 1; - if (flags & builtin_noreturn) - TREE_READONLY (decl) = 1; - if (flags & builtin_novops) - DECL_IS_NOVOPS (decl) = 1; + 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::define_builtin (const std::string rust_name, - built_in_function bcode, const char *name, - const char *libname, tree fntype, int flags) +BuiltinsContext::register_rust_mappings () { - tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL, - libname, NULL_TREE); - handle_flags (decl, flags); - set_builtin_decl (bcode, decl, true); - - this->builtin_functions_[name] = decl; - if (libname != NULL) - { - decl = add_builtin_function (libname, fntype, bcode, BUILT_IN_NORMAL, - NULL, NULL_TREE); - handle_flags (decl, flags); + rust_intrinsic_to_gcc_builtin = { + {"sinf32", "__builtin_sinf"}, + {"sqrtf32", "__builtin_sqrtf"}, + {"unreachable", "__builtin_unreachable"}, + {"abort", "__builtin_abort"}, + }; +} - this->builtin_functions_[libname] = decl; - } +void +BuiltinsContext::setup () +{ + define_builtin_types (); + define_builtin_attributes (); + define_builtins (); - rust_intrinsic_to_gcc_builtin[rust_name] = name; + 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 ()) + auto it = builtin_functions.find (name); + if (it == builtin_functions.end ()) return false; *builtin = it->second; diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h index c2825107faff..5052edad51e9 100644 --- a/gcc/rust/backend/rust-builtins.h +++ b/gcc/rust/backend/rust-builtins.h @@ -21,6 +21,7 @@ #include "rust-tree.h" #include "langhooks.h" #include "tree.h" +#include "selftest.h" namespace Rust { namespace Compile { @@ -75,6 +76,7 @@ namespace Compile { // _ => return None, // }; // Some(cx.get_intrinsic(&llvm_name)) + class BuiltinsContext { public: @@ -83,6 +85,110 @@ class BuiltinsContext bool lookup_simple_builtin (const std::string &name, tree *builtin); private: + enum Type + { +#define DEF_PRIMITIVE_TYPE(NAME, V) NAME, +#define DEF_FUNCTION_TYPE_0(NAME, R) NAME, +#define DEF_FUNCTION_TYPE_1(NAME, R, A1) NAME, +#define DEF_FUNCTION_TYPE_2(NAME, R, A1, A2) NAME, +#define DEF_FUNCTION_TYPE_3(NAME, R, A1, A2, A3) NAME, +#define DEF_FUNCTION_TYPE_4(NAME, R, A1, A2, A3, A4) NAME, +#define DEF_FUNCTION_TYPE_5(NAME, R, A1, A2, A3, A4, A5) NAME, +#define DEF_FUNCTION_TYPE_6(NAME, R, A1, A2, A3, A4, A5, A6) NAME, +#define DEF_FUNCTION_TYPE_7(NAME, R, A1, A2, A3, A4, A5, A6, A7) NAME, +#define DEF_FUNCTION_TYPE_8(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8) NAME, +#define DEF_FUNCTION_TYPE_9(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9) NAME, +#define DEF_FUNCTION_TYPE_10(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \ + NAME, +#define DEF_FUNCTION_TYPE_11(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, \ + A11) \ + NAME, +#define DEF_FUNCTION_TYPE_VAR_0(NAME, R) NAME, +#define DEF_FUNCTION_TYPE_VAR_1(NAME, R, A1) NAME, +#define DEF_FUNCTION_TYPE_VAR_2(NAME, R, A1, A2) NAME, +#define DEF_FUNCTION_TYPE_VAR_3(NAME, R, A1, A2, A3) NAME, +#define DEF_FUNCTION_TYPE_VAR_4(NAME, R, A1, A2, A3, A4) NAME, +#define DEF_FUNCTION_TYPE_VAR_5(NAME, R, A1, A2, A3, A4, A5) NAME, +#define DEF_FUNCTION_TYPE_VAR_6(NAME, R, A1, A2, A3, A4, A5, A6) NAME, +#define DEF_FUNCTION_TYPE_VAR_7(NAME, R, A1, A2, A3, A4, A5, A6, A7) NAME, +#define DEF_FUNCTION_TYPE_VAR_11(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, \ + A10, A11) \ + NAME, +#define DEF_POINTER_TYPE(NAME, TYPE) NAME, + +#include "builtin-types.def" + +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_0 +#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 + + BT_LAST, + }; + + enum Attr + { +#define DEF_ATTR_NULL_TREE(ENUM) ENUM, +#define DEF_ATTR_INT(ENUM, VALUE) ENUM, +#define DEF_ATTR_STRING(ENUM, VALUE) ENUM, +#define DEF_ATTR_IDENT(ENUM, STRING) ENUM, +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, + +#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 + + ATTR_LAST, + }; + + /** + * All builtin types, as defined in `builtin-types.def` + * + * This array is filled by the `define_builtin_types` method, during the first + * initialization of the `BuiltinsContext` + */ + tree builtin_types[Type::BT_LAST + 1]; + + /** + * Similarly, this array contains all builtin attributes, as defined in + * `builtin-attr.def` + * + * This array is filled by the `define_builtin_attributes` method, during the + * first initialization of the `BuiltinsContext` + */ + tree builtin_attributes[Attr::ATTR_LAST + 1]; + + void define_function_type (Type def, Type ret, bool is_variadic, size_t n, + ...); + void define_builtin_types (); + void define_builtin_attributes (); + void define_builtins (); + + void register_rust_mappings (); + BuiltinsContext (); void setup_overflow_fns (); @@ -91,20 +197,10 @@ class BuiltinsContext void setup (); - // Define a builtin function. BCODE is the builtin function code - // defined by builtins.def. NAME is the name of the builtin function. - // LIBNAME is the name of the corresponding library function, and is - // NULL if there isn't one. FNTYPE is the type of the function. - // CONST_P is true if the function has the const attribute. - // NORETURN_P is true if the function has the noreturn attribute. - void define_builtin (const std::string rust_name, built_in_function bcode, - const char *name, const char *libname, tree fntype, - int flags); - bool lookup_gcc_builtin (const std::string &name, tree *builtin); // A mapping of the GCC built-ins exposed to GCC Rust. - std::map builtin_functions_; + std::map builtin_functions; std::map rust_intrinsic_to_gcc_builtin; }; diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index feaf74dff7b7..1714d6bd2d2f 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -29,6 +29,8 @@ #include "print-tree.h" #include "fold-const.h" #include "langhooks.h" +#include "rust-gcc.h" +#include "rust-constexpr.h" #include "print-tree.h" @@ -250,6 +252,7 @@ Intrinsics::compile (TyTy::FnType *fntype) tree builtin = error_mark_node; BuiltinsContext &builtin_ctx = BuiltinsContext::get (); + if (builtin_ctx.lookup_simple_builtin (fntype->get_identifier (), &builtin)) return builtin; @@ -749,8 +752,7 @@ copy_handler_inner (Context *ctx, TyTy::FnType *fntype, bool overlaps) = build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count); tree memcpy_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "memmove" - : "memcpy", + BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "__builtin_memmove" : "__builtin_memcpy", &memcpy_raw); rust_assert (memcpy_raw); auto memcpy = build_fold_addr_expr_loc (UNKNOWN_LOCATION, memcpy_raw); @@ -796,19 +798,36 @@ prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, Prefetch kind) enter_intrinsic_block (ctx, fndecl); - auto addr = Backend::var_expression (args[0], UNDEF_LOCATION); - auto locality = Backend::var_expression (args[1], UNDEF_LOCATION); - auto rw_flag = make_unsigned_long_tree (kind == Prefetch::Write ? 1 : 0); + auto addr = ctx->get_backend ()->var_expression (args[0], Location ()); + + // The core library technically allows you to pass any i32 value as a + // locality, but LLVM will then complain if the value cannot be constant + // evaluated. For now, we ignore the locality argument and instead always + // pass `3` (the most restrictive value). This allows us to still have + // prefetch behavior, just not as granular as expected. In future Rust + // versions, we hope that prefetch intrinsics will be split up according to + // locality, similarly to atomic intrinsics. + // The solution is to try and perform constant folding for the locality + // argument, or instead of creating a new function definition, modify the call + // site directly This has the bad side-effect of creating warnings about + // `unused name - locality`, which we hack away here: + // TODO: Take care of handling locality properly + ctx->get_backend ()->var_expression (args[1], Location ()); + + auto rw_flag = make_unsigned_long_tree (ctx, kind == Prefetch::Write ? 1 : 0); auto prefetch_raw = NULL_TREE; - auto ok - = BuiltinsContext::get ().lookup_simple_builtin ("prefetch", &prefetch_raw); + auto ok = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_prefetch", + &prefetch_raw); rust_assert (ok); auto prefetch = build_fold_addr_expr_loc (UNKNOWN_LOCATION, prefetch_raw); auto prefetch_call - = Backend::call_expression (prefetch, {addr, rw_flag, locality}, nullptr, - UNDEF_LOCATION); + = ctx->get_backend ()->call_expression (prefetch, + {addr, rw_flag, + // locality arg + make_unsigned_long_tree (ctx, 3)}, + nullptr, Location ()); TREE_READONLY (prefetch_call) = 0; TREE_SIDE_EFFECTS (prefetch_call) = 1; @@ -833,7 +852,7 @@ build_atomic_builtin_name (const std::string &prefix, location_t locus, // TODO: Can we maybe get the generic version (atomic_store_n) to work... This // would be so much better - std::string result = prefix; + std::string result = "__" + prefix; // + "n"; auto type_name = operand_type->get_name (); if (type_name == "usize" || type_name == "isize") @@ -843,6 +862,13 @@ build_atomic_builtin_name (const std::string &prefix, location_t locus, return ""; } + if (type_name.at (0) == 'i') + { + rust_sorry_at (locus, "atomics are not yet supported for signed " + "integer types (i8, i16, i32, i64, i128)"); + return ""; + } + auto type_size_str = allowed_types.find (type_name); if (!check_for_basic_integer_type ("atomic", locus, operand_type)) @@ -970,6 +996,7 @@ atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering) TREE_SIDE_EFFECTS (load_call) = 1; ctx->add_statement (return_statement); + finalize_intrinsic_block (ctx, fndecl); return fndecl; diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 5cdd44c97de2..088148f5d6f8 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -1131,20 +1131,20 @@ fetch_overflow_builtins (ArithmeticOrLogicalOperator op) switch (op) { case ArithmeticOrLogicalOperator::ADD: - builtin_ctx.lookup_simple_builtin ("add_overflow", &builtin); + builtin_ctx.lookup_simple_builtin ("__builtin_add_overflow", &builtin); break; case ArithmeticOrLogicalOperator::SUBTRACT: - builtin_ctx.lookup_simple_builtin ("sub_overflow", &builtin); + builtin_ctx.lookup_simple_builtin ("__builtin_sub_overflow", &builtin); break; case ArithmeticOrLogicalOperator::MULTIPLY: - builtin_ctx.lookup_simple_builtin ("mul_overflow", &builtin); + builtin_ctx.lookup_simple_builtin ("__builtin_mul_overflow", &builtin); break; default: rust_unreachable (); break; }; - builtin_ctx.lookup_simple_builtin ("abort", &abort); + builtin_ctx.lookup_simple_builtin ("__builtin_abort", &abort); rust_assert (abort); rust_assert (builtin); diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-4.rs b/gcc/testsuite/rust/compile/torture/intrinsics-4.rs index 1f6c0d6608a2..3d26e999b9e9 100644 --- a/gcc/testsuite/rust/compile/torture/intrinsics-4.rs +++ b/gcc/testsuite/rust/compile/torture/intrinsics-4.rs @@ -67,7 +67,7 @@ extern "rust-intrinsic" { } fn main() { - let mut dst = 15; + let mut dst = 15u32; let new_value = 14; unsafe { diff --git a/gcc/testsuite/rust/execute/torture/atomic_load.rs b/gcc/testsuite/rust/execute/torture/atomic_load.rs index b66c4641424a..11da84844945 100644 --- a/gcc/testsuite/rust/execute/torture/atomic_load.rs +++ b/gcc/testsuite/rust/execute/torture/atomic_load.rs @@ -66,14 +66,14 @@ extern "rust-intrinsic" { pub fn atomic_load_unordered(src: *const T) -> T; } -fn main() -> i32 { +fn main() -> u32 { let one; let two; let three; let four; unsafe { - let mut src = 1; + let mut src = 1u32; one = atomic_load_seqcst(&src); src = 2; diff --git a/gcc/testsuite/rust/execute/torture/atomic_store.rs b/gcc/testsuite/rust/execute/torture/atomic_store.rs index dcbb2a90f199..1b46678ba382 100644 --- a/gcc/testsuite/rust/execute/torture/atomic_store.rs +++ b/gcc/testsuite/rust/execute/torture/atomic_store.rs @@ -66,8 +66,8 @@ extern "rust-intrinsic" { pub fn atomic_store_unordered(dst: *mut T, val: T); } -fn main() -> i32 { - let mut dst = 15; +fn main() -> u32 { + let mut dst = 15u32; let one; let two; let three;