Skip to content

Commit

Permalink
gccrs: refactor builtins initialization and attributes
Browse files Browse the repository at this point in the history
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 <[email protected]>
Co-authored-by: Arthur Cohen <[email protected]>
  • Loading branch information
CohenArthur committed Dec 18, 2023
1 parent 6c80746 commit f7127fc
Show file tree
Hide file tree
Showing 14 changed files with 899 additions and 340 deletions.
1 change: 1 addition & 0 deletions gcc/rust/Make-lang.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
524 changes: 281 additions & 243 deletions gcc/rust/backend/rust-builtins.cc

Large diffs are not rendered by default.

118 changes: 107 additions & 11 deletions gcc/rust/backend/rust-builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "rust-tree.h"
#include "langhooks.h"
#include "tree.h"
#include "selftest.h"

namespace Rust {
namespace Compile {
Expand Down Expand Up @@ -75,6 +76,7 @@ namespace Compile {
// _ => return None,
// };
// Some(cx.get_intrinsic(&llvm_name))

class BuiltinsContext
{
public:
Expand All @@ -83,6 +85,110 @@ class BuiltinsContext
bool lookup_simple_builtin (const std::string &name, tree *builtin);

private:
enum Type
{
#define DEF_PRIMITIVE_TYPE(NAME, V) NAME,
#define DEF_FUNCTION_TYPE_0(NAME, R) NAME,
#define DEF_FUNCTION_TYPE_1(NAME, R, A1) NAME,
#define DEF_FUNCTION_TYPE_2(NAME, R, A1, A2) NAME,
#define DEF_FUNCTION_TYPE_3(NAME, R, A1, A2, A3) NAME,
#define DEF_FUNCTION_TYPE_4(NAME, R, A1, A2, A3, A4) NAME,
#define DEF_FUNCTION_TYPE_5(NAME, R, A1, A2, A3, A4, A5) NAME,
#define DEF_FUNCTION_TYPE_6(NAME, R, A1, A2, A3, A4, A5, A6) NAME,
#define DEF_FUNCTION_TYPE_7(NAME, R, A1, A2, A3, A4, A5, A6, A7) NAME,
#define DEF_FUNCTION_TYPE_8(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8) NAME,
#define DEF_FUNCTION_TYPE_9(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9) NAME,
#define DEF_FUNCTION_TYPE_10(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) \
NAME,
#define DEF_FUNCTION_TYPE_11(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, \
A11) \
NAME,
#define DEF_FUNCTION_TYPE_VAR_0(NAME, R) NAME,
#define DEF_FUNCTION_TYPE_VAR_1(NAME, R, A1) NAME,
#define DEF_FUNCTION_TYPE_VAR_2(NAME, R, A1, A2) NAME,
#define DEF_FUNCTION_TYPE_VAR_3(NAME, R, A1, A2, A3) NAME,
#define DEF_FUNCTION_TYPE_VAR_4(NAME, R, A1, A2, A3, A4) NAME,
#define DEF_FUNCTION_TYPE_VAR_5(NAME, R, A1, A2, A3, A4, A5) NAME,
#define DEF_FUNCTION_TYPE_VAR_6(NAME, R, A1, A2, A3, A4, A5, A6) NAME,
#define DEF_FUNCTION_TYPE_VAR_7(NAME, R, A1, A2, A3, A4, A5, A6, A7) NAME,
#define DEF_FUNCTION_TYPE_VAR_11(NAME, R, A1, A2, A3, A4, A5, A6, A7, A8, A9, \
A10, A11) \
NAME,
#define DEF_POINTER_TYPE(NAME, TYPE) NAME,

#include "builtin-types.def"

#undef DEF_PRIMITIVE_TYPE
#undef DEF_FUNCTION_TYPE_0
#undef DEF_FUNCTION_TYPE_1
#undef DEF_FUNCTION_TYPE_2
#undef DEF_FUNCTION_TYPE_3
#undef DEF_FUNCTION_TYPE_4
#undef DEF_FUNCTION_TYPE_5
#undef DEF_FUNCTION_TYPE_6
#undef DEF_FUNCTION_TYPE_7
#undef DEF_FUNCTION_TYPE_8
#undef DEF_FUNCTION_TYPE_9
#undef DEF_FUNCTION_TYPE_10
#undef DEF_FUNCTION_TYPE_11
#undef DEF_FUNCTION_TYPE_VAR_0
#undef DEF_FUNCTION_TYPE_VAR_1
#undef DEF_FUNCTION_TYPE_VAR_2
#undef DEF_FUNCTION_TYPE_VAR_3
#undef DEF_FUNCTION_TYPE_VAR_4
#undef DEF_FUNCTION_TYPE_VAR_5
#undef DEF_FUNCTION_TYPE_VAR_6
#undef DEF_FUNCTION_TYPE_VAR_7
#undef DEF_FUNCTION_TYPE_VAR_11
#undef DEF_POINTER_TYPE

BT_LAST,
};

enum Attr
{
#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,

#include "builtin-attrs.def"

#undef DEF_ATTR_NULL_TREE
#undef DEF_ATTR_INT
#undef DEF_ATTR_STRING
#undef DEF_ATTR_IDENT
#undef DEF_ATTR_TREE_LIST

ATTR_LAST,
};

/**
* All builtin types, as defined in `builtin-types.def`
*
* This array is filled by the `define_builtin_types` method, during the first
* initialization of the `BuiltinsContext`
*/
tree builtin_types[Type::BT_LAST + 1];

/**
* Similarly, this array contains all builtin attributes, as defined in
* `builtin-attr.def`
*
* This array is filled by the `define_builtin_attributes` method, during the
* first initialization of the `BuiltinsContext`
*/
tree builtin_attributes[Attr::ATTR_LAST + 1];

void define_function_type (Type def, Type ret, bool is_variadic, size_t n,
...);
void define_builtin_types ();
void define_builtin_attributes ();
void define_builtins ();

void register_rust_mappings ();

BuiltinsContext ();

void setup_overflow_fns ();
Expand All @@ -91,20 +197,10 @@ class BuiltinsContext

void setup ();

// Define a builtin function. BCODE is the builtin function code
// defined by builtins.def. NAME is the name of the builtin function.
// LIBNAME is the name of the corresponding library function, and is
// NULL if there isn't one. FNTYPE is the type of the function.
// CONST_P is true if the function has the const attribute.
// NORETURN_P is true if the function has the noreturn attribute.
void define_builtin (const std::string rust_name, built_in_function bcode,
const char *name, const char *libname, tree fntype,
int flags);

bool lookup_gcc_builtin (const std::string &name, tree *builtin);

// A mapping of the GCC built-ins exposed to GCC Rust.
std::map<std::string, tree> builtin_functions_;
std::map<std::string, tree> builtin_functions;
std::map<std::string, std::string> rust_intrinsic_to_gcc_builtin;
};

Expand Down
68 changes: 53 additions & 15 deletions gcc/rust/backend/rust-compile-intrinsic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -243,13 +245,22 @@ 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)
{
rust_assert (fntype->get_abi () == ABI::INTRINSIC);

tree builtin = error_mark_node;
BuiltinsContext &builtin_ctx = BuiltinsContext::get ();

if (builtin_ctx.lookup_simple_builtin (fntype->get_identifier (), &builtin))
return builtin;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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")
Expand All @@ -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))
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
Loading

0 comments on commit f7127fc

Please sign in to comment.