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;