Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
builtins: Cleanup initialization of builtins
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.
CohenArthur authored and dkm committed Nov 11, 2023
1 parent 9864d7f commit 899eb62
Showing 7 changed files with 392 additions and 269 deletions.
478 changes: 239 additions & 239 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
@@ -21,6 +21,7 @@
#include "rust-tree.h"
#include "langhooks.h"
#include "tree.h"
#include "selftest.h"

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

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

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

#include "builtin-types.def"

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

BT_LAST,
};

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

#include "builtin-attrs.def"

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

ATTR_LAST,
};

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

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

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

void register_rust_mappings ();

BuiltinsContext ();

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

void setup ();

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

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

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

47 changes: 37 additions & 10 deletions gcc/rust/backend/rust-compile-intrinsic.cc
Original file line number Diff line number Diff line change
@@ -29,6 +29,8 @@
#include "print-tree.h"
#include "fold-const.h"
#include "langhooks.h"
#include "rust-gcc.h"
#include "rust-constexpr.h"

#include "print-tree.h"

@@ -250,6 +252,7 @@ Intrinsics::compile (TyTy::FnType *fntype)

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

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

@@ -749,8 +752,7 @@ copy_handler_inner (Context *ctx, TyTy::FnType *fntype, bool overlaps)
= build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count);

tree memcpy_raw = nullptr;
BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "memmove"
: "memcpy",
BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "__builtin_memmove" : "__builtin_memcpy",
&memcpy_raw);
rust_assert (memcpy_raw);
auto memcpy = build_fold_addr_expr_loc (UNKNOWN_LOCATION, memcpy_raw);
@@ -796,19 +798,36 @@ prefetch_data_handler (Context *ctx, TyTy::FnType *fntype, Prefetch kind)

enter_intrinsic_block (ctx, fndecl);

auto addr = Backend::var_expression (args[0], UNDEF_LOCATION);
auto locality = Backend::var_expression (args[1], UNDEF_LOCATION);
auto rw_flag = make_unsigned_long_tree (kind == Prefetch::Write ? 1 : 0);
auto addr = ctx->get_backend ()->var_expression (args[0], Location ());

// The core library technically allows you to pass any i32 value as a
// locality, but LLVM will then complain if the value cannot be constant
// evaluated. For now, we ignore the locality argument and instead always
// pass `3` (the most restrictive value). This allows us to still have
// prefetch behavior, just not as granular as expected. In future Rust
// versions, we hope that prefetch intrinsics will be split up according to
// locality, similarly to atomic intrinsics.
// The solution is to try and perform constant folding for the locality
// argument, or instead of creating a new function definition, modify the call
// site directly This has the bad side-effect of creating warnings about
// `unused name - locality`, which we hack away here:
// TODO: Take care of handling locality properly
ctx->get_backend ()->var_expression (args[1], Location ());

auto rw_flag = make_unsigned_long_tree (ctx, kind == Prefetch::Write ? 1 : 0);

auto prefetch_raw = NULL_TREE;
auto ok
= BuiltinsContext::get ().lookup_simple_builtin ("prefetch", &prefetch_raw);
auto ok = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_prefetch",
&prefetch_raw);
rust_assert (ok);
auto prefetch = build_fold_addr_expr_loc (UNKNOWN_LOCATION, prefetch_raw);

auto prefetch_call
= Backend::call_expression (prefetch, {addr, rw_flag, locality}, nullptr,
UNDEF_LOCATION);
= ctx->get_backend ()->call_expression (prefetch,
{addr, rw_flag,
// locality arg
make_unsigned_long_tree (ctx, 3)},
nullptr, Location ());

TREE_READONLY (prefetch_call) = 0;
TREE_SIDE_EFFECTS (prefetch_call) = 1;
@@ -833,7 +852,7 @@ build_atomic_builtin_name (const std::string &prefix, location_t locus,
// TODO: Can we maybe get the generic version (atomic_store_n) to work... This
// would be so much better

std::string result = prefix;
std::string result = "__" + prefix; // + "n";

auto type_name = operand_type->get_name ();
if (type_name == "usize" || type_name == "isize")
@@ -843,6 +862,13 @@ build_atomic_builtin_name (const std::string &prefix, location_t locus,
return "";
}

if (type_name.at (0) == 'i')
{
rust_sorry_at (locus, "atomics are not yet supported for signed "
"integer types (i8, i16, i32, i64, i128)");
return "";
}

auto type_size_str = allowed_types.find (type_name);

if (!check_for_basic_integer_type ("atomic", locus, operand_type))
@@ -970,6 +996,7 @@ atomic_load_handler_inner (Context *ctx, TyTy::FnType *fntype, int ordering)
TREE_SIDE_EFFECTS (load_call) = 1;

ctx->add_statement (return_statement);

finalize_intrinsic_block (ctx, fndecl);

return fndecl;
8 changes: 4 additions & 4 deletions gcc/rust/rust-gcc.cc
Original file line number Diff line number Diff line change
@@ -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);
2 changes: 1 addition & 1 deletion gcc/testsuite/rust/compile/torture/intrinsics-4.rs
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ extern "rust-intrinsic" {
}

fn main() {
let mut dst = 15;
let mut dst = 15u32;
let new_value = 14;

unsafe {
4 changes: 2 additions & 2 deletions gcc/testsuite/rust/execute/torture/atomic_load.rs
Original file line number Diff line number Diff line change
@@ -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;
4 changes: 2 additions & 2 deletions gcc/testsuite/rust/execute/torture/atomic_store.rs
Original file line number Diff line number Diff line change
@@ -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;

0 comments on commit 899eb62

Please sign in to comment.