https://gcc.gnu.org/g:0dadfc831ea4d79e3a71359c8bd38c94fe1b9602
commit r17-5439-g0dadfc831ea4d79e3a71359c8bd38c94fe1b9602 Author: Arthur Cohen <[email protected]> Date: Wed Oct 7 00:03:56 2026 +0200 gccrs: builtins: Improve lookup interface gcc/rust/ChangeLog: * backend/rust-builtins.cc (BuiltinsContext::lookup_simple_builtin): Improve API to return an optional<tree> instead. (BuiltinsContext::lookup_gcc_builtin): Likewise. (BuiltinsContext::map_llvm_to_gcc_builtin): Return an expected<T> instead to avoid passing two parameters by pointer. * backend/rust-builtins.h (enum class LlvmBuiltinMappingResult): Rename and improve into... (struct LlvmBuiltinMappingError): ...This. In order to have a better interface, associated functions and an associated `emit` method on the error. * backend/rust-compile-extern.h: Use these new interfaces. * backend/rust-compile-intrinsic.cc (Intrinsics::compile): Likewise. * backend/rust-intrinsic-handlers.cc (expect): Likewise. (op_with_overflow): Likewise. (copy): Likewise. (atomic_store): Likewise. (atomic_load): Likewise. (ctlz_handler): Likewise. (cttz_handler): Likewise. (move_val_init): Likewise. (uninit): Likewise. (prefetch_data): Likewise. (bswap_handler): Likewise. (write_bytes_handler): Likewise. * rust-gcc.cc (fetch_overflow_builtins): Likewise. Diff: --- gcc/rust/backend/rust-builtins.cc | 35 ++++---- gcc/rust/backend/rust-builtins.h | 58 +++++++++++--- gcc/rust/backend/rust-compile-extern.h | 25 ++---- gcc/rust/backend/rust-compile-intrinsic.cc | 6 +- gcc/rust/backend/rust-intrinsic-handlers.cc | 119 +++++++++++++--------------- gcc/rust/rust-gcc.cc | 13 ++- 6 files changed, 137 insertions(+), 119 deletions(-) diff --git a/gcc/rust/backend/rust-builtins.cc b/gcc/rust/backend/rust-builtins.cc index de2d97eb1de5..b7e766a50216 100644 --- a/gcc/rust/backend/rust-builtins.cc +++ b/gcc/rust/backend/rust-builtins.cc @@ -14,6 +14,8 @@ // along with GCC; see the file COPYING3. If not see // <http://www.gnu.org/licenses/>. +#include "expected.h" +#include "optional.h" #include "rust-diagnostics.h" #include "rust-system.h" #include "rust-builtins.h" @@ -36,8 +38,8 @@ BuiltinsContext::get () return instance; } -bool -BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin) +tl::optional<tree> +BuiltinsContext::lookup_simple_builtin (const std::string &name) { auto *to_search = &name; @@ -45,26 +47,20 @@ BuiltinsContext::lookup_simple_builtin (const std::string &name, tree *builtin) if (it != rust_intrinsic_to_gcc_builtin.end ()) to_search = &it->second; - return lookup_gcc_builtin (*to_search, builtin); + return lookup_gcc_builtin (*to_search); } -LlvmBuiltinMappingResult -BuiltinsContext::map_llvm_to_gcc_builtin (const std::string &name, - tree *resolved, - LlvmBuiltinAdapter *adapter) +tl::expected<std::pair<tree, LlvmBuiltinAdapter>, LlvmBuiltinMappingError> +BuiltinsContext::map_llvm_to_gcc_builtin (const std::string &name) { - rust_assert (resolved != nullptr); - auto mapping = llvm_to_gcc_builtin.find (name); if (mapping == llvm_to_gcc_builtin.end ()) - return LlvmBuiltinMappingResult::NOT_MAPPED; + return tl::make_unexpected (LlvmBuiltinMappingError::NotMapped ()); - *resolved = NULL_TREE; - if (!lookup_gcc_builtin (mapping->second.gcc_name, resolved)) - return LlvmBuiltinMappingResult::TARGET_UNAVAILABLE; + if (auto lookup = lookup_gcc_builtin (mapping->second.gcc_name)) + return std::make_pair (*lookup, mapping->second.adapter); - *adapter = mapping->second.adapter; - return LlvmBuiltinMappingResult::RESOLVED; + return tl::make_unexpected (LlvmBuiltinMappingError::TargetUnavailable ()); } BuiltinsContext::BuiltinsContext () : setup_state (SetupState::UNINITIALIZED) {} @@ -457,15 +453,14 @@ BuiltinsContext::setup () setup_state = SetupState::READY; } -bool -BuiltinsContext::lookup_gcc_builtin (const std::string &name, tree *builtin) +tl::optional<tree> +BuiltinsContext::lookup_gcc_builtin (const std::string &name) { auto it = builtin_functions.find (name); if (it == builtin_functions.end ()) - return false; + return tl::nullopt; - *builtin = it->second; - return true; + return it->second; } } // namespace Compile diff --git a/gcc/rust/backend/rust-builtins.h b/gcc/rust/backend/rust-builtins.h index e2c7f9816f9a..bf9c22a86195 100644 --- a/gcc/rust/backend/rust-builtins.h +++ b/gcc/rust/backend/rust-builtins.h @@ -24,6 +24,10 @@ #include "langhooks.h" #include "tree.h" #include "selftest.h" +#include "util/expected.h" +#include "util/optional.h" +#include "util/rust-ggc.h" +#include "rust-diagnostics.h" namespace Rust { namespace Compile { @@ -79,11 +83,48 @@ namespace Compile { // }; // Some(cx.get_intrinsic(&llvm_name)) -enum class LlvmBuiltinMappingResult +/** + * Error type for Builtins::map_llvm_to_gcc_builtin + */ +struct LlvmBuiltinMappingError { - NOT_MAPPED, - TARGET_UNAVAILABLE, - RESOLVED, + enum class Kind + { + NOT_MAPPED, + TARGET_UNAVAILABLE, + } kind; + + static LlvmBuiltinMappingError NotMapped () + { + return LlvmBuiltinMappingError (Kind::NOT_MAPPED); + } + + static LlvmBuiltinMappingError TargetUnavailable () + { + return LlvmBuiltinMappingError (Kind::TARGET_UNAVAILABLE); + } + + /** + * Emit the error for the missing intrinsic + */ + void emit (const GGC::Ident &name, location_t loc) + { + switch (kind) + { + case LlvmBuiltinMappingError::Kind::TARGET_UNAVAILABLE: + rust_error_at (loc, + "LLVM intrinsic %qs is not available for this target", + name.c_str ()); + return; + case LlvmBuiltinMappingError::Kind::NOT_MAPPED: + rust_sorry_at (loc, "LLVM intrinsic %qs is not supported at the moment", + name.c_str ()); + return; + } + } + +private: + LlvmBuiltinMappingError (Kind kind) : kind (kind) {} }; enum class LlvmBuiltinAdapter @@ -104,11 +145,10 @@ class BuiltinsContext public: static BuiltinsContext &get (); - bool lookup_simple_builtin (const std::string &name, tree *builtin); + tl::optional<tree> lookup_simple_builtin (const std::string &name); - LlvmBuiltinMappingResult - map_llvm_to_gcc_builtin (const std::string &name, tree *resolved, - LlvmBuiltinAdapter *adapter); + tl::expected<std::pair<tree, LlvmBuiltinAdapter>, LlvmBuiltinMappingError> + map_llvm_to_gcc_builtin (const std::string &name); void register_builtin (tree decl); @@ -235,7 +275,7 @@ private: void setup (); - bool lookup_gcc_builtin (const std::string &name, tree *builtin); + tl::optional<tree> lookup_gcc_builtin (const std::string &name); // A mapping of the GCC built-ins exposed to GCC Rust. std::map<std::string, tree> builtin_functions; diff --git a/gcc/rust/backend/rust-compile-extern.h b/gcc/rust/backend/rust-compile-extern.h index 824d312143c5..313be385212f 100644 --- a/gcc/rust/backend/rust-compile-extern.h +++ b/gcc/rust/backend/rust-compile-extern.h @@ -132,30 +132,19 @@ public: if (fntype->get_abi () == ABI::UNADJUSTED) { - tree resolved; - LlvmBuiltinAdapter adapter; - auto mapping_res = BuiltinsContext::get ().map_llvm_to_gcc_builtin ( - asm_name.as_string (), &resolved, &adapter); + auto res = BuiltinsContext::get ().map_llvm_to_gcc_builtin ( + asm_name.as_string ()); - switch (mapping_res) + if (!res) { - case LlvmBuiltinMappingResult::NOT_MAPPED: - rust_error_at (function.get_locus (), - "LLVM intrinsic %qs is not supported at the moment", - asm_name.c_str ()); - reference = error_mark_node; - return; - case LlvmBuiltinMappingResult::TARGET_UNAVAILABLE: - rust_error_at ( - function.get_locus (), - "LLVM intrinsic %qs is not available for this target", - asm_name.c_str ()); + res.error ().emit (asm_name, function.get_locus ()); reference = error_mark_node; return; - case LlvmBuiltinMappingResult::RESOLVED: - break; } + tree resolved = res->first; + LlvmBuiltinAdapter adapter = res->second; + tree adapter_tree = error_mark_node; switch (adapter) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index b13e721a8ca7..872b53e701a8 100644 --- a/gcc/rust/backend/rust-compile-intrinsic.cc +++ b/gcc/rust/backend/rust-compile-intrinsic.cc @@ -99,11 +99,11 @@ Intrinsics::compile (TyTy::FnType *fntype, location_t expr_locus) { 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; + if (auto builtin + = builtin_ctx.lookup_simple_builtin (fntype->get_identifier ())) + return *builtin; // is it an generic builtin? auto it = generic_intrinsics.find (fntype->get_identifier ()); diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc b/gcc/rust/backend/rust-intrinsic-handlers.cc index 127d0642ed31..d68e872af43e 100644 --- a/gcc/rust/backend/rust-intrinsic-handlers.cc +++ b/gcc/rust/backend/rust-intrinsic-handlers.cc @@ -303,11 +303,11 @@ expect (Context *ctx, TyTy::FnType *fntype, bool likely) std::vector<Bvariable *> param_vars; compile_fn_params (ctx, fntype, fndecl, ¶m_vars); tree expr = Backend::var_expression (param_vars[0], UNDEF_LOCATION); - tree expect_fn_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin ("__builtin_expect", - &expect_fn_raw); + auto expect_fn_raw + = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_expect"); rust_assert (expect_fn_raw); - auto expect_fn = build_fold_addr_expr_loc (BUILTINS_LOCATION, expect_fn_raw); + + auto expect_fn = build_fold_addr_expr_loc (BUILTINS_LOCATION, *expect_fn_raw); // we need to convert the expression return type to long to match the expected // parameter type of __builtin_expect @@ -521,35 +521,37 @@ op_with_overflow (Context *ctx, TyTy::FnType *fntype, tree_code op) auto x = Backend::var_expression (x_param, UNDEF_LOCATION); auto y = Backend::var_expression (y_param, UNDEF_LOCATION); - tree overflow_builtin = error_mark_node; + tl::optional<tree> overflow_builtin = tl::nullopt; + auto &builtins = BuiltinsContext::get (); + switch (op) { case PLUS_EXPR: - BuiltinsContext::get ().lookup_simple_builtin ("__builtin_add_overflow", - &overflow_builtin); + overflow_builtin + = builtins.lookup_simple_builtin ("__builtin_add_overflow"); break; case MINUS_EXPR: - BuiltinsContext::get ().lookup_simple_builtin ("__builtin_sub_overflow", - &overflow_builtin); + overflow_builtin + = builtins.lookup_simple_builtin ("__builtin_sub_overflow"); break; case MULT_EXPR: - BuiltinsContext::get ().lookup_simple_builtin ("__builtin_mul_overflow", - &overflow_builtin); + overflow_builtin + = builtins.lookup_simple_builtin ("__builtin_mul_overflow"); break; default: rust_unreachable (); break; } - rust_assert (overflow_builtin != error_mark_node); + rust_assert (overflow_builtin); tree bool_decl = bool_variable->get_tree (BUILTINS_LOCATION); tree result_decl = result_variable->get_tree (BUILTINS_LOCATION); tree result_ref = build_fold_addr_expr_loc (BUILTINS_LOCATION, result_decl); - tree builtin_call = build_call_expr_loc (BUILTINS_LOCATION, overflow_builtin, + tree builtin_call = build_call_expr_loc (BUILTINS_LOCATION, *overflow_builtin, 3, x, y, result_ref); tree overflow_assignment @@ -620,12 +622,11 @@ copy (Context *ctx, TyTy::FnType *fntype, bool overlaps) tree size_expr = build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count); - tree memcpy_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "__builtin_memmove" - : "__builtin_memcpy", - &memcpy_raw); + auto memcpy_raw = BuiltinsContext::get ().lookup_simple_builtin ( + overlaps ? "__builtin_memmove" : "__builtin_memcpy"); rust_assert (memcpy_raw); - auto memcpy = build_fold_addr_expr_loc (UNKNOWN_LOCATION, memcpy_raw); + + auto memcpy = build_fold_addr_expr_loc (UNKNOWN_LOCATION, *memcpy_raw); auto copy_call = Backend::call_expression (memcpy, {dst, src, size_expr}, nullptr, UNDEF_LOCATION); @@ -680,13 +681,12 @@ atomic_store (Context *ctx, TyTy::FnType *fntype, int ordering) if (builtin_name.empty ()) return error_mark_node; - tree atomic_store_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin (builtin_name, - &atomic_store_raw); + auto atomic_store_raw + = BuiltinsContext::get ().lookup_simple_builtin (builtin_name); rust_assert (atomic_store_raw); auto atomic_store - = build_fold_addr_expr_loc (UNKNOWN_LOCATION, atomic_store_raw); + = build_fold_addr_expr_loc (UNKNOWN_LOCATION, *atomic_store_raw); auto store_call = Backend::call_expression (atomic_store, {dst, value, memorder}, nullptr, @@ -739,13 +739,12 @@ atomic_load (Context *ctx, TyTy::FnType *fntype, int ordering) if (builtin_name.empty ()) return error_mark_node; - tree atomic_load_raw = nullptr; - BuiltinsContext::get ().lookup_simple_builtin (builtin_name, - &atomic_load_raw); + auto atomic_load_raw + = BuiltinsContext::get ().lookup_simple_builtin (builtin_name); rust_assert (atomic_load_raw); auto atomic_load - = build_fold_addr_expr_loc (UNKNOWN_LOCATION, atomic_load_raw); + = build_fold_addr_expr_loc (UNKNOWN_LOCATION, *atomic_load_raw); auto load_call = Backend::call_expression (atomic_load, {src, memorder}, nullptr, UNDEF_LOCATION); @@ -863,11 +862,11 @@ ctlz_handler (Context *ctx, TyTy::FnType *fntype, bool nonzero) // matches the builtin's operand width, so the subtraction is skipped. tree call_arg = fold_convert (cast_type, unsigned_arg); - tree builtin_decl = error_mark_node; - BuiltinsContext::get ().lookup_simple_builtin (builtin_name, &builtin_decl); + auto builtin_decl + = BuiltinsContext::get ().lookup_simple_builtin (builtin_name); rust_assert (builtin_decl != error_mark_node); - tree builtin_fn = build_fold_addr_expr_loc (locus, builtin_decl); + tree builtin_fn = build_fold_addr_expr_loc (locus, *builtin_decl); tree clz_expr = Backend::call_expression (builtin_fn, {call_arg}, nullptr, locus); @@ -1000,11 +999,11 @@ cttz_handler (Context *ctx, TyTy::FnType *fntype, bool nonzero) tree call_arg = fold_convert (cast_type, unsigned_arg); - tree builtin_decl = error_mark_node; - BuiltinsContext::get ().lookup_simple_builtin (builtin_name, &builtin_decl); - rust_assert (builtin_decl != error_mark_node); + auto builtin_decl + = BuiltinsContext::get ().lookup_simple_builtin (builtin_name); + rust_assert (builtin_decl); - tree builtin_fn = build_fold_addr_expr_loc (locus, builtin_decl); + tree builtin_fn = build_fold_addr_expr_loc (locus, *builtin_decl); tree ctz_expr = Backend::call_expression (builtin_fn, {call_arg}, nullptr, locus); @@ -1318,13 +1317,12 @@ move_val_init (Context *ctx, TyTy::FnType *fntype, location_t) tree src = Backend::var_expression (param_vars[1], UNDEF_LOCATION); tree size = TYPE_SIZE_UNIT (template_parameter_type); - tree memcpy_builtin = error_mark_node; - BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memcpy", - &memcpy_builtin); - rust_assert (memcpy_builtin != error_mark_node); + auto memcpy_builtin + = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memcpy"); + rust_assert (memcpy_builtin); src = build_fold_addr_expr_loc (BUILTINS_LOCATION, src); - tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, memcpy_builtin, 3, + tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, *memcpy_builtin, 3, dst, src, size); ctx->add_statement (memset_call); @@ -1374,10 +1372,9 @@ uninit (Context *ctx, TyTy::FnType *fntype, location_t) // BUILTIN size_of FN BODY BEGIN - tree memset_builtin = error_mark_node; - BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset", - &memset_builtin); - rust_assert (memset_builtin != error_mark_node); + auto memset_builtin + = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset"); + rust_assert (memset_builtin); // call memset with 0x01 and size of the thing see // https://github.com/Rust-GCC/gccrs/issues/1899 @@ -1387,7 +1384,7 @@ uninit (Context *ctx, TyTy::FnType *fntype, location_t) tree constant_byte = build_int_cst (integer_type_node, 0x01); tree size_expr = TYPE_SIZE_UNIT (template_parameter_type); - tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, memset_builtin, 3, + tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, *memset_builtin, 3, dst_addr, constant_byte, size_expr); ctx->add_statement (memset_call); @@ -1453,11 +1450,11 @@ prefetch_data (Context *ctx, TyTy::FnType *fntype, Prefetch kind) auto rw_flag = make_unsigned_long_tree (kind == Prefetch::Write ? 1 : 0); - auto prefetch_raw = NULL_TREE; - 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_raw + = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_prefetch"); + rust_assert (prefetch_raw); + + auto prefetch = build_fold_addr_expr_loc (UNKNOWN_LOCATION, *prefetch_raw); auto prefetch_call = Backend::call_expression (prefetch, {addr, rw_flag, @@ -1994,13 +1991,12 @@ bswap_handler (Context *ctx, TyTy::FnType *fntype, location_t) return error_mark_node; } - tree bswap_raw = nullptr; - auto ok = BuiltinsContext::get ().lookup_simple_builtin (builtin_name, - &bswap_raw); + auto bswap_raw + = BuiltinsContext::get ().lookup_simple_builtin (builtin_name); - if (ok) + if (bswap_raw) { - tree bswap_fn = build_fold_addr_expr_loc (locus, bswap_raw); + tree bswap_fn = build_fold_addr_expr_loc (locus, *bswap_raw); auto bswap_x = build1 (CONVERT_EXPR, target_type, expr_x); @@ -2011,11 +2007,11 @@ bswap_handler (Context *ctx, TyTy::FnType *fntype, location_t) } else { - auto ok2 = BuiltinsContext::get ().lookup_simple_builtin ( - "__builtin_bswap64", &bswap_raw); - rust_assert (ok2); + bswap_raw = BuiltinsContext::get ().lookup_simple_builtin ( + "__builtin_bswap64"); + rust_assert (bswap_raw); - tree bswap_fn = build_fold_addr_expr_loc (locus, bswap_raw); + tree bswap_fn = build_fold_addr_expr_loc (locus, *bswap_raw); tree tmp_in_stmt = error_mark_node; Bvariable *in_var @@ -2152,13 +2148,12 @@ write_bytes_handler (Context *ctx, TyTy::FnType *fntype, location_t) fold_convert_loc (locus, size_type_node, expr_count), fold_convert_loc (locus, size_type_node, dst_size_expr)); - tree write_bytes_raw = nullptr; // void* memset( void* dest, int ch, size_t count ); - bool ok = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset", - &write_bytes_raw); - rust_assert (ok); + auto write_bytes_raw + = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset"); + rust_assert (write_bytes_raw); - tree write_bytes_fn = build_fold_addr_expr_loc (locus, write_bytes_raw); + tree write_bytes_fn = build_fold_addr_expr_loc (locus, *write_bytes_raw); tree write_bytes_call = Backend::call_expression (write_bytes_fn, {expr_dst, expr_val, expr_count_final}, diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc index bb9aee2c5581..88781f52b172 100644 --- a/gcc/rust/rust-gcc.cc +++ b/gcc/rust/rust-gcc.cc @@ -1168,31 +1168,30 @@ fetch_overflow_builtins (ArithmeticOrLogicalOperator op) { auto builtin_ctx = Rust::Compile::BuiltinsContext::get (); - auto builtin = NULL_TREE; - auto abort = NULL_TREE; + tl::optional<tree> builtin = NULL_TREE; switch (op) { case ArithmeticOrLogicalOperator::ADD: - builtin_ctx.lookup_simple_builtin ("__builtin_add_overflow", &builtin); + builtin = builtin_ctx.lookup_simple_builtin ("__builtin_add_overflow"); break; case ArithmeticOrLogicalOperator::SUBTRACT: - builtin_ctx.lookup_simple_builtin ("__builtin_sub_overflow", &builtin); + builtin = builtin_ctx.lookup_simple_builtin ("__builtin_sub_overflow"); break; case ArithmeticOrLogicalOperator::MULTIPLY: - builtin_ctx.lookup_simple_builtin ("__builtin_mul_overflow", &builtin); + builtin = builtin_ctx.lookup_simple_builtin ("__builtin_mul_overflow"); break; default: rust_unreachable (); break; }; - builtin_ctx.lookup_simple_builtin ("__builtin_abort", &abort); + auto abort = builtin_ctx.lookup_simple_builtin ("__builtin_abort"); rust_assert (abort); rust_assert (builtin); - return {abort, builtin}; + return {*abort, *builtin}; } // Return an expression for the arithmetic or logical operation LEFT OP RIGHT
