[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, &param_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