Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respin the builtin PR #2693

Merged
merged 1 commit into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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