From a08ac0c27aed0c6d390d03656b708eb71381a5e9 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 9 Mar 2022 14:37:47 +0000 Subject: [PATCH 1/6] Add support for the rust offset intrinsic This patch adds the initial support for generic intrinsics these are do not map directly to GCC builtins and need to be substited with their specificed types. This patch allows for custom implementation body for these functions by specifying handler functions which will generate the applicable intrinsic when asked for. Addresses #658 --- gcc/rust/backend/rust-compile-fnparam.h | 8 ++ gcc/rust/backend/rust-compile-intrinsic.cc | 124 +++++++++++++++++- gcc/rust/backend/rust-compile-resolve-path.cc | 8 ++ gcc/rust/backend/rust-tree.cc | 18 +++ gcc/rust/backend/rust-tree.h | 6 + gcc/rust/rust-backend.h | 4 - gcc/rust/rust-gcc.cc | 23 ---- 7 files changed, 163 insertions(+), 28 deletions(-) diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h index 74df725f8d75..5e3cfaa2f3d4 100644 --- a/gcc/rust/backend/rust-compile-fnparam.h +++ b/gcc/rust/backend/rust-compile-fnparam.h @@ -36,6 +36,14 @@ class CompileFnParam : public HIRCompileBase, public HIR::HIRPatternVisitor return compiler.compiled_param; } + static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern *param, + tree decl_type, Location locus) + { + CompileFnParam compiler (ctx, fndecl, decl_type, locus); + param->accept_vis (compiler); + return compiler.compiled_param; + } + void visit (HIR::IdentifierPattern &pattern) override { if (!pattern.is_mut ()) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 8c5b073488d5..177c14e8d282 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -15,10 +15,20 @@ // . #include "rust-compile-intrinsic.h" +#include "rust-compile-type.h" +#include "rust-compile-fnparam.h" +#include "rust-tree.h" namespace Rust { namespace Compile { +static tree +offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype); + +static const std::map> + generic_intrinsics = {{"offset", &offset_intrinsic_handler}}; + Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} tree @@ -82,11 +92,123 @@ Intrinsics::compile (TyTy::FnType *fntype) if (builtin != nullptr) return builtin; + // is it an generic builtin? + auto it = generic_intrinsics.find (fntype->get_identifier ()); + if (it != generic_intrinsics.end ()) + return it->second (ctx, fntype); + Location locus = ctx->get_mappings ()->lookup_location (fntype->get_ref ()); - rust_error_at (locus, "unknown builtin"); + rust_error_at (locus, "unknown builtin intrinsic: %s", + fntype->get_identifier ().c_str ()); return error_mark_node; } +static tree +offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty) +{ + rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fntype = static_cast (fntype_tyty); + const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path; + + // items can be forward compiled which means we may not need to invoke this + // code. We might also have already compiled this generic function as well. + tree lookup = NULL_TREE; + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, + fntype->get_id (), fntype)) + { + // has this been added to the list then it must be finished + if (ctx->function_completed (lookup)) + { + tree dummy = NULL_TREE; + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) + { + ctx->insert_function_decl (fntype, lookup); + } + return lookup; + } + } + + if (fntype->has_subsititions_defined ()) + { + // override the Hir Lookups for the substituions in this context + fntype->override_context (); + } + + // offset intrinsic has two params dst pointer and offset isize + if (fntype->get_params ().size () != 2) + { + rust_error_at (fntype->get_ident ().locus, + "invalid number of parameters for offset intrinsic"); + return error_mark_node; + } + + tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype); + std::string ir_symbol_name + = canonical_path.get () + fntype->subst_as_string (); + std::string asm_name = ctx->mangle_item (fntype, canonical_path); + + unsigned int flags = 0; + tree fndecl + = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name, + flags, fntype->get_ident ().locus); + TREE_PUBLIC (fndecl) = 0; + TREE_READONLY (fndecl) = 1; + DECL_ARTIFICIAL (fndecl) = 1; + DECL_EXTERNAL (fndecl) = 0; + DECL_DECLARED_INLINE_P (fndecl) = 1; + + // setup the params + std::vector param_vars; + for (auto &parm : fntype->get_params ()) + { + auto &referenced_param = parm.first; + auto ¶m_tyty = parm.second; + auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty); + + Location param_locus = referenced_param->get_locus (); + Bvariable *compiled_param_var + = CompileFnParam::compile (ctx, fndecl, referenced_param, + compiled_param_type, param_locus); + + param_vars.push_back (compiled_param_var); + } + + auto &dst_param = param_vars.at (0); + auto &size_param = param_vars.at (1); + rust_assert (param_vars.size () == 2); + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + tree enclosing_scope = NULL_TREE; + Location start_location = Location (); + Location end_location = Location (); + + tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, {}, + start_location, end_location); + ctx->push_block (code_block); + + // BUILTIN offset FN BODY BEGIN + tree dst = ctx->get_backend ()->var_expression (dst_param, Location ()); + tree size = ctx->get_backend ()->var_expression (size_param, Location ()); + tree pointer_offset_expr + = pointer_offset_expression (dst, size, BUILTINS_LOCATION); + auto return_statement + = ctx->get_backend ()->return_statement (fndecl, {pointer_offset_expr}, + Location ()); + ctx->add_statement (return_statement); + // BUILTIN offset FN BODY END + + tree bind_tree = ctx->pop_block (); + + gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); + DECL_SAVED_TREE (fndecl) = bind_tree; + + ctx->pop_fn (); + ctx->push_function (fndecl); + + return fndecl; +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc index 09f3860efedb..2ad672d0b4c8 100644 --- a/gcc/rust/backend/rust-compile-resolve-path.cc +++ b/gcc/rust/backend/rust-compile-resolve-path.cc @@ -17,6 +17,7 @@ // . #include "rust-compile-resolve-path.h" +#include "rust-compile-intrinsic.h" #include "rust-compile-item.h" #include "rust-compile-implitem.h" #include "rust-compile-expr.h" @@ -142,6 +143,13 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment, TREE_USED (fn) = 1; return address_expression (fn, expr_locus); } + else if (fntype->get_abi () == ABI::INTRINSIC) + { + Intrinsics compile (ctx); + fn = compile.compile (fntype); + TREE_USED (fn) = 1; + return address_expression (fn, expr_locus); + } } // let the query system figure it out diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc index 8e39408e2afb..6f7614d04133 100644 --- a/gcc/rust/backend/rust-tree.cc +++ b/gcc/rust/backend/rust-tree.cc @@ -17,6 +17,7 @@ // . #include "rust-tree.h" +#include "fold-const.h" #include "stringpool.h" #include "attribs.h" #include "escaped_string.h" @@ -656,4 +657,21 @@ get_fndecl_from_callee (tree fn) return NULL_TREE; } +tree +pointer_offset_expression (tree base_tree, tree index_tree, location_t location) +{ + tree element_type_tree = TREE_TYPE (TREE_TYPE (base_tree)); + if (base_tree == error_mark_node || TREE_TYPE (base_tree) == error_mark_node + || index_tree == error_mark_node || element_type_tree == error_mark_node) + return error_mark_node; + + tree element_size = TYPE_SIZE_UNIT (element_type_tree); + index_tree = fold_convert_loc (location, sizetype, index_tree); + tree offset + = fold_build2_loc (location, MULT_EXPR, sizetype, index_tree, element_size); + + return fold_build2_loc (location, POINTER_PLUS_EXPR, TREE_TYPE (base_tree), + base_tree, offset); +} + } // namespace Rust diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h index c21bf4b0509e..c50e090f9391 100644 --- a/gcc/rust/backend/rust-tree.h +++ b/gcc/rust/backend/rust-tree.h @@ -177,6 +177,12 @@ expr_loc_or_input_loc (const_tree t); extern tree get_fndecl_from_callee (tree fn); +// FIXME some helpers from HIRCompileBase could probably be moved here over time + +// Return an expression for the address of BASE[INDEX], used in offset intrinsic +extern tree +pointer_offset_expression (tree base_tree, tree index_tree, location_t locus); + } // namespace Rust #endif // RUST_TREE diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index fca09b2bd68d..b942ed339cc8 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -275,10 +275,6 @@ class Backend const std::vector &vals, Location) = 0; - // Return an expression for the address of BASE[INDEX]. - // BASE has a pointer type. This is used for slice indexing. - virtual tree pointer_offset_expression (tree base, tree index, Location) = 0; - // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid // fixed-length array, not a slice. virtual tree array_index_expression (tree array, tree index, Location) = 0; diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 70c07c152564..87affcfab98a 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -246,8 +246,6 @@ class Gcc_backend : public Backend tree array_constructor_expression (tree, const std::vector &, const std::vector &, Location); - tree pointer_offset_expression (tree base, tree offset, Location); - tree array_index_expression (tree array, tree index, Location); tree call_expression (tree caller, tree fn, const std::vector &args, @@ -1717,27 +1715,6 @@ Gcc_backend::array_constructor_expression ( return ret; } -// Return an expression for the address of BASE[INDEX]. - -tree -Gcc_backend::pointer_offset_expression (tree base_tree, tree index_tree, - Location location) -{ - tree element_type_tree = TREE_TYPE (TREE_TYPE (base_tree)); - if (base_tree == error_mark_node || TREE_TYPE (base_tree) == error_mark_node - || index_tree == error_mark_node || element_type_tree == error_mark_node) - return error_mark_node; - - tree element_size = TYPE_SIZE_UNIT (element_type_tree); - index_tree - = fold_convert_loc (location.gcc_location (), sizetype, index_tree); - tree offset = fold_build2_loc (location.gcc_location (), MULT_EXPR, sizetype, - index_tree, element_size); - tree ptr = fold_build2_loc (location.gcc_location (), POINTER_PLUS_EXPR, - TREE_TYPE (base_tree), base_tree, offset); - return ptr; -} - // Return an expression representing ARRAY[INDEX] tree From 94990a843b6df9ff6010957d724dbb70bea94ceb Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 9 Mar 2022 15:35:04 +0000 Subject: [PATCH 2/6] Refactor how we define simple intrinsics Intrinsics were hidden behind the GCC abstract. This removes it by keeping all of this logic within rust-intrinsic.cc so that we can make mappings of the rustc name to GCC ones. We have a big comment from the mappings used over to LLVM builtins which we can use to help guide how we do this for GCC. --- gcc/rust/backend/rust-compile-intrinsic.cc | 197 +++++++++++++++------ gcc/rust/rust-backend.h | 6 - gcc/rust/rust-gcc.cc | 80 --------- 3 files changed, 143 insertions(+), 140 deletions(-) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 177c14e8d282..c57943cc379f 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -15,6 +15,7 @@ // . #include "rust-compile-intrinsic.h" +#include "langhooks.h" #include "rust-compile-type.h" #include "rust-compile-fnparam.h" #include "rust-tree.h" @@ -22,6 +23,144 @@ namespace Rust { namespace Compile { +// https://github.com/rust-lang/rust/blob/master/library/core/src/intrinsics.rs +// https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs +// https://github.com/Rust-GCC/gccrs/issues/658 +// +// let llvm_name = match name { +// sym::sqrtf32 => "llvm.sqrt.f32", +// sym::sqrtf64 => "llvm.sqrt.f64", +// sym::powif32 => "llvm.powi.f32", +// sym::powif64 => "llvm.powi.f64", +// sym::sinf32 => "llvm.sin.f32", +// sym::sinf64 => "llvm.sin.f64", +// sym::cosf32 => "llvm.cos.f32", +// sym::cosf64 => "llvm.cos.f64", +// sym::powf32 => "llvm.pow.f32", +// sym::powf64 => "llvm.pow.f64", +// sym::expf32 => "llvm.exp.f32", +// sym::expf64 => "llvm.exp.f64", +// sym::exp2f32 => "llvm.exp2.f32", +// sym::exp2f64 => "llvm.exp2.f64", +// sym::logf32 => "llvm.log.f32", +// sym::logf64 => "llvm.log.f64", +// sym::log10f32 => "llvm.log10.f32", +// sym::log10f64 => "llvm.log10.f64", +// sym::log2f32 => "llvm.log2.f32", +// sym::log2f64 => "llvm.log2.f64", +// sym::fmaf32 => "llvm.fma.f32", +// sym::fmaf64 => "llvm.fma.f64", +// sym::fabsf32 => "llvm.fabs.f32", +// sym::fabsf64 => "llvm.fabs.f64", +// sym::minnumf32 => "llvm.minnum.f32", +// sym::minnumf64 => "llvm.minnum.f64", +// sym::maxnumf32 => "llvm.maxnum.f32", +// sym::maxnumf64 => "llvm.maxnum.f64", +// sym::copysignf32 => "llvm.copysign.f32", +// sym::copysignf64 => "llvm.copysign.f64", +// sym::floorf32 => "llvm.floor.f32", +// sym::floorf64 => "llvm.floor.f64", +// sym::ceilf32 => "llvm.ceil.f32", +// sym::ceilf64 => "llvm.ceil.f64", +// sym::truncf32 => "llvm.trunc.f32", +// sym::truncf64 => "llvm.trunc.f64", +// sym::rintf32 => "llvm.rint.f32", +// sym::rintf64 => "llvm.rint.f64", +// sym::nearbyintf32 => "llvm.nearbyint.f32", +// sym::nearbyintf64 => "llvm.nearbyint.f64", +// sym::roundf32 => "llvm.round.f32", +// sym::roundf64 => "llvm.round.f64", +// _ => return None, +// }; +// Some(cx.get_intrinsic(&llvm_name)) +class SimpleIntrinsics +{ +public: + static SimpleIntrinsics &get () + { + static SimpleIntrinsics instance; + return instance; + } + + bool lookup_simple_builtin (const std::string &name, tree *builtin) + { + auto it = rust_intrinsic_to_gcc_builtin.find (name); + if (it == rust_intrinsic_to_gcc_builtin.end ()) + return false; + + return lookup_gcc_builtin (it->second, builtin); + } + +private: + static const int builtin_const = 1 << 0; + static const int builtin_noreturn = 1 << 1; + static const int builtin_novops = 1 << 2; + + SimpleIntrinsics () { setup (); } + + void setup () + { + tree math_function_type_f32 + = build_function_type_list (float_type_node, float_type_node, NULL_TREE); + + define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf", + math_function_type_f32, builtin_const); + + define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", + math_function_type_f32, builtin_const); + } + + // 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) + { + tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL, + libname, NULL_TREE); + if ((flags & builtin_const) != 0) + TREE_READONLY (decl) = 1; + if ((flags & builtin_noreturn) != 0) + TREE_THIS_VOLATILE (decl) = 1; + if ((flags & builtin_novops) != 0) + DECL_IS_NOVOPS (decl) = 1; + 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); + if ((flags & builtin_const) != 0) + TREE_READONLY (decl) = 1; + if ((flags & builtin_noreturn) != 0) + TREE_THIS_VOLATILE (decl) = 1; + if ((flags & builtin_novops) != 0) + DECL_IS_NOVOPS (decl) = 1; + this->builtin_functions_[libname] = decl; + } + + rust_intrinsic_to_gcc_builtin[rust_name] = name; + } + + bool lookup_gcc_builtin (const std::string &name, tree *builtin) + { + auto it = builtin_functions_.find (name); + if (it == builtin_functions_.end ()) + return false; + + *builtin = it->second; + return true; + } + + // A mapping of the GCC built-ins exposed to GCC Rust. + std::map builtin_functions_; + std::map rust_intrinsic_to_gcc_builtin; +}; + static tree offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype); @@ -36,60 +175,10 @@ Intrinsics::compile (TyTy::FnType *fntype) { rust_assert (fntype->get_abi () == ABI::INTRINSIC); - // https://github.com/rust-lang/rust/blob/master/library/core/src/intrinsics.rs - // https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/intrinsic.rs - // https://github.com/Rust-GCC/gccrs/issues/658 - - // let llvm_name = match name { - // sym::sqrtf32 => "llvm.sqrt.f32", - // sym::sqrtf64 => "llvm.sqrt.f64", - // sym::powif32 => "llvm.powi.f32", - // sym::powif64 => "llvm.powi.f64", - // sym::sinf32 => "llvm.sin.f32", - // sym::sinf64 => "llvm.sin.f64", - // sym::cosf32 => "llvm.cos.f32", - // sym::cosf64 => "llvm.cos.f64", - // sym::powf32 => "llvm.pow.f32", - // sym::powf64 => "llvm.pow.f64", - // sym::expf32 => "llvm.exp.f32", - // sym::expf64 => "llvm.exp.f64", - // sym::exp2f32 => "llvm.exp2.f32", - // sym::exp2f64 => "llvm.exp2.f64", - // sym::logf32 => "llvm.log.f32", - // sym::logf64 => "llvm.log.f64", - // sym::log10f32 => "llvm.log10.f32", - // sym::log10f64 => "llvm.log10.f64", - // sym::log2f32 => "llvm.log2.f32", - // sym::log2f64 => "llvm.log2.f64", - // sym::fmaf32 => "llvm.fma.f32", - // sym::fmaf64 => "llvm.fma.f64", - // sym::fabsf32 => "llvm.fabs.f32", - // sym::fabsf64 => "llvm.fabs.f64", - // sym::minnumf32 => "llvm.minnum.f32", - // sym::minnumf64 => "llvm.minnum.f64", - // sym::maxnumf32 => "llvm.maxnum.f32", - // sym::maxnumf64 => "llvm.maxnum.f64", - // sym::copysignf32 => "llvm.copysign.f32", - // sym::copysignf64 => "llvm.copysign.f64", - // sym::floorf32 => "llvm.floor.f32", - // sym::floorf64 => "llvm.floor.f64", - // sym::ceilf32 => "llvm.ceil.f32", - // sym::ceilf64 => "llvm.ceil.f64", - // sym::truncf32 => "llvm.trunc.f32", - // sym::truncf64 => "llvm.trunc.f64", - // sym::rintf32 => "llvm.rint.f32", - // sym::rintf64 => "llvm.rint.f64", - // sym::nearbyintf32 => "llvm.nearbyint.f32", - // sym::nearbyintf64 => "llvm.nearbyint.f64", - // sym::roundf32 => "llvm.round.f32", - // sym::roundf64 => "llvm.round.f64", - // _ => return None, - // }; - // Some(cx.get_intrinsic(&llvm_name)) - - tree builtin = ctx->get_backend ()->lookup_builtin_by_rust_name ( - fntype->get_identifier ()); - if (builtin != nullptr) + tree builtin = error_mark_node; + SimpleIntrinsics &simple_intrinsics = SimpleIntrinsics::get (); + if (simple_intrinsics.lookup_simple_builtin (fntype->get_identifier (), + &builtin)) return builtin; // is it an generic builtin? diff --git a/gcc/rust/rust-backend.h b/gcc/rust/rust-backend.h index b942ed339cc8..6bfebe3d5c2f 100644 --- a/gcc/rust/rust-backend.h +++ b/gcc/rust/rust-backend.h @@ -504,12 +504,6 @@ class Backend const std::vector ¶m_vars) = 0; - // Look up a named built-in function in the current backend implementation. - // Returns NULL if no built-in function by that name exists. - virtual tree lookup_gcc_builtin (const std::string &) = 0; - - virtual tree lookup_builtin_by_rust_name (const std::string &) = 0; - // Utility. // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index 87affcfab98a..6ea9ef3e44e0 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -344,19 +344,6 @@ class Gcc_backend : public Backend tree non_zero_size_type (tree); tree convert_tree (tree, tree, Location); - -private: - static const int builtin_const = 1 << 0; - static const int builtin_noreturn = 1 << 1; - static const int builtin_novops = 1 << 2; - - void define_builtin (const std::string rust_name, built_in_function bcode, - const char *name, const char *libname, tree fntype, - int flags); - - // A mapping of the GCC built-ins exposed to GCCRust. - std::map builtin_functions_; - std::map rust_intrinsic_to_gcc_builtin; }; // A helper function to create a GCC identifier from a C++ string. @@ -473,14 +460,6 @@ Gcc_backend::Gcc_backend () // builtin_const); // We provide some functions for the math library. - tree math_function_type_f32 - = build_function_type_list (float_type_node, float_type_node, NULL_TREE); - - this->define_builtin ("sinf32", BUILT_IN_SINF, "__builtin_sinf", "sinf", - math_function_type_f32, builtin_const); - - this->define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", - math_function_type_f32, builtin_const); // We use __builtin_return_address in the thunk we build for // functions which call recover, and for runtime.getcallerpc. @@ -2661,27 +2640,6 @@ Gcc_backend::function_set_parameters ( return true; } -// Look up a named built-in function in the current backend implementation. -// Returns NULL if no built-in function by that name exists. - -tree -Gcc_backend::lookup_gcc_builtin (const std::string &name) -{ - if (this->builtin_functions_.count (name) != 0) - return this->builtin_functions_[name]; - return NULL; -} - -tree -Gcc_backend::lookup_builtin_by_rust_name (const std::string &name) -{ - auto it = rust_intrinsic_to_gcc_builtin.find (name); - if (it == rust_intrinsic_to_gcc_builtin.end ()) - return NULL; - - return lookup_gcc_builtin (it->second); -} - // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, // FUNCTION_DECLS, and VARIABLE_DECLS declared globally, as well as // emit early debugging information. @@ -2763,44 +2721,6 @@ Gcc_backend::write_export_data (const char *bytes, unsigned int size) rust_write_export_data (bytes, size); } -// 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 -Gcc_backend::define_builtin (const std::string rust_name, - built_in_function bcode, const char *name, - const char *libname, tree fntype, int flags) -{ - tree decl = add_builtin_function (name, fntype, bcode, BUILT_IN_NORMAL, - libname, NULL_TREE); - if ((flags & builtin_const) != 0) - TREE_READONLY (decl) = 1; - if ((flags & builtin_noreturn) != 0) - TREE_THIS_VOLATILE (decl) = 1; - if ((flags & builtin_novops) != 0) - DECL_IS_NOVOPS (decl) = 1; - 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); - if ((flags & builtin_const) != 0) - TREE_READONLY (decl) = 1; - if ((flags & builtin_noreturn) != 0) - TREE_THIS_VOLATILE (decl) = 1; - if ((flags & builtin_novops) != 0) - DECL_IS_NOVOPS (decl) = 1; - this->builtin_functions_[libname] = decl; - } - - rust_intrinsic_to_gcc_builtin[rust_name] = name; -} - // Return the backend generator. Backend * From 178cabde9f99023559922318ad54ad47c1fce803 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 9 Mar 2022 16:09:09 +0000 Subject: [PATCH 3/6] Add missing builtin mappings for never type --- gcc/rust/hir/rust-ast-lower-type.h | 13 +++++++++++++ gcc/rust/resolve/rust-ast-resolve-type.cc | 6 ++++++ gcc/rust/resolve/rust-ast-resolve-type.h | 2 ++ gcc/rust/resolve/rust-ast-resolve.cc | 2 ++ gcc/rust/typecheck/rust-hir-type-check-type.h | 9 +++++++++ gcc/testsuite/rust/compile/never_type_err2.rs | 4 ---- 6 files changed, 32 insertions(+), 4 deletions(-) delete mode 100644 gcc/testsuite/rust/compile/never_type_err2.rs diff --git a/gcc/rust/hir/rust-ast-lower-type.h b/gcc/rust/hir/rust-ast-lower-type.h index 3d1690f8bb42..a9b4dd8ab038 100644 --- a/gcc/rust/hir/rust-ast-lower-type.h +++ b/gcc/rust/hir/rust-ast-lower-type.h @@ -291,6 +291,19 @@ class ASTLoweringType : public ASTLoweringBase translated); } + void visit (AST::NeverType &type) override + { + auto crate_num = mappings->get_current_crate (); + Analysis::NodeMapping mapping (crate_num, type.get_node_id (), + mappings->get_next_hir_id (crate_num), + mappings->get_next_localdef_id (crate_num)); + + translated = new HIR::NeverType (mapping, type.get_locus ()); + + mappings->insert_hir_type (mapping.get_crate_num (), mapping.get_hirid (), + translated); + } + void visit (AST::TraitObjectTypeOneBound &type) override; void visit (AST::TraitObjectType &type) override; diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 252d1cae8aa9..fd5c056725a6 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -197,6 +197,12 @@ ResolveType::visit (AST::InferredType &type) ok = true; } +void +ResolveType::visit (AST::NeverType &type) +{ + ok = true; +} + void ResolveType::visit (AST::SliceType &type) { diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index d835e00c77c3..e5344235879e 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -386,6 +386,8 @@ class ResolveType : public ResolverBase void visit (AST::InferredType &type) override; + void visit (AST::NeverType &type) override; + void visit (AST::RawPointerType &type) override; void visit (AST::TraitObjectTypeOneBound &type) override; diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc index 094fa4a2946b..86c159da9531 100644 --- a/gcc/rust/resolve/rust-ast-resolve.cc +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -187,6 +187,7 @@ Resolver::generate_builtins () auto isize = new TyTy::ISizeType (mappings->get_next_hir_id ()); auto char_tyty = new TyTy::CharType (mappings->get_next_hir_id ()); auto str = new TyTy::StrType (mappings->get_next_hir_id ()); + auto never = new TyTy::NeverType (mappings->get_next_hir_id ()); MKBUILTIN_TYPE ("u8", builtins, u8); MKBUILTIN_TYPE ("u16", builtins, u16); @@ -205,6 +206,7 @@ Resolver::generate_builtins () MKBUILTIN_TYPE ("isize", builtins, isize); MKBUILTIN_TYPE ("char", builtins, char_tyty); MKBUILTIN_TYPE ("str", builtins, str); + MKBUILTIN_TYPE ("!", builtins, never); // unit type () TyTy::TupleType *unit_tyty diff --git a/gcc/rust/typecheck/rust-hir-type-check-type.h b/gcc/rust/typecheck/rust-hir-type-check-type.h index 400328c3fb43..74298e422e8a 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-type.h +++ b/gcc/rust/typecheck/rust-hir-type-check-type.h @@ -145,6 +145,15 @@ class TypeCheckType : public TypeCheckBase type.get_locus ()); } + void visit (HIR::NeverType &type) override + { + TyTy::BaseType *lookup = nullptr; + bool ok = context->lookup_builtin ("!", &lookup); + rust_assert (ok); + + translated = lookup->clone (); + } + void visit (HIR::TraitObjectType &type) override; private: diff --git a/gcc/testsuite/rust/compile/never_type_err2.rs b/gcc/testsuite/rust/compile/never_type_err2.rs deleted file mode 100644 index c94cb828071f..000000000000 --- a/gcc/testsuite/rust/compile/never_type_err2.rs +++ /dev/null @@ -1,4 +0,0 @@ -// FIXME: Unimplemented features -fn foo() -> ! { // { dg-error "unresolved type" } - let a: !; // { dg-error "unresolved type" } -} From 9e23c29cd0f95f4e6102f770965079546aebd96c Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 9 Mar 2022 16:15:19 +0000 Subject: [PATCH 4/6] Add builtin unreachable intrinsic mapping This demonstrates how we can add in the simple intrinsics in a single patch. Addresses #658 --- gcc/rust/backend/rust-compile-intrinsic.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index c57943cc379f..be4f835b0501 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -108,6 +108,11 @@ class SimpleIntrinsics define_builtin ("sqrtf32", BUILT_IN_SQRTF, "__builtin_sqrtf", "sqrtf", math_function_type_f32, builtin_const); + + define_builtin ("unreachable", BUILT_IN_UNREACHABLE, + "__builtin_unreachable", NULL, + build_function_type (void_type_node, void_list_node), + builtin_const | builtin_noreturn); } // Define a builtin function. BCODE is the builtin function code From 796c978c4894d6510116180522315c97989c4ccf Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Thu, 10 Mar 2022 11:46:24 +0000 Subject: [PATCH 5/6] Add builtin abort intrinsic Addresses #658 --- gcc/rust/backend/rust-compile-intrinsic.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index be4f835b0501..c9098884f52c 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -113,6 +113,10 @@ class SimpleIntrinsics "__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 a builtin function. BCODE is the builtin function code From f05744511998309f6694ad18abcc22fbac025dc2 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Thu, 10 Mar 2022 11:47:28 +0000 Subject: [PATCH 6/6] Add size_of intrinsic This is another type of intrisic since the function contains no parameters but the argument for the size_of is the generic parameter T. Which uses TYPE_SIZE_UNIT to get the type size in bytes. GCC will optimize the function call away when you turn optimizations on. Addresses #658 --- gcc/rust/backend/rust-compile-intrinsic.cc | 94 +++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index c9098884f52c..3665f5d35f79 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -172,10 +172,13 @@ class SimpleIntrinsics static tree offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype); +static tree +sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype); static const std::map> - generic_intrinsics = {{"offset", &offset_intrinsic_handler}}; + generic_intrinsics = {{"offset", &offset_intrinsic_handler}, + {"size_of", &sizeof_intrinsic_handler}}; Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {} @@ -308,5 +311,94 @@ offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty) return fndecl; } +static tree +sizeof_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty) +{ + rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF); + TyTy::FnType *fntype = static_cast (fntype_tyty); + const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path; + + // items can be forward compiled which means we may not need to invoke this + // code. We might also have already compiled this generic function as well. + tree lookup = NULL_TREE; + if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup, + fntype->get_id (), fntype)) + { + // has this been added to the list then it must be finished + if (ctx->function_completed (lookup)) + { + tree dummy = NULL_TREE; + if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy)) + { + ctx->insert_function_decl (fntype, lookup); + } + return lookup; + } + } + + if (fntype->has_subsititions_defined ()) + { + // override the Hir Lookups for the substituions in this context + fntype->override_context (); + } + + // offset intrinsic has two params dst pointer and offset isize + if (fntype->get_params ().size () != 0) + { + rust_error_at (fntype->get_ident ().locus, + "invalid number of parameters for size of intrinsic"); + return error_mark_node; + } + + // get the template parameter type tree fn size_of(); + rust_assert (fntype->get_num_substitutions () == 1); + auto ¶m_mapping = fntype->get_substs ().at (0); + const TyTy::ParamType *param_tyty = param_mapping.get_param_ty (); + TyTy::BaseType *resolved_tyty = param_tyty->resolve (); + tree template_parameter_type + = TyTyResolveCompile::compile (ctx, resolved_tyty); + + // build the intrinsic function + tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype); + std::string ir_symbol_name + = canonical_path.get () + fntype->subst_as_string (); + std::string asm_name = ctx->mangle_item (fntype, canonical_path); + + unsigned int flags = 0; + tree fndecl + = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name, + flags, fntype->get_ident ().locus); + TREE_PUBLIC (fndecl) = 0; + TREE_READONLY (fndecl) = 1; + DECL_ARTIFICIAL (fndecl) = 1; + DECL_EXTERNAL (fndecl) = 0; + DECL_DECLARED_INLINE_P (fndecl) = 1; + + tree enclosing_scope = NULL_TREE; + Location start_location = Location (); + Location end_location = Location (); + + tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, {}, + start_location, end_location); + ctx->push_block (code_block); + + // BUILTIN size_of FN BODY BEGIN + tree size_expr = TYPE_SIZE_UNIT (template_parameter_type); + auto return_statement + = ctx->get_backend ()->return_statement (fndecl, {size_expr}, Location ()); + ctx->add_statement (return_statement); + // BUILTIN size_of FN BODY END + + tree bind_tree = ctx->pop_block (); + + gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); + DECL_SAVED_TREE (fndecl) = bind_tree; + + ctx->pop_fn (); + ctx->push_function (fndecl); + + return fndecl; +} + } // namespace Compile } // namespace Rust