[COMMITTED 071/101] gccrs: refactor builtins initialization and attributes
arthur.cohen@embecosm.com
arthur.cohen@embecosm.com
Tue Jan 30 12:07:27 GMT 2024
From: Arthur Cohen <arthur.cohen@embecosm.com>
This commit performs builtin initialization in a more "GCC-y" way,
similarly to what the D frontend is doing. This way, we no longer have
to worry about invalid attributes or types when initializing them by
hand.
Also add attributes support through LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
lang hook.
Most of these changes are based on D frontend.
gcc/rust/ChangeLog:
* Make-lang.in (GRS_OBJS): Add rust-attribs.o.
* backend/rust-builtins.cc (builtin_const, builtin_noreturn)
(builtin_novops): Remove.
(BuiltinsContext::lookup_simple_builtin): Adjust.
(BuiltinsContext::setup_overflow_fns): Remove.
(BuiltinsContext::define_function_type): Set builtin type to
errormark so the builtin is considered unavailable.
(BuiltinsContext::setup_math_fns): Remove.
(BuiltinsContext::setup_atomic_fns): Remove.
(build_c_type_nodes): Refactor based on D frontend.
(BuiltinsContext::define_builtin_types): Likewise.
(DEF_PRIMITIVE_TYPE): New.
(DEF_FUNCTION_TYPE_0): New.
(DEF_FUNCTION_TYPE_1): New.
(DEF_FUNCTION_TYPE_2): New.
(DEF_FUNCTION_TYPE_3): New.
(DEF_FUNCTION_TYPE_4): New.
(DEF_FUNCTION_TYPE_5): New.
(DEF_FUNCTION_TYPE_6): New.
(DEF_FUNCTION_TYPE_7): New.
(DEF_FUNCTION_TYPE_8): New.
(DEF_FUNCTION_TYPE_9): New.
(DEF_FUNCTION_TYPE_10): New.
(DEF_FUNCTION_TYPE_11): New.
(DEF_FUNCTION_TYPE_VAR_0): New.
(DEF_FUNCTION_TYPE_VAR_1): New.
(DEF_FUNCTION_TYPE_VAR_2): New.
(DEF_FUNCTION_TYPE_VAR_3): New.
(DEF_FUNCTION_TYPE_VAR_4): New.
(DEF_FUNCTION_TYPE_VAR_5): New.
(DEF_FUNCTION_TYPE_VAR_6): New.
(DEF_FUNCTION_TYPE_VAR_7): New.
(DEF_FUNCTION_TYPE_VAR_11): New.
(DEF_POINTER_TYPE): New.
(BuiltinsContext::setup): Adjust.
(BuiltinsContext::define_builtin_attributes): New.
(DEF_ATTR_NULL_TREE): New.
(DEF_ATTR_INT): New.
(DEF_ATTR_STRING): New.
(DEF_ATTR_IDENT): New.
(DEF_ATTR_TREE_LIST): New.
(handle_flags): Remove.
(BuiltinsContext::define_builtins): New.
(DEF_BUILTIN): New.
(BuiltinsContext::define_builtin): Remove.
(BuiltinsContext::register_rust_mappings): New. Add all missing
builtins.
(BuiltinsContext::lookup_gcc_builtin): Adjust.
* backend/rust-builtins.h (DEF_PRIMITIVE_TYPE): New.
(DEF_FUNCTION_TYPE_0): New.
(DEF_FUNCTION_TYPE_1): New.
(DEF_FUNCTION_TYPE_2): New.
(DEF_FUNCTION_TYPE_3): New.
(DEF_FUNCTION_TYPE_4): New.
(DEF_FUNCTION_TYPE_5): New.
(DEF_FUNCTION_TYPE_6): New.
(DEF_FUNCTION_TYPE_7): New.
(DEF_FUNCTION_TYPE_8): New.
(DEF_FUNCTION_TYPE_9): New.
(DEF_FUNCTION_TYPE_10): New.
(DEF_FUNCTION_TYPE_11): New.
(DEF_FUNCTION_TYPE_VAR_0): New.
(DEF_FUNCTION_TYPE_VAR_1): New.
(DEF_FUNCTION_TYPE_VAR_2): New.
(DEF_FUNCTION_TYPE_VAR_3): New.
(DEF_FUNCTION_TYPE_VAR_4): New.
(DEF_FUNCTION_TYPE_VAR_5): New.
(DEF_FUNCTION_TYPE_VAR_6): New.
(DEF_FUNCTION_TYPE_VAR_7): New.
(DEF_FUNCTION_TYPE_VAR_11): New.
(DEF_POINTER_TYPE): New.
(DEF_ATTR_NULL_TREE): New.
(DEF_ATTR_INT): New.
(DEF_ATTR_STRING): New.
(DEF_ATTR_IDENT): New.
(DEF_ATTR_TREE_LIST): New.
* backend/rust-compile-intrinsic.cc (Intrinsics::compile): Add
comment.
(op_with_overflow_inner): Adjust.
(copy_handler_inner): Adjust.
(prefetch_data_handler): Adjust.
(build_atomic_builtin_name): Adjust.
(atomic_load_handler_inner): Adjust.
(uninit_handler): Adjust.
(move_val_init_handler): Adjust.
(expect_handler_inner): Adjust.
* rust-gcc.cc (fetch_overflow_builtins): Adjust.
* rust-lang.cc (rust_localize_identifier): Adjust.
(LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): New.
* rust-attribs.cc: New file.
gcc/testsuite/ChangeLog:
* rust/compile/torture/intrinsics-4.rs: Adjust.
* rust/compile/torture/intrinsics-math.rs: Adjust.
* rust/execute/torture/atomic_load.rs: Adjust.
* rust/execute/torture/atomic_store.rs: Adjust.
* rust/compile/torture/intrinsics-1.rs: Removed.
* rust/compile/torture/builtin_abort.rs: New test.
* rust/execute/torture/builtin_abort.rs: New test.
Signed-off-by: Marc Poulhiès <dkm@kataplop.net>
Co-authored-by: Arthur Cohen <arthur.cohen@embecosm.com>
---
gcc/rust/Make-lang.in | 1 +
gcc/rust/backend/rust-builtins.cc | 524 ++++++++++--------
gcc/rust/backend/rust-builtins.h | 118 +++-
gcc/rust/backend/rust-compile-intrinsic.cc | 68 ++-
gcc/rust/rust-attribs.cc | 370 +++++++++++++
gcc/rust/rust-gcc.cc | 8 +-
gcc/rust/rust-lang.cc | 6 +
.../rust/compile/torture/builtin_abort.rs | 18 +
.../rust/compile/torture/intrinsics-1.rs | 22 -
.../rust/compile/torture/intrinsics-4.rs | 2 +-
.../rust/compile/torture/intrinsics-math.rs | 80 +--
.../rust/execute/torture/atomic_load.rs | 4 +-
.../rust/execute/torture/atomic_store.rs | 4 +-
.../rust/execute/torture/builtin_abort.rs | 14 +
14 files changed, 899 insertions(+), 340 deletions(-)
create mode 100644 gcc/rust/rust-attribs.cc
create mode 100644 gcc/testsuite/rust/compile/torture/builtin_abort.rs
delete mode 100644 gcc/testsuite/rust/compile/torture/intrinsics-1.rs
create mode 100644 gcc/testsuite/rust/execute/torture/builtin_abort.rs
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 47cc87750be..b138ba26801 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -64,6 +64,7 @@ gccrs$(exeext): $(GCCRS_D_OBJS) $(EXTRA_GCC_OBJS) libcommon-target.a $(LIBDEPS)
# The compiler proper, not driver
GRS_OBJS = \
rust/rust-lang.o \
+ rust/rust-attribs.o \
rust/rust-object-export.o \
rust/rust-linemap.o \
rust/rust-diagnostics.o \
diff --git a/gcc/rust/backend/rust-builtins.cc b/gcc/rust/backend/rust-builtins.cc
index cd06379fcb0..1a87f869206 100644
--- a/gcc/rust/backend/rust-builtins.cc
+++ b/gcc/rust/backend/rust-builtins.cc
@@ -14,15 +14,16 @@
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
+#include "rust-diagnostics.h"
+#include "rust-system.h"
#include "rust-builtins.h"
+#include "target.h"
+#include "stringpool.h"
+
namespace Rust {
namespace Compile {
-static const int builtin_const = 1 << 0;
-static const int builtin_noreturn = 1 << 1;
-static const int builtin_novops = 1 << 2;
-
BuiltinsContext &
BuiltinsContext::get ()
{
@@ -33,280 +34,317 @@ 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<tree> ();
+
+ 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);
}
-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"},
+ {"sqrtf64", "__builtin_sqrt"},
+ {"unreachable", "__builtin_unreachable"},
+ {"abort", "__builtin_abort"},
+ {"sinf64", "__builtin_sin"},
+ {"cosf32", "__builtin_cosf"},
+ {"cosf64", "__builtin_cos"},
+ {"powf32", "__builtin_powf"},
+ {"powf64", "__builtin_pow"},
+ {"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"},
+ };
+}
- 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 c2825107faf..5052edad51e 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 @@ public:
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 @@ private:
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<std::string, tree> builtin_functions_;
+ std::map<std::string, tree> builtin_functions;
std::map<std::string, std::string> rust_intrinsic_to_gcc_builtin;
};
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc
index feaf74dff7b..49ee4c0ead9 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"
@@ -243,6 +245,14 @@ static const std::map<std::string,
Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
+/**
+ * Returns a FUNC_DECL corresponding to the intrinsic function FNTYPE. If a
+ * corresponding builtin exists, returns it. If not, search in the generic
+ * intrinsics declared and delegate the return to the corresponding handler.
+ *
+ * @param fntype The Rust function type that should be implemented by the
+ * compiler
+ */
tree
Intrinsics::compile (TyTy::FnType *fntype)
{
@@ -250,6 +260,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;
@@ -653,17 +664,17 @@ op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
switch (op)
{
case PLUS_EXPR:
- BuiltinsContext::get ().lookup_simple_builtin ("add_overflow",
+ BuiltinsContext::get ().lookup_simple_builtin ("__builtin_add_overflow",
&overflow_builtin);
break;
case MINUS_EXPR:
- BuiltinsContext::get ().lookup_simple_builtin ("sub_overflow",
+ BuiltinsContext::get ().lookup_simple_builtin ("__builtin_sub_overflow",
&overflow_builtin);
break;
case MULT_EXPR:
- BuiltinsContext::get ().lookup_simple_builtin ("mul_overflow",
+ BuiltinsContext::get ().lookup_simple_builtin ("__builtin_mul_overflow",
&overflow_builtin);
break;
@@ -749,8 +760,8 @@ 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);
@@ -797,18 +808,34 @@ 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);
+
+ // 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
+ Backend::var_expression (args[1], UNDEF_LOCATION);
+
auto rw_flag = make_unsigned_long_tree (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);
+ auto prefetch_call = Backend::call_expression (prefetch,
+ {addr, rw_flag,
+ // locality arg
+ make_unsigned_long_tree (3)},
+ nullptr, UNDEF_LOCATION);
TREE_READONLY (prefetch_call) = 0;
TREE_SIDE_EFFECTS (prefetch_call) = 1;
@@ -833,7 +860,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 +870,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 +1004,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;
@@ -1060,7 +1095,8 @@ uninit_handler (Context *ctx, TyTy::FnType *fntype)
// BUILTIN size_of FN BODY BEGIN
tree memset_builtin = error_mark_node;
- BuiltinsContext::get ().lookup_simple_builtin ("memset", &memset_builtin);
+ BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset",
+ &memset_builtin);
rust_assert (memset_builtin != error_mark_node);
// call memset with 0x01 and size of the thing see
@@ -1123,7 +1159,8 @@ move_val_init_handler (Context *ctx, TyTy::FnType *fntype)
tree size = TYPE_SIZE_UNIT (template_parameter_type);
tree memcpy_builtin = error_mark_node;
- BuiltinsContext::get ().lookup_simple_builtin ("memcpy", &memcpy_builtin);
+ BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memcpy",
+ &memcpy_builtin);
rust_assert (memcpy_builtin != error_mark_node);
src = build_fold_addr_expr_loc (BUILTINS_LOCATION, src);
@@ -1157,7 +1194,8 @@ expect_handler_inner (Context *ctx, TyTy::FnType *fntype, bool likely)
compile_fn_params (ctx, fntype, fndecl, ¶m_vars);
tree expr = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
tree expect_fn_raw = nullptr;
- BuiltinsContext::get ().lookup_simple_builtin ("expect", &expect_fn_raw);
+ BuiltinsContext::get ().lookup_simple_builtin ("__builtin_expect",
+ &expect_fn_raw);
rust_assert (expect_fn_raw);
auto expect_fn = build_fold_addr_expr_loc (BUILTINS_LOCATION, expect_fn_raw);
diff --git a/gcc/rust/rust-attribs.cc b/gcc/rust/rust-attribs.cc
new file mode 100644
index 00000000000..134dcf9eeca
--- /dev/null
+++ b/gcc/rust/rust-attribs.cc
@@ -0,0 +1,370 @@
+/* rust-attribs.c -- Rust attributes handling.
+ Copyright (C) 2015-2023 Free Software Foundation, Inc.
+
+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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "tree.h"
+#include "diagnostic.h"
+#include "tm.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "varasm.h"
+#include "fold-const.h"
+#include "opts.h"
+
+/* Heavily based on the D frontend Only a subset of the attributes found in the
+ * D frontend have been pulled, the goal being to have the builtin function
+ * correctly setup. It's possible we may need to add extra attributes in the
+ * future.
+ */
+
+extern const attribute_spec grs_langhook_common_attribute_table[];
+
+/* Internal attribute handlers for built-in functions. */
+static tree
+handle_noreturn_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_leaf_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_const_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_malloc_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_novops_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_nothrow_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+static tree
+handle_omp_declare_simd_attribute (tree *, tree, tree, int, bool *);
+
+/* Helper to define attribute exclusions. */
+#define ATTR_EXCL(name, function, type, variable) \
+ { \
+ name, function, type, variable \
+ }
+
+static const struct attribute_spec::exclusions attr_noreturn_exclusions[] = {
+ // ATTR_EXCL ("alloc_size", true, true, true),
+ ATTR_EXCL ("const", true, true, true),
+ // ATTR_EXCL ("malloc", true, true, true),
+ ATTR_EXCL ("pure", true, true, true),
+ ATTR_EXCL ("returns_twice", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_returns_twice_exclusions[]
+ = {
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL (NULL, false, false, false),
+};
+
+static const struct attribute_spec::exclusions attr_const_pure_exclusions[] = {
+ // ATTR_EXCL ("alloc_size", true, true, true),
+ ATTR_EXCL ("const", true, true, true),
+ ATTR_EXCL ("noreturn", true, true, true),
+ ATTR_EXCL ("pure", true, true, true), ATTR_EXCL (NULL, false, false, false)};
+
+/* Helper to define an attribute. */
+#define ATTR_SPEC(name, min_len, max_len, decl_req, type_req, fn_type_req, \
+ affects_type_identity, handler, exclude) \
+ { \
+ name, min_len, max_len, decl_req, type_req, fn_type_req, \
+ affects_type_identity, handler, exclude \
+ }
+
+/* Table of machine-independent attributes.
+ For internal use (marking of built-ins) only. */
+const attribute_spec grs_langhook_common_attribute_table[] = {
+ ATTR_SPEC ("noreturn", 0, 0, true, false, false, false,
+ handle_noreturn_attribute, attr_noreturn_exclusions),
+ ATTR_SPEC ("leaf", 0, 0, true, false, false, false, handle_leaf_attribute,
+ NULL),
+ ATTR_SPEC ("const", 0, 0, true, false, false, false, handle_const_attribute,
+ attr_const_pure_exclusions),
+ ATTR_SPEC ("malloc", 0, 0, true, false, false, false, handle_malloc_attribute,
+ NULL),
+ ATTR_SPEC ("returns_twice", 0, 0, true, false, false, false,
+ handle_returns_twice_attribute, attr_returns_twice_exclusions),
+ ATTR_SPEC ("pure", 0, 0, true, false, false, false, handle_pure_attribute,
+ attr_const_pure_exclusions),
+ ATTR_SPEC ("nonnull", 0, -1, false, true, true, false,
+ handle_nonnull_attribute, NULL),
+ ATTR_SPEC ("nothrow", 0, 0, true, false, false, false,
+ handle_nothrow_attribute, NULL),
+ ATTR_SPEC ("transaction_pure", 0, 0, false, true, true, false,
+ handle_transaction_pure_attribute, NULL),
+ ATTR_SPEC ("no vops", 0, 0, true, false, false, false,
+ handle_novops_attribute, NULL),
+ ATTR_SPEC ("type generic", 0, 0, false, true, true, false,
+ handle_type_generic_attribute, NULL),
+ ATTR_SPEC ("fn spec", 1, 1, false, true, true, false, handle_fnspec_attribute,
+ NULL),
+ ATTR_SPEC ("omp declare simd", 0, -1, true, false, false, false,
+ handle_omp_declare_simd_attribute, NULL),
+ ATTR_SPEC (NULL, 0, 0, false, false, false, false, NULL, NULL),
+};
+
+/* Built-in attribute handlers.
+ These functions take the arguments:
+ (tree *node, tree name, tree args, int flags, bool *no_add_attrs) */
+
+/* Handle a "noreturn" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_noreturn_attribute (tree *node, tree, tree, int, bool *)
+{
+ tree type = TREE_TYPE (*node);
+
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_THIS_VOLATILE (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node) = build_pointer_type (
+ build_type_variant (TREE_TYPE (type), TYPE_READONLY (TREE_TYPE (type)),
+ 1));
+ else
+ gcc_unreachable ();
+
+ return NULL_TREE;
+}
+
+/* Handle a "leaf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_leaf_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ if (!TREE_PUBLIC (*node))
+ {
+ warning (OPT_Wattributes, "%qE attribute has no effect", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "const" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_const_attribute (tree *node, tree, tree, int, bool *)
+{
+ tree type = TREE_TYPE (*node);
+
+ if (TREE_CODE (*node) == FUNCTION_DECL)
+ TREE_READONLY (*node) = 1;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+ TREE_TYPE (*node) = build_pointer_type (
+ build_type_variant (TREE_TYPE (type), 1,
+ TREE_THIS_VOLATILE (TREE_TYPE (type))));
+ else
+ gcc_unreachable ();
+
+ return NULL_TREE;
+}
+
+/* Handle a "malloc" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_malloc_attribute (tree *node, tree, tree, int, bool *)
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))));
+ DECL_IS_MALLOC (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_pure_attribute (tree *node, tree, tree, int, bool *)
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ DECL_PURE_P (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Handle a "no vops" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_novops_attribute (tree *node, tree, tree, int, bool *)
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ DECL_IS_NOVOPS (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Helper for nonnull attribute handling; fetch the operand number
+ from the attribute argument list. */
+
+static bool
+get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
+{
+ /* Verify the arg number is a constant. */
+ if (!tree_fits_uhwi_p (arg_num_expr))
+ return false;
+
+ *valp = TREE_INT_CST_LOW (arg_num_expr);
+ return true;
+}
+
+/* Handle the "nonnull" attribute. */
+
+static tree
+handle_nonnull_attribute (tree *node, tree, tree args, int, bool *)
+{
+ tree type = *node;
+
+ /* If no arguments are specified, all pointer arguments should be
+ non-null. Verify a full prototype is given so that the arguments
+ will have the correct types when we actually check them later.
+ Avoid diagnosing type-generic built-ins since those have no
+ prototype. */
+ if (!args)
+ {
+ gcc_assert (prototype_p (type) || !TYPE_ATTRIBUTES (type)
+ || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)));
+
+ return NULL_TREE;
+ }
+
+ /* Argument list specified. Verify that each argument number references
+ a pointer argument. */
+ for (; args; args = TREE_CHAIN (args))
+ {
+ tree argument;
+ unsigned HOST_WIDE_INT arg_num = 0, ck_num;
+
+ if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
+ gcc_unreachable ();
+
+ argument = TYPE_ARG_TYPES (type);
+ if (argument)
+ {
+ for (ck_num = 1;; ck_num++)
+ {
+ if (!argument || ck_num == arg_num)
+ break;
+ argument = TREE_CHAIN (argument);
+ }
+
+ gcc_assert (argument
+ && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE);
+ }
+ }
+
+ return NULL_TREE;
+}
+
+/* Handle a "nothrow" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_nothrow_attribute (tree *node, tree, tree, int, bool *)
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ TREE_NOTHROW (*node) = 1;
+ return NULL_TREE;
+}
+
+/* Handle a "type generic" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_type_generic_attribute (tree *node, tree, tree, int, bool *)
+{
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+ /* Ensure we have a variadic function. */
+ gcc_assert (!prototype_p (*node) || stdarg_p (*node));
+
+ return NULL_TREE;
+}
+
+/* Handle a "transaction_pure" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_transaction_pure_attribute (tree *node, tree, tree, int, bool *)
+{
+ /* Ensure we have a function type. */
+ gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+ return NULL_TREE;
+}
+
+/* Handle a "returns_twice" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_returns_twice_attribute (tree *node, tree, tree, int, bool *)
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+
+ DECL_IS_RETURNS_TWICE (*node) = 1;
+
+ return NULL_TREE;
+}
+
+/* Handle a "fn spec" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_fnspec_attribute (tree *, tree, tree args, int, bool *)
+{
+ gcc_assert (args && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+ && !TREE_CHAIN (args));
+ return NULL_TREE;
+}
+
+/* Handle an "omp declare simd" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+tree
+handle_omp_declare_simd_attribute (tree *node, tree, tree, int, bool *)
+{
+ gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+ return NULL_TREE;
+}
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 580bda7f00a..f17e19a2dfc 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/rust/rust-lang.cc b/gcc/rust/rust-lang.cc
index f9bec3f7c1e..8b76ba28ea2 100644
--- a/gcc/rust/rust-lang.cc
+++ b/gcc/rust/rust-lang.cc
@@ -380,6 +380,8 @@ rust_localize_identifier (const char *ident)
return identifier_to_locale (ident);
}
+extern const attribute_spec grs_langhook_common_attribute_table[];
+
/* The language hooks data structure. This is the main interface between the GCC
* front-end and the GCC middle-end/back-end. A list of language hooks could be
* found in <gcc>/langhooks.h
@@ -400,6 +402,8 @@ rust_localize_identifier (const char *ident)
#undef LANG_HOOKS_GIMPLIFY_EXPR
#undef LANG_HOOKS_EH_PERSONALITY
+#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
+
#define LANG_HOOKS_NAME "GNU Rust"
#define LANG_HOOKS_INIT grs_langhook_init
#define LANG_HOOKS_OPTION_LANG_MASK grs_langhook_option_lang_mask
@@ -420,6 +424,8 @@ rust_localize_identifier (const char *ident)
#define LANG_HOOKS_GIMPLIFY_EXPR grs_langhook_gimplify_expr
#define LANG_HOOKS_EH_PERSONALITY grs_langhook_eh_personality
+#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE grs_langhook_common_attribute_table
+
#if CHECKING_P
#undef LANG_HOOKS_RUN_LANG_SELFTESTS
diff --git a/gcc/testsuite/rust/compile/torture/builtin_abort.rs b/gcc/testsuite/rust/compile/torture/builtin_abort.rs
new file mode 100644
index 00000000000..3112cdc67f7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/builtin_abort.rs
@@ -0,0 +1,18 @@
+// { dg-options "-fdump-tree-original" }
+
+// { dg-final { scan-assembler-not "__builtin_abort\[^\"\]" } }
+// { dg-final { scan-tree-dump "__builtin_abort" "original" } }
+
+#![feature(rustc_attrs)]
+#![feature(intrinsics)]
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+pub fn main () -> i32 {
+ abort();
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-1.rs b/gcc/testsuite/rust/compile/torture/intrinsics-1.rs
deleted file mode 100644
index 6704c0210d1..00000000000
--- a/gcc/testsuite/rust/compile/torture/intrinsics-1.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// { dg-additional-options -fdump-tree-original }
-
-#![feature(intrinsics)]
-
-extern "rust-intrinsic" {
- pub fn sqrtf32(x: f32) -> f32;
- pub fn sinf32(x: f32) -> f32;
-}
-
-fn main() {
- unsafe fn foo() {
- let mut f32;
-
- f32 = sqrtf32(5f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sqrtf \(5\.0e\+0\);$} 1 original } }
-
- f32 = sinf32(39f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sinf \(3\.9e\+1\);$} 1 original } }
- }
-
- unsafe { foo() };
-}
diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-4.rs b/gcc/testsuite/rust/compile/torture/intrinsics-4.rs
index 1f6c0d6608a..3d26e999b9e 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/compile/torture/intrinsics-math.rs b/gcc/testsuite/rust/compile/torture/intrinsics-math.rs
index fb329baafdd..42acdde1494 100644
--- a/gcc/testsuite/rust/compile/torture/intrinsics-math.rs
+++ b/gcc/testsuite/rust/compile/torture/intrinsics-math.rs
@@ -69,104 +69,104 @@ fn main() {
let mut f64;
f32 = sqrtf32(1f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sqrtf \(1\.0e\+0\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_sqrt. \(.*.*1\.0e\+0\);$} 1 original } }
f64 = sqrtf64(2f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_sqrt \(2\.0e\+0\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_sqrt.? \(.*2\.0e\+0\);$} 1 original } }
f32 = sinf32(39f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_sinf \(3\.9e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_sin. \(.*3\.9e\+1\);$} 1 original } }
f64 = sinf64(40f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_sin \(4\.0e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_sin.? \(.*4\.0e\+1\);$} 1 original } }
f32 = cosf32(5f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_cosf \(5\.0e\+0\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_cos. \(.*5\.0e\+0\);$} 1 original } }
f64 = cosf64(6f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_cos \(6\.0e\+0\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_cos.? \(.*6\.0e\+0\);$} 1 original } }
f32 = powf32(7f32, 8f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_powf \(7\.0e\+0, 8\.0e\+0\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_pow. \(.*7\.0e\+0, .*8\.0e\+0\);$} 1 original } }
f64 = powf64(9f64, 10f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_pow \(9\.0e\+0, 1\.0e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_pow.? \(.*9\.0e\+0, .*1\.0e\+1\);$} 1 original } }
f32 = expf32(11f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_expf \(1\.1e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_exp. \(.*1\.1e\+1\);$} 1 original } }
f64 = expf64(12f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_exp \(1\.2e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_exp.? \(.*1\.2e\+1\);$} 1 original } }
f32 = exp2f32(13f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_expf \(1\.1e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_exp. \(.*1\.1e\+1\);$} 1 original } }
f64 = exp2f64(14f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_exp \(1\.2e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_exp.? \(.*1\.2e\+1\);$} 1 original } }
f32 = logf32(15f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_logf \(1\.5e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_log. \(.*1\.5e\+1\);$} 1 original } }
f64 = logf64(16f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_log \(1\.6e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_log.? \(.*1\.6e\+1\);$} 1 original } }
f32 = log10f32(17f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_log10f \(1\.7e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_log10. \(.*1\.7e\+1\);$} 1 original } }
f64 = log10f64(18f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_log10 \(1\.8e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_log10.? \(.*1\.8e\+1\);$} 1 original } }
f32 = log2f32(19f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_log2f \(1\.9e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_log2. \(.*1\.9e\+1\);$} 1 original } }
f64 = log2f64(20f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_log2 \(2\.0e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_log2.? \(.*2\.0e\+1\);$} 1 original } }
f32 = fmaf32(21f32, 22f32, 23f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fmaf \(2\.1e\+1, 2\.2e\+1, 2\.3e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fma. \(.*2\.1e\+1, .*2\.2e\+1, .*2\.3e\+1\);$} 1 original } }
f64 = fmaf64(24f64, 25f64, 26f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fma \(2\.4e\+1, 2\.5e\+1, 2\.6e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fma.? \(.*2\.4e\+1, .*2\.5e\+1, .*2\.6e\+1\);$} 1 original } }
f32 = fabsf32(27f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fabsf \(2\.7e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fabs. \(.*2\.7e\+1\);$} 1 original } }
f64 = fabsf64(28f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fabs \(2\.8e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fabs.? \(.*2\.8e\+1\);$} 1 original } }
f32 = minnumf32(29f32, 30f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fminf \(2\.9e\+1, 3\.0e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fmin. \(.*2\.9e\+1, .*3\.0e\+1\);$} 1 original } }
f64 = minnumf64(31f64, 32f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fmin \(3\.1e\+1, 3\.2e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fmin.? \(.*3\.1e\+1, .*3\.2e\+1\);$} 1 original } }
f32 = maxnumf32(33f32, 34f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_fmaxf \(3\.3e\+1, 3\.4e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_fmax. \(.*3\.3e\+1, .*3\.4e\+1\);$} 1 original } }
f64 = maxnumf64(35f64, 36f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_fmax \(3\.5e\+1, 3\.6e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_fmax.? \(.*3\.5e\+1, .*3\.6e\+1\);$} 1 original } }
f32 = copysignf32(37f32, 38f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_copysignf \(3\.7e\+1, 3\.8e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_copysign. \(.*3\.7e\+1, .*3\.8e\+1\);$} 1 original } }
f64 = copysignf64(39f64, 40f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_copysign \(3\.9e\+1, 4\.0e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_copysign.? \(.*3\.9e\+1, .*4\.0e\+1\);$} 1 original } }
f32 = floorf32(41f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_floorf \(4\.1e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_floor. \(.*4\.1e\+1\);$} 1 original } }
f64 = floorf64(42f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_floor \(4\.2e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_floor.? \(.*4\.2e\+1\);$} 1 original } }
f32 = ceilf32(43f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_ceilf \(4\.3e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_ceil. \(.*4\.3e\+1\);$} 1 original } }
f64 = ceilf64(44f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_ceil \(4\.4e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_ceil.? \(.*4\.4e\+1\);$} 1 original } }
f32 = truncf32(45f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_truncf \(4\.5e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_trunc. \(.*4\.5e\+1\);$} 1 original } }
f64 = truncf64(46f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_trunc \(4\.6e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_trunc.? \(.*4\.6e\+1\);$} 1 original } }
f32 = rintf32(47f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_rintf \(4\.7e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_rint. \(.*4\.7e\+1\);$} 1 original } }
f64 = rintf64(48f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_rint \(4\.8e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_rint.? \(.*4\.8e\+1\);$} 1 original } }
f32 = nearbyintf32(49f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_nearbyintf \(4\.9e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_nearbyint. \(.*4\.9e\+1\);$} 1 original } }
f64 = nearbyintf64(50f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_nearbyint \(5\.0e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_nearbyint.? \(.*5\.0e\+1\);$} 1 original } }
f32 = roundf32(51f32);
- // { dg-final { scan-tree-dump-times {(?n)f32 = __builtin_roundf \(5\.1e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f32 .* __builtin_round. \(.*5\.1e\+1\);$} 1 original } }
f64 = roundf64(52f64);
- // { dg-final { scan-tree-dump-times {(?n)f64 = __builtin_round \(5\.2e\+1\);$} 1 original } }
+ // { dg-final { scan-tree-dump-times {(?n)f64 .* __builtin_round.? \(.*5\.2e\+1\);$} 1 original } }
}
unsafe { foo() };
diff --git a/gcc/testsuite/rust/execute/torture/atomic_load.rs b/gcc/testsuite/rust/execute/torture/atomic_load.rs
index b66c4641424..11da8484494 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<T: Copy>(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 dcbb2a90f19..1b46678ba38 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<T: Copy>(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;
diff --git a/gcc/testsuite/rust/execute/torture/builtin_abort.rs b/gcc/testsuite/rust/execute/torture/builtin_abort.rs
new file mode 100644
index 00000000000..9f2d8c2d9f3
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/builtin_abort.rs
@@ -0,0 +1,14 @@
+// { dg-shouldfail "abort should stop the program" }
+#![feature(rustc_attrs)]
+#![feature(intrinsics)]
+
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn abort() -> !;
+ }
+}
+
+pub fn main () -> i32 {
+ abort();
+ 0
+}
--
2.42.1
More information about the Gcc-rust
mailing list