LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-intrinsic-handlers.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 86.7 % 804 697
Test Date: 2026-03-28 14:25:54 Functions: 95.2 % 42 40
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2026 Free Software Foundation, Inc.
       2              : //
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-intrinsic-handlers.h"
      20              : #include "rust-compile-context.h"
      21              : #include "rust-compile-type.h"
      22              : #include "rust-compile-fnparam.h"
      23              : #include "rust-builtins.h"
      24              : #include "rust-diagnostics.h"
      25              : #include "rust-location.h"
      26              : #include "rust-constexpr.h"
      27              : #include "rust-session-manager.h"
      28              : #include "rust-tree.h"
      29              : #include "tree-core.h"
      30              : #include "rust-gcc.h"
      31              : #include "fold-const.h"
      32              : #include "rust-constexpr.h"
      33              : 
      34              : // declaration taken from "stringpool.h"
      35              : // the get_identifier macro causes compilation issues
      36              : extern tree get_identifier (const char *);
      37              : 
      38              : namespace Rust {
      39              : namespace Compile {
      40              : namespace handlers {
      41              : 
      42              : static tree
      43          126 : make_unsigned_long_tree (unsigned long value)
      44              : {
      45           14 :   return build_int_cst (integer_type_node, value);
      46              : }
      47              : 
      48              : static bool
      49          163 : is_basic_integer_type (TyTy::BaseType *type)
      50              : {
      51          163 :   switch (type->get_kind ())
      52              :     {
      53              :     case TyTy::INT:
      54              :     case TyTy::UINT:
      55              :     case TyTy::USIZE:
      56              :     case TyTy::ISIZE:
      57              :       return true;
      58           22 :     default:
      59           22 :       return false;
      60              :       break;
      61              :     }
      62              : }
      63              : 
      64              : /**
      65              :  * Maybe override the Hir Lookups for the substituions in this context
      66              :  */
      67              : static void
      68         2191 : maybe_override_ctx (TyTy::FnType *fntype)
      69              : {
      70         2191 :   if (fntype->has_substitutions_defined ())
      71         2188 :     fntype->override_context ();
      72         2191 : }
      73              : 
      74              : static bool
      75          163 : check_for_basic_integer_type (const std::string &intrinsic_str,
      76              :                               location_t locus, TyTy::BaseType *type)
      77              : {
      78          163 :   auto is_basic_integer = is_basic_integer_type (type);
      79          163 :   if (!is_basic_integer)
      80              :     {
      81           22 :       rust_error_at (
      82              :         locus,
      83              :         "%s intrinsics can only be used with basic integer types (got %qs)",
      84           44 :         intrinsic_str.c_str (), type->get_name ().c_str ());
      85              :     }
      86              : 
      87          163 :   return is_basic_integer;
      88              : }
      89              : 
      90              : /**
      91              :  * Items can be forward compiled which means we may not need to invoke this
      92              :  * code. We might also have already compiled this generic function as well.
      93              :  */
      94              : static bool
      95         2119 : check_for_cached_intrinsic (Context *ctx, TyTy::FnType *fntype, tree *lookup)
      96              : {
      97         2119 :   const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
      98         2119 :   std::string asm_name = ctx->mangle_item (fntype, canonical_path);
      99         2119 :   if (ctx->lookup_function_decl (fntype->get_ty_ref (), lookup,
     100              :                                  fntype->get_id (), fntype, asm_name))
     101              :     {
     102              :       return true;
     103              :     }
     104              : 
     105              :   return false;
     106         2119 : }
     107              : 
     108              : static tree
     109         2191 : compile_intrinsic_function (Context *ctx, TyTy::FnType *fntype)
     110              : {
     111         2191 :   maybe_override_ctx (fntype);
     112              : 
     113         2191 :   const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
     114              : 
     115         2191 :   tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
     116         2191 :   std::string ir_symbol_name
     117         2191 :     = canonical_path.get () + fntype->subst_as_string ();
     118         2191 :   std::string asm_name = ctx->mangle_item (fntype, canonical_path);
     119              : 
     120         2191 :   unsigned int flags = 0;
     121         2191 :   tree fndecl = Backend::function (compiled_fn_type, ir_symbol_name, asm_name,
     122         2191 :                                    flags, fntype->get_ident ().locus);
     123              : 
     124         2191 :   TREE_PUBLIC (fndecl) = 0;
     125         2191 :   TREE_READONLY (fndecl) = 1;
     126         2191 :   DECL_ARTIFICIAL (fndecl) = 1;
     127         2191 :   DECL_EXTERNAL (fndecl) = 0;
     128         2191 :   DECL_DECLARED_INLINE_P (fndecl) = 1;
     129              : 
     130         2191 :   return fndecl;
     131         2191 : }
     132              : 
     133              : /**
     134              :  * Compile and setup a function's parameters
     135              :  */
     136              : static void
     137         1625 : compile_fn_params (Context *ctx, TyTy::FnType *fntype, tree fndecl,
     138              :                    std::vector<Bvariable *> *compiled_param_variables,
     139              :                    std::vector<tree_node *> *compiled_param_types = nullptr)
     140              : {
     141         4775 :   for (auto &parm : fntype->get_params ())
     142              :     {
     143         3150 :       auto &referenced_param = parm.get_pattern ();
     144         3150 :       auto param_tyty = parm.get_type ();
     145         3150 :       auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
     146              : 
     147         3150 :       location_t param_locus = referenced_param.get_locus ();
     148         3150 :       Bvariable *compiled_param_var
     149         3150 :         = CompileFnParam::compile (ctx, fndecl, referenced_param,
     150         3150 :                                    compiled_param_type, param_locus);
     151              : 
     152         3150 :       compiled_param_variables->push_back (compiled_param_var);
     153         3150 :       if (compiled_param_types)
     154          359 :         compiled_param_types->push_back (compiled_param_type);
     155              :     }
     156         1625 : }
     157              : 
     158              : static void
     159         2191 : enter_intrinsic_block (Context *ctx, tree fndecl,
     160              :                        const std::vector<Bvariable *> &vars = {})
     161              : {
     162         2191 :   tree enclosing_scope = NULL_TREE;
     163         2191 :   location_t start_location = UNDEF_LOCATION;
     164         2191 :   location_t end_location = UNDEF_LOCATION;
     165              : 
     166         2191 :   auto block = Backend::block (fndecl, enclosing_scope, vars, start_location,
     167              :                                end_location);
     168              : 
     169         2191 :   ctx->push_block (block);
     170         2191 : }
     171              : 
     172              : static void
     173         2177 : finalize_intrinsic_block (Context *ctx, tree fndecl)
     174              : {
     175         2177 :   tree bind_tree = ctx->pop_block ();
     176              : 
     177         2177 :   gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
     178              : 
     179         2177 :   DECL_SAVED_TREE (fndecl) = bind_tree;
     180              : 
     181         2177 :   ctx->push_function (fndecl);
     182              : 
     183         2177 :   DECL_DECLARED_CONSTEXPR_P (fndecl) = 1;
     184         2177 :   maybe_save_constexpr_fundef (fndecl);
     185         2177 : }
     186              : 
     187              : namespace inner {
     188              : 
     189              : static std::string
     190           98 : build_atomic_builtin_name (const std::string &prefix, location_t locus,
     191              :                            TyTy::BaseType *operand_type)
     192              : {
     193           98 :   static const std::map<std::string, std::string> allowed_types = {
     194              :     {"i8", "1"},    {"i16", "2"},   {"i32", "4"},   {"i64", "8"},
     195              :     {"i128", "16"}, {"isize", "8"}, {"u8", "1"},    {"u16", "2"},
     196              :     {"u32", "4"},   {"u64", "8"},   {"u128", "16"}, {"usize", "8"},
     197          462 :   };
     198              : 
     199              :   // TODO: Can we maybe get the generic version (atomic_store_n) to work... This
     200              :   // would be so much better
     201              : 
     202           98 :   std::string result = "__" + prefix; //  + "n";
     203              : 
     204           98 :   auto type_name = operand_type->get_name ();
     205           98 :   if (type_name == "usize" || type_name == "isize")
     206              :     {
     207            0 :       rust_sorry_at (
     208              :         locus, "atomics are not yet available for size types (usize, isize)");
     209            0 :       return "";
     210              :     }
     211              : 
     212           98 :   if (type_name.at (0) == 'i')
     213              :     {
     214            0 :       rust_sorry_at (locus, "atomics are not yet supported for signed "
     215              :                             "integer types (i8, i16, i32, i64, i128)");
     216            0 :       return "";
     217              :     }
     218              : 
     219           98 :   auto type_size_str = allowed_types.find (type_name);
     220              : 
     221           98 :   if (!check_for_basic_integer_type ("atomic", locus, operand_type))
     222           14 :     return "";
     223              : 
     224           84 :   result += type_size_str->second;
     225              : 
     226           84 :   return result;
     227           98 : }
     228              : 
     229              : inline tree
     230           56 : unchecked_op (Context *ctx, TyTy::FnType *fntype, tree_code op)
     231              : {
     232           56 :   rust_assert (fntype->get_params ().size () == 2);
     233           56 :   rust_assert (fntype->get_num_substitutions () == 1);
     234              : 
     235           56 :   tree lookup = NULL_TREE;
     236           56 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     237            0 :     return lookup;
     238              : 
     239           56 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     240              : 
     241              :   // setup the params
     242           56 :   std::vector<Bvariable *> param_vars;
     243           56 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     244              : 
     245           56 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     246            0 :     return error_mark_node;
     247              : 
     248           56 :   enter_intrinsic_block (ctx, fndecl);
     249              : 
     250              :   // BUILTIN unchecked_<op> BODY BEGIN
     251              : 
     252           56 :   auto x = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     253           56 :   auto y = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
     254              : 
     255           56 :   auto *monomorphized_type
     256           56 :     = fntype->get_substs ().at (0).get_param_ty ()->resolve ();
     257              : 
     258           56 :   check_for_basic_integer_type ("unchecked operation", fntype->get_locus (),
     259              :                                 monomorphized_type);
     260              : 
     261           56 :   auto expr = build2 (op, TREE_TYPE (x), x, y);
     262           56 :   auto return_statement
     263           56 :     = Backend::return_statement (fndecl, expr, UNDEF_LOCATION);
     264              : 
     265           56 :   ctx->add_statement (return_statement);
     266              : 
     267              :   // BUILTIN unchecked_<op> BODY END
     268              : 
     269           56 :   finalize_intrinsic_block (ctx, fndecl);
     270              : 
     271           56 :   return fndecl;
     272           56 : }
     273              : 
     274              : inline tree
     275            0 : expect (Context *ctx, TyTy::FnType *fntype, bool likely)
     276              : {
     277            0 :   rust_assert (fntype->get_params ().size () == 1);
     278              : 
     279            0 :   tree lookup = NULL_TREE;
     280            0 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     281            0 :     return lookup;
     282              : 
     283            0 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     284              : 
     285            0 :   enter_intrinsic_block (ctx, fndecl);
     286              : 
     287              :   // BUILTIN expect_handler_inner FN BODY BEGIN
     288              :   // setup the params
     289            0 :   std::vector<Bvariable *> param_vars;
     290            0 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     291            0 :   tree expr = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     292            0 :   tree expect_fn_raw = nullptr;
     293            0 :   BuiltinsContext::get ().lookup_simple_builtin ("__builtin_expect",
     294              :                                                  &expect_fn_raw);
     295            0 :   rust_assert (expect_fn_raw);
     296            0 :   auto expect_fn = build_fold_addr_expr_loc (BUILTINS_LOCATION, expect_fn_raw);
     297              : 
     298              :   // we need to convert the expression return type to long to match the expected
     299              :   // parameter type of __builtin_expect
     300            0 :   auto expect_src = build1 (CONVERT_EXPR, long_integer_type_node, expr);
     301            0 :   auto expect_value
     302            0 :     = make_unsigned_long_tree (static_cast<unsigned long> (likely));
     303              : 
     304            0 :   auto expect_call
     305            0 :     = Backend::call_expression (expect_fn, {expect_src, expect_value}, nullptr,
     306              :                                 BUILTINS_LOCATION);
     307              :   // the return value also needs to be casted (to bool)
     308            0 :   auto expect_call_bool = build1 (CONVERT_EXPR, boolean_type_node, expect_call);
     309            0 :   auto return_statement
     310            0 :     = Backend::return_statement (fndecl, expect_call_bool, BUILTINS_LOCATION);
     311            0 :   ctx->add_statement (return_statement);
     312              :   // BUILTIN expect_handler_inner FN BODY END
     313              : 
     314            0 :   finalize_intrinsic_block (ctx, fndecl);
     315              : 
     316            0 :   return fndecl;
     317            0 : }
     318              : 
     319              : tree
     320            2 : try_handler (Context *ctx, TyTy::FnType *fntype, bool is_new_api)
     321              : {
     322            2 :   rust_assert (fntype->get_params ().size () == 3);
     323              : 
     324            2 :   tree lookup = NULL_TREE;
     325            2 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     326            0 :     return lookup;
     327            2 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     328              : 
     329            2 :   enter_intrinsic_block (ctx, fndecl);
     330              : 
     331              :   // The following tricks are needed to make sure the try-catch blocks are not
     332              :   // optimized away
     333            2 :   TREE_READONLY (fndecl) = 0;
     334            2 :   DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
     335            2 :   DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"),
     336            2 :                                         NULL_TREE, DECL_ATTRIBUTES (fndecl));
     337              : 
     338              :   // BUILTIN try_handler FN BODY BEGIN
     339              :   // setup the params
     340            2 :   std::vector<Bvariable *> param_vars;
     341            2 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     342            2 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     343            0 :     return error_mark_node;
     344            2 :   tree enclosing_scope = NULL_TREE;
     345              : 
     346            2 :   bool panic_is_abort = Session::get_instance ().options.get_panic_strategy ()
     347            2 :                         == CompileOptions::PanicStrategy::Abort;
     348            2 :   tree try_fn = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     349            2 :   tree user_data = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
     350            2 :   tree catch_fn = Backend::var_expression (param_vars[2], UNDEF_LOCATION);
     351            2 :   tree normal_return_stmt = NULL_TREE;
     352            2 :   tree error_return_stmt = NULL_TREE;
     353            2 :   tree try_call = Backend::call_expression (try_fn, {user_data}, nullptr,
     354              :                                             BUILTINS_LOCATION);
     355            2 :   tree catch_call = NULL_TREE;
     356            2 :   tree try_block = Backend::block (fndecl, enclosing_scope, {}, UNDEF_LOCATION,
     357              :                                    UNDEF_LOCATION);
     358              : 
     359            2 :   if (is_new_api)
     360              :     {
     361            1 :       auto ret_type = TyTyResolveCompile::get_unit_type (ctx);
     362            1 :       auto ret_expr = Backend::constructor_expression (ret_type, false, {}, -1,
     363              :                                                        UNDEF_LOCATION);
     364            1 :       normal_return_stmt
     365            1 :         = Backend::return_statement (fndecl, ret_expr, BUILTINS_LOCATION);
     366            1 :       error_return_stmt
     367            1 :         = Backend::return_statement (fndecl, ret_expr, BUILTINS_LOCATION);
     368              :     }
     369              :   else
     370              :     {
     371            1 :       normal_return_stmt = Backend::return_statement (fndecl, integer_zero_node,
     372              :                                                       BUILTINS_LOCATION);
     373            1 :       error_return_stmt = Backend::return_statement (fndecl, integer_one_node,
     374              :                                                      BUILTINS_LOCATION);
     375              :     }
     376            2 :   Backend::block_add_statements (try_block,
     377            2 :                                  std::vector<tree>{try_call,
     378            2 :                                                    normal_return_stmt});
     379            2 :   if (panic_is_abort)
     380              :     {
     381              :       // skip building the try-catch construct
     382            0 :       ctx->add_statement (try_block);
     383            0 :       finalize_intrinsic_block (ctx, fndecl);
     384            0 :       return fndecl;
     385              :     }
     386              : 
     387            2 :   tree eh_pointer
     388            2 :     = build_call_expr (builtin_decl_explicit (BUILT_IN_EH_POINTER), 1,
     389              :                        integer_zero_node);
     390            2 :   catch_call = Backend::call_expression (catch_fn, {user_data, eh_pointer},
     391              :                                          NULL_TREE, BUILTINS_LOCATION);
     392              : 
     393            2 :   tree catch_block = Backend::block (fndecl, enclosing_scope, {},
     394              :                                      UNDEF_LOCATION, UNDEF_LOCATION);
     395            2 :   Backend::block_add_statements (catch_block,
     396            2 :                                  std::vector<tree>{catch_call,
     397            2 :                                                    error_return_stmt});
     398              :   // emulate what cc1plus is doing for C++ try-catch
     399            2 :   tree inner_eh_construct
     400            2 :     = Backend::exception_handler_statement (catch_call, NULL_TREE,
     401              :                                             error_return_stmt,
     402              :                                             BUILTINS_LOCATION);
     403              :   // TODO(liushuyu): eh_personality needs to be implemented as a runtime thing
     404            2 :   auto eh_construct
     405            2 :     = Backend::exception_handler_statement (try_block, inner_eh_construct,
     406              :                                             NULL_TREE, BUILTINS_LOCATION);
     407            2 :   ctx->add_statement (eh_construct);
     408              :   // BUILTIN try_handler FN BODY END
     409            2 :   finalize_intrinsic_block (ctx, fndecl);
     410              : 
     411            2 :   return fndecl;
     412            2 : }
     413              : 
     414              : /**
     415              :  * pub fn wrapping_{add, sub, mul}<T>(lhs: T, rhs: T) -> T;
     416              :  */
     417              : tree
     418          310 : wrapping_op (Context *ctx, TyTy::FnType *fntype, tree_code op)
     419              : {
     420              :   // wrapping_<op> intrinsics have two parameter
     421          310 :   rust_assert (fntype->get_params ().size () == 2);
     422              : 
     423          310 :   tree lookup = NULL_TREE;
     424          310 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     425            0 :     return lookup;
     426              : 
     427          310 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     428              : 
     429              :   // setup the params
     430          310 :   std::vector<Bvariable *> param_vars;
     431          310 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     432              : 
     433          310 :   auto &lhs_param = param_vars.at (0);
     434          310 :   auto &rhs_param = param_vars.at (1);
     435              : 
     436          310 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     437            0 :     return error_mark_node;
     438              : 
     439          310 :   enter_intrinsic_block (ctx, fndecl);
     440              : 
     441              :   // BUILTIN wrapping_<op> FN BODY BEGIN
     442          310 :   auto lhs = Backend::var_expression (lhs_param, UNDEF_LOCATION);
     443          310 :   auto rhs = Backend::var_expression (rhs_param, UNDEF_LOCATION);
     444              : 
     445              :   // Operations are always wrapping in Rust, as we have -fwrapv enabled by
     446              :   // default. The difference between a wrapping_{add, sub, mul} and a regular
     447              :   // arithmetic operation is that these intrinsics do not panic - they always
     448              :   // carry over.
     449          310 :   auto wrap_expr = build2 (op, TREE_TYPE (lhs), lhs, rhs);
     450              : 
     451          310 :   auto return_statement
     452          310 :     = Backend::return_statement (fndecl, wrap_expr, UNDEF_LOCATION);
     453          310 :   ctx->add_statement (return_statement);
     454              :   // BUILTIN wrapping_<op> FN BODY END
     455              : 
     456          310 :   finalize_intrinsic_block (ctx, fndecl);
     457              : 
     458          310 :   return fndecl;
     459          310 : }
     460              : 
     461              : /**
     462              :  * pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
     463              :  */
     464              : tree
     465          141 : op_with_overflow (Context *ctx, TyTy::FnType *fntype, tree_code op)
     466              : {
     467              :   // wrapping_<op> intrinsics have two parameter
     468          141 :   rust_assert (fntype->get_params ().size () == 2);
     469              : 
     470          141 :   tree lookup = NULL_TREE;
     471          141 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     472            0 :     return lookup;
     473              : 
     474          141 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     475              : 
     476              :   // setup the params
     477          141 :   std::vector<Bvariable *> param_vars;
     478          141 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     479              : 
     480          141 :   auto &x_param = param_vars.at (0);
     481          141 :   auto &y_param = param_vars.at (1);
     482              : 
     483          141 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     484            0 :     return error_mark_node;
     485              : 
     486          141 :   rust_assert (fntype->get_num_substitutions () == 1);
     487          141 :   auto &param_mapping = fntype->get_substs ().at (0);
     488          141 :   const auto param_tyty = param_mapping.get_param_ty ();
     489          141 :   auto resolved_tyty = param_tyty->resolve ();
     490          141 :   tree template_parameter_type
     491          141 :     = TyTyResolveCompile::compile (ctx, resolved_tyty);
     492              : 
     493              :   // this should match y as well or we can take it from the TyTy structure
     494          141 :   tree tmp_stmt = error_mark_node;
     495          141 :   Bvariable *result_variable
     496          141 :     = Backend::temporary_variable (fndecl, NULL_TREE, template_parameter_type,
     497              :                                    NULL_TREE, true /*address_is_taken*/,
     498              :                                    UNDEF_LOCATION, &tmp_stmt);
     499          141 :   Bvariable *bool_variable
     500          141 :     = Backend::temporary_variable (fndecl, NULL_TREE, boolean_type_node,
     501              :                                    NULL_TREE, true /*address_is_taken*/,
     502              :                                    UNDEF_LOCATION, &tmp_stmt);
     503              : 
     504          141 :   enter_intrinsic_block (ctx, fndecl, {result_variable, bool_variable});
     505              : 
     506              :   // BUILTIN op_with_overflow FN BODY BEGIN
     507          141 :   auto x = Backend::var_expression (x_param, UNDEF_LOCATION);
     508          141 :   auto y = Backend::var_expression (y_param, UNDEF_LOCATION);
     509              : 
     510          141 :   tree overflow_builtin = error_mark_node;
     511          141 :   switch (op)
     512              :     {
     513          127 :     case PLUS_EXPR:
     514          127 :       BuiltinsContext::get ().lookup_simple_builtin ("__builtin_add_overflow",
     515              :                                                      &overflow_builtin);
     516          127 :       break;
     517              : 
     518            7 :     case MINUS_EXPR:
     519            7 :       BuiltinsContext::get ().lookup_simple_builtin ("__builtin_sub_overflow",
     520              :                                                      &overflow_builtin);
     521            7 :       break;
     522              : 
     523            7 :     case MULT_EXPR:
     524            7 :       BuiltinsContext::get ().lookup_simple_builtin ("__builtin_mul_overflow",
     525              :                                                      &overflow_builtin);
     526            7 :       break;
     527              : 
     528            0 :     default:
     529            0 :       rust_unreachable ();
     530          141 :       break;
     531              :     }
     532          141 :   rust_assert (overflow_builtin != error_mark_node);
     533              : 
     534          141 :   tree bool_decl = bool_variable->get_tree (BUILTINS_LOCATION);
     535          141 :   tree result_decl = result_variable->get_tree (BUILTINS_LOCATION);
     536          141 :   tree result_ref = build_fold_addr_expr_loc (BUILTINS_LOCATION, result_decl);
     537              : 
     538          141 :   tree builtin_call = build_call_expr_loc (BUILTINS_LOCATION, overflow_builtin,
     539              :                                            3, x, y, result_ref);
     540              : 
     541          141 :   tree overflow_assignment
     542          141 :     = Backend::assignment_statement (bool_decl, builtin_call,
     543              :                                      BUILTINS_LOCATION);
     544              : 
     545          141 :   ctx->add_statement (overflow_assignment);
     546              : 
     547          282 :   std::vector<tree> vals = {result_decl, bool_decl};
     548          141 :   tree tuple_type = TREE_TYPE (DECL_RESULT (fndecl));
     549          141 :   tree result_expr = Backend::constructor_expression (tuple_type, false, vals,
     550              :                                                       -1, UNDEF_LOCATION);
     551              : 
     552          141 :   auto return_statement
     553          141 :     = Backend::return_statement (fndecl, result_expr, UNDEF_LOCATION);
     554          141 :   ctx->add_statement (return_statement);
     555              : 
     556              :   // BUILTIN wrapping_<op> FN BODY END
     557              : 
     558          141 :   finalize_intrinsic_block (ctx, fndecl);
     559              : 
     560          141 :   return fndecl;
     561          141 : }
     562              : 
     563              : /**
     564              :  * fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
     565              :  * fn copy<T>(src: *const T, dst: *mut T, count: usize);
     566              :  */
     567              : tree
     568          243 : copy (Context *ctx, TyTy::FnType *fntype, bool overlaps)
     569              : {
     570          243 :   rust_assert (fntype->get_params ().size () == 3);
     571          243 :   rust_assert (fntype->get_num_substitutions () == 1);
     572              : 
     573          243 :   tree lookup = NULL_TREE;
     574          243 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     575            0 :     return lookup;
     576              : 
     577          243 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     578              : 
     579              :   // Most intrinsic functions are pure - not `copy_nonoverlapping` and `copy`
     580          243 :   TREE_READONLY (fndecl) = 0;
     581          243 :   TREE_SIDE_EFFECTS (fndecl) = 1;
     582              : 
     583              :   // setup the params
     584          243 :   std::vector<Bvariable *> param_vars;
     585          243 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     586              : 
     587          243 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     588            0 :     return error_mark_node;
     589              : 
     590          243 :   enter_intrinsic_block (ctx, fndecl);
     591              : 
     592              :   // BUILTIN copy_nonoverlapping BODY BEGIN
     593              : 
     594          243 :   auto src = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     595          243 :   auto dst = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
     596          243 :   auto count = Backend::var_expression (param_vars[2], UNDEF_LOCATION);
     597              : 
     598              :   // We want to create the following statement
     599              :   // memcpy(dst, src, size_of::<T>());
     600              :   // so
     601              :   // memcpy(dst, src, size_expr);
     602              : 
     603          243 :   auto *resolved_ty = fntype->get_substs ().at (0).get_param_ty ()->resolve ();
     604          243 :   auto param_type = TyTyResolveCompile::compile (ctx, resolved_ty);
     605              : 
     606          243 :   tree size_expr
     607          243 :     = build2 (MULT_EXPR, size_type_node, TYPE_SIZE_UNIT (param_type), count);
     608              : 
     609          243 :   tree memcpy_raw = nullptr;
     610          486 :   BuiltinsContext::get ().lookup_simple_builtin (overlaps ? "__builtin_memmove"
     611              :                                                           : "__builtin_memcpy",
     612              :                                                  &memcpy_raw);
     613          243 :   rust_assert (memcpy_raw);
     614          243 :   auto memcpy = build_fold_addr_expr_loc (UNKNOWN_LOCATION, memcpy_raw);
     615              : 
     616          243 :   auto copy_call = Backend::call_expression (memcpy, {dst, src, size_expr},
     617              :                                              nullptr, UNDEF_LOCATION);
     618              : 
     619          243 :   ctx->add_statement (copy_call);
     620              : 
     621              :   // BUILTIN copy_nonoverlapping BODY END
     622              : 
     623          243 :   finalize_intrinsic_block (ctx, fndecl);
     624              : 
     625          243 :   return fndecl;
     626          243 : }
     627              : 
     628              : tree
     629           70 : atomic_store (Context *ctx, TyTy::FnType *fntype, int ordering)
     630              : {
     631           70 :   rust_assert (fntype->get_params ().size () == 2);
     632           70 :   rust_assert (fntype->get_num_substitutions () == 1);
     633              : 
     634           70 :   tree lookup = NULL_TREE;
     635           70 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     636            0 :     return lookup;
     637              : 
     638           70 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     639              : 
     640              :   // Most intrinsic functions are pure but not the atomic ones
     641           70 :   TREE_READONLY (fndecl) = 0;
     642           70 :   TREE_SIDE_EFFECTS (fndecl) = 1;
     643              : 
     644              :   // setup the params
     645           70 :   std::vector<Bvariable *> param_vars;
     646           70 :   std::vector<tree> types;
     647           70 :   compile_fn_params (ctx, fntype, fndecl, &param_vars, &types);
     648              : 
     649           70 :   auto ok = Backend::function_set_parameters (fndecl, param_vars);
     650           70 :   rust_assert (ok);
     651              : 
     652           70 :   enter_intrinsic_block (ctx, fndecl);
     653              : 
     654           70 :   auto dst = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     655           70 :   TREE_READONLY (dst) = 0;
     656              : 
     657           70 :   auto value = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
     658           70 :   auto memorder = make_unsigned_long_tree (ordering);
     659              : 
     660           70 :   auto monomorphized_type
     661           70 :     = fntype->get_substs ()[0].get_param_ty ()->resolve ();
     662              : 
     663           70 :   auto builtin_name
     664           70 :     = build_atomic_builtin_name ("atomic_store_", fntype->get_locus (),
     665           70 :                                  monomorphized_type);
     666           70 :   if (builtin_name.empty ())
     667           14 :     return error_mark_node;
     668              : 
     669           56 :   tree atomic_store_raw = nullptr;
     670           56 :   BuiltinsContext::get ().lookup_simple_builtin (builtin_name,
     671              :                                                  &atomic_store_raw);
     672           56 :   rust_assert (atomic_store_raw);
     673              : 
     674           56 :   auto atomic_store
     675           56 :     = build_fold_addr_expr_loc (UNKNOWN_LOCATION, atomic_store_raw);
     676              : 
     677           56 :   auto store_call
     678           56 :     = Backend::call_expression (atomic_store, {dst, value, memorder}, nullptr,
     679              :                                 UNDEF_LOCATION);
     680           56 :   TREE_READONLY (store_call) = 0;
     681           56 :   TREE_SIDE_EFFECTS (store_call) = 1;
     682              : 
     683           56 :   ctx->add_statement (store_call);
     684           56 :   finalize_intrinsic_block (ctx, fndecl);
     685              : 
     686           56 :   return fndecl;
     687           70 : }
     688              : 
     689              : tree
     690           28 : atomic_load (Context *ctx, TyTy::FnType *fntype, int ordering)
     691              : {
     692           28 :   rust_assert (fntype->get_params ().size () == 1);
     693           28 :   rust_assert (fntype->get_num_substitutions () == 1);
     694              : 
     695           28 :   tree lookup = NULL_TREE;
     696           28 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     697            0 :     return lookup;
     698              : 
     699           28 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     700              : 
     701              :   // Most intrinsic functions are pure but not the atomic ones
     702              :   // FIXME: Is atomic_load_* pure? Feels like it shouldn't so
     703           28 :   TREE_READONLY (fndecl) = 0;
     704           28 :   TREE_SIDE_EFFECTS (fndecl) = 1;
     705              : 
     706              :   // setup the params
     707           28 :   std::vector<Bvariable *> param_vars;
     708           28 :   std::vector<tree> types;
     709           28 :   compile_fn_params (ctx, fntype, fndecl, &param_vars, &types);
     710              : 
     711           28 :   auto ok = Backend::function_set_parameters (fndecl, param_vars);
     712           28 :   rust_assert (ok);
     713              : 
     714           28 :   enter_intrinsic_block (ctx, fndecl);
     715              : 
     716           28 :   auto src = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     717           28 :   auto memorder = make_unsigned_long_tree (ordering);
     718              : 
     719           28 :   auto monomorphized_type
     720           28 :     = fntype->get_substs ()[0].get_param_ty ()->resolve ();
     721              : 
     722           28 :   auto builtin_name
     723           28 :     = build_atomic_builtin_name ("atomic_load_", fntype->get_locus (),
     724           28 :                                  monomorphized_type);
     725           28 :   if (builtin_name.empty ())
     726            0 :     return error_mark_node;
     727              : 
     728           28 :   tree atomic_load_raw = nullptr;
     729           28 :   BuiltinsContext::get ().lookup_simple_builtin (builtin_name,
     730              :                                                  &atomic_load_raw);
     731           28 :   rust_assert (atomic_load_raw);
     732              : 
     733           28 :   auto atomic_load
     734           28 :     = build_fold_addr_expr_loc (UNKNOWN_LOCATION, atomic_load_raw);
     735              : 
     736           28 :   auto load_call = Backend::call_expression (atomic_load, {src, memorder},
     737              :                                              nullptr, UNDEF_LOCATION);
     738           28 :   auto return_statement
     739           28 :     = Backend::return_statement (fndecl, load_call, UNDEF_LOCATION);
     740              : 
     741           28 :   TREE_READONLY (load_call) = 0;
     742           28 :   TREE_SIDE_EFFECTS (load_call) = 1;
     743              : 
     744           28 :   ctx->add_statement (return_statement);
     745              : 
     746           28 :   finalize_intrinsic_block (ctx, fndecl);
     747              : 
     748           28 :   return fndecl;
     749           28 : }
     750              : 
     751              : } // namespace inner
     752              : 
     753              : const HandlerBuilder
     754        13959 : op_with_overflow (tree_code op)
     755              : {
     756        14100 :   return [op] (Context *ctx, TyTy::FnType *fntype) {
     757          141 :     return inner::op_with_overflow (ctx, fntype, op);
     758        13959 :   };
     759              : }
     760              : 
     761              : tree
     762          198 : rotate_left (Context *ctx, TyTy::FnType *fntype)
     763              : {
     764          198 :   return handlers::rotate (ctx, fntype, LROTATE_EXPR);
     765              : }
     766              : 
     767              : tree
     768          155 : rotate_right (Context *ctx, TyTy::FnType *fntype)
     769              : {
     770          155 :   return handlers::rotate (ctx, fntype, RROTATE_EXPR);
     771              : }
     772              : 
     773              : const HandlerBuilder
     774        13959 : wrapping_op (tree_code op)
     775              : {
     776        14269 :   return [op] (Context *ctx, TyTy::FnType *fntype) {
     777          310 :     return inner::wrapping_op (ctx, fntype, op);
     778        13959 :   };
     779              : }
     780              : 
     781              : HandlerBuilder
     782        18612 : atomic_store (int ordering)
     783              : {
     784        18682 :   return [ordering] (Context *ctx, TyTy::FnType *fntype) {
     785           70 :     return inner::atomic_store (ctx, fntype, ordering);
     786        18612 :   };
     787              : }
     788              : 
     789              : HandlerBuilder
     790        18612 : atomic_load (int ordering)
     791              : {
     792        18640 :   return [ordering] (Context *ctx, TyTy::FnType *fntype) {
     793           28 :     return inner::atomic_load (ctx, fntype, ordering);
     794        18612 :   };
     795              : }
     796              : 
     797              : const HandlerBuilder
     798        32571 : unchecked_op (tree_code op)
     799              : {
     800        32627 :   return [op] (Context *ctx, TyTy::FnType *fntype) {
     801           56 :     return inner::unchecked_op (ctx, fntype, op);
     802        32571 :   };
     803              : }
     804              : 
     805              : const HandlerBuilder
     806         9306 : copy (bool overlaps)
     807              : {
     808         9549 :   return [overlaps] (Context *ctx, TyTy::FnType *fntype) {
     809          243 :     return inner::copy (ctx, fntype, overlaps);
     810         9306 :   };
     811              : }
     812              : 
     813              : const HandlerBuilder
     814         9306 : expect (bool likely)
     815              : {
     816         9306 :   return [likely] (Context *ctx, TyTy::FnType *fntype) {
     817            0 :     return inner::expect (ctx, fntype, likely);
     818         9306 :   };
     819              : }
     820              : 
     821              : const HandlerBuilder
     822         9306 : try_handler (bool is_new_api)
     823              : {
     824         9308 :   return [is_new_api] (Context *ctx, TyTy::FnType *fntype) {
     825            2 :     return inner::try_handler (ctx, fntype, is_new_api);
     826         9306 :   };
     827              : }
     828              : 
     829              : tree
     830            0 : sorry (Context *ctx, TyTy::FnType *fntype)
     831              : {
     832            0 :   rust_sorry_at (fntype->get_locus (), "intrinsic %qs is not yet implemented",
     833              :                  fntype->get_identifier ().c_str ());
     834              : 
     835            0 :   return error_mark_node;
     836              : }
     837              : 
     838              : tree
     839            1 : assume (Context *ctx, TyTy::FnType *fntype)
     840              : {
     841              :   // TODO: make sure this is actually helping the compiler optimize
     842              : 
     843            1 :   rust_assert (fntype->get_params ().size () == 1);
     844            1 :   rust_assert (fntype->param_at (0).get_type ()->get_kind ()
     845              :                == TyTy::TypeKind::BOOL);
     846              : 
     847            1 :   tree lookup = NULL_TREE;
     848            1 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     849            0 :     return lookup;
     850              : 
     851            1 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     852              : 
     853              :   // TODO: make sure these are necessary
     854            1 :   TREE_READONLY (fndecl) = 0;
     855            1 :   DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
     856            1 :   DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("always_inline"),
     857            1 :                                         NULL_TREE, DECL_ATTRIBUTES (fndecl));
     858              : 
     859            1 :   std::vector<Bvariable *> param_vars;
     860            1 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     861              : 
     862            1 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     863            0 :     return error_mark_node;
     864              : 
     865            1 :   enter_intrinsic_block (ctx, fndecl);
     866              : 
     867              :   // BUILTIN assume FN BODY BEGIN
     868              : 
     869            1 :   tree val = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     870              : 
     871            1 :   tree assume_expr = build_call_expr_internal_loc (UNDEF_LOCATION, IFN_ASSUME,
     872              :                                                    void_type_node, 1, val);
     873            1 :   TREE_SIDE_EFFECTS (assume_expr) = 1;
     874              : 
     875            1 :   ctx->add_statement (assume_expr);
     876              :   // BUILTIN assume FN BODY END
     877              : 
     878            1 :   finalize_intrinsic_block (ctx, fndecl);
     879              : 
     880            1 :   return fndecl;
     881            1 : }
     882              : 
     883              : tree
     884          102 : discriminant_value (Context *ctx, TyTy::FnType *fntype)
     885              : {
     886          102 :   rust_assert (fntype->get_params ().size () == 1);
     887          102 :   rust_assert (fntype->get_return_type ()->is<TyTy::PlaceholderType> ());
     888          102 :   rust_assert (fntype->has_substitutions ());
     889          102 :   rust_assert (fntype->get_num_type_params () == 1);
     890          102 :   auto &mapping = fntype->get_substs ().at (0);
     891          102 :   auto param_ty = mapping.get_param_ty ();
     892          102 :   rust_assert (param_ty->can_resolve ());
     893          102 :   auto resolved = param_ty->resolve ();
     894          102 :   auto p = static_cast<TyTy::PlaceholderType *> (fntype->get_return_type ());
     895              : 
     896          102 :   TyTy::BaseType *return_type = nullptr;
     897          102 :   bool ok = ctx->get_tyctx ()->lookup_builtin ("isize", &return_type);
     898          102 :   rust_assert (ok);
     899              : 
     900          102 :   bool is_adt = resolved->is<TyTy::ADTType> ();
     901          102 :   bool is_enum = false;
     902          102 :   if (is_adt)
     903              :     {
     904          102 :       const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
     905          102 :       return_type = adt.get_repr_options ().repr;
     906          102 :       rust_assert (return_type != nullptr);
     907          102 :       is_enum = adt.is_enum ();
     908              :     }
     909              : 
     910          102 :   p->set_associated_type (return_type->get_ref ());
     911              : 
     912          102 :   tree lookup = NULL_TREE;
     913          102 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     914            0 :     return lookup;
     915              : 
     916          102 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     917              : 
     918          102 :   std::vector<Bvariable *> param_vars;
     919          102 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     920              : 
     921          102 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     922            0 :     return error_mark_node;
     923              : 
     924          102 :   enter_intrinsic_block (ctx, fndecl);
     925              : 
     926              :   // BUILTIN disriminant_value FN BODY BEGIN
     927              : 
     928          102 :   tree result = integer_zero_node;
     929          102 :   if (is_enum)
     930              :     {
     931          102 :       tree val = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
     932          102 :       tree deref = build_fold_indirect_ref_loc (UNKNOWN_LOCATION, val);
     933          102 :       result = Backend::struct_field_expression (deref, 0, UNKNOWN_LOCATION);
     934              :     }
     935              : 
     936          102 :   auto return_statement
     937          102 :     = Backend::return_statement (fndecl, result, BUILTINS_LOCATION);
     938          102 :   ctx->add_statement (return_statement);
     939              : 
     940              :   // BUILTIN disriminant_value FN BODY END
     941              : 
     942          102 :   finalize_intrinsic_block (ctx, fndecl);
     943              : 
     944          102 :   return fndecl;
     945          102 : }
     946              : 
     947              : tree
     948            7 : variant_count (Context *ctx, TyTy::FnType *fntype)
     949              : {
     950            7 :   rust_assert (fntype->get_num_type_params () == 1);
     951            7 :   auto &mapping = fntype->get_substs ().at (0);
     952            7 :   auto param_ty = mapping.get_param_ty ();
     953            7 :   rust_assert (param_ty->can_resolve ());
     954            7 :   auto resolved = param_ty->resolve ();
     955              : 
     956            7 :   size_t variant_count = 0;
     957            7 :   bool is_adt = resolved->is<TyTy::ADTType> ();
     958            7 :   if (is_adt)
     959              :     {
     960            7 :       const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
     961            7 :       variant_count = adt.number_of_variants ();
     962              :     }
     963              : 
     964            7 :   tree lookup = NULL_TREE;
     965            7 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
     966            0 :     return lookup;
     967              : 
     968            7 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
     969              : 
     970            7 :   std::vector<Bvariable *> param_vars;
     971            7 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
     972              : 
     973            7 :   if (!Backend::function_set_parameters (fndecl, param_vars))
     974            0 :     return error_mark_node;
     975              : 
     976            7 :   enter_intrinsic_block (ctx, fndecl);
     977              : 
     978              :   // BUILTIN disriminant_value FN BODY BEGIN
     979            7 :   tree result_decl = DECL_RESULT (fndecl);
     980            7 :   tree type = TREE_TYPE (result_decl);
     981              : 
     982            7 :   mpz_t ival;
     983            7 :   mpz_init_set_ui (ival, variant_count);
     984            7 :   tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
     985            7 :   mpz_clear (ival);
     986              : 
     987            7 :   auto return_statement
     988            7 :     = Backend::return_statement (fndecl, result, BUILTINS_LOCATION);
     989            7 :   ctx->add_statement (return_statement);
     990              : 
     991              :   // BUILTIN disriminant_value FN BODY END
     992              : 
     993            7 :   finalize_intrinsic_block (ctx, fndecl);
     994              : 
     995            7 :   return fndecl;
     996            7 : }
     997              : 
     998              : tree
     999           26 : move_val_init (Context *ctx, TyTy::FnType *fntype)
    1000              : {
    1001           26 :   rust_assert (fntype->get_params ().size () == 2);
    1002              : 
    1003           26 :   tree lookup = NULL_TREE;
    1004           26 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1005            0 :     return lookup;
    1006              : 
    1007           26 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1008              : 
    1009              :   // Most intrinsic functions are pure - not `move_val_init`
    1010           26 :   TREE_READONLY (fndecl) = 0;
    1011           26 :   TREE_SIDE_EFFECTS (fndecl) = 1;
    1012              : 
    1013              :   // get the template parameter type tree fn size_of<T>();
    1014           26 :   rust_assert (fntype->get_num_substitutions () == 1);
    1015           26 :   auto &param_mapping = fntype->get_substs ().at (0);
    1016           26 :   auto param_tyty = param_mapping.get_param_ty ();
    1017           26 :   auto resolved_tyty = param_tyty->resolve ();
    1018           26 :   tree template_parameter_type
    1019           26 :     = TyTyResolveCompile::compile (ctx, resolved_tyty);
    1020              : 
    1021           26 :   std::vector<Bvariable *> param_vars;
    1022           26 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
    1023              : 
    1024           26 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    1025            0 :     return error_mark_node;
    1026              : 
    1027           26 :   enter_intrinsic_block (ctx, fndecl);
    1028              : 
    1029              :   // BUILTIN size_of FN BODY BEGIN
    1030              : 
    1031           26 :   tree dst = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
    1032           26 :   tree src = Backend::var_expression (param_vars[1], UNDEF_LOCATION);
    1033           26 :   tree size = TYPE_SIZE_UNIT (template_parameter_type);
    1034              : 
    1035           26 :   tree memcpy_builtin = error_mark_node;
    1036           26 :   BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memcpy",
    1037              :                                                  &memcpy_builtin);
    1038           26 :   rust_assert (memcpy_builtin != error_mark_node);
    1039              : 
    1040           26 :   src = build_fold_addr_expr_loc (BUILTINS_LOCATION, src);
    1041           26 :   tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, memcpy_builtin, 3,
    1042              :                                           dst, src, size);
    1043              : 
    1044           26 :   ctx->add_statement (memset_call);
    1045              :   // BUILTIN size_of FN BODY END
    1046              : 
    1047           26 :   finalize_intrinsic_block (ctx, fndecl);
    1048              : 
    1049           26 :   return fndecl;
    1050           26 : }
    1051              : 
    1052              : tree
    1053           92 : uninit (Context *ctx, TyTy::FnType *fntype)
    1054              : {
    1055              :   // uninit has _zero_ parameters its parameter is the generic one
    1056           92 :   rust_assert (fntype->get_params ().size () == 0);
    1057              : 
    1058           92 :   tree lookup = NULL_TREE;
    1059           92 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1060            0 :     return lookup;
    1061              : 
    1062           92 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1063              : 
    1064              :   // Most intrinsic functions are pure - not `uninit_handler`
    1065           92 :   TREE_READONLY (fndecl) = 0;
    1066           92 :   TREE_SIDE_EFFECTS (fndecl) = 1;
    1067              : 
    1068              :   // get the template parameter type tree fn uninit<T>();
    1069           92 :   rust_assert (fntype->get_num_substitutions () == 1);
    1070           92 :   auto &param_mapping = fntype->get_substs ().at (0);
    1071           92 :   const auto param_tyty = param_mapping.get_param_ty ();
    1072           92 :   auto resolved_tyty = param_tyty->resolve ();
    1073           92 :   tree template_parameter_type
    1074           92 :     = TyTyResolveCompile::compile (ctx, resolved_tyty);
    1075              : 
    1076              :   // result temporary
    1077           92 :   tree dst_type = TREE_TYPE (DECL_RESULT (fndecl));
    1078           92 :   rust_assert (TYPE_SIZE_UNIT (template_parameter_type)
    1079              :                == TYPE_SIZE_UNIT (dst_type));
    1080              : 
    1081           92 :   tree tmp_stmt = error_mark_node;
    1082           92 :   Bvariable *bvar
    1083           92 :     = Backend::temporary_variable (fndecl, NULL_TREE, dst_type, NULL_TREE,
    1084              :                                    true /*address_is_taken*/, UNDEF_LOCATION,
    1085              :                                    &tmp_stmt);
    1086              : 
    1087           92 :   enter_intrinsic_block (ctx, fndecl, {bvar});
    1088              : 
    1089              :   // BUILTIN size_of FN BODY BEGIN
    1090              : 
    1091           92 :   tree memset_builtin = error_mark_node;
    1092           92 :   BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset",
    1093              :                                                  &memset_builtin);
    1094           92 :   rust_assert (memset_builtin != error_mark_node);
    1095              : 
    1096              :   // call memset with 0x01 and size of the thing see
    1097              :   // https://github.com/Rust-GCC/gccrs/issues/1899
    1098              : 
    1099           92 :   tree dst = bvar->get_tree (BUILTINS_LOCATION);
    1100           92 :   tree dst_addr = build_fold_addr_expr_loc (BUILTINS_LOCATION, dst);
    1101           92 :   tree constant_byte = build_int_cst (integer_type_node, 0x01);
    1102           92 :   tree size_expr = TYPE_SIZE_UNIT (template_parameter_type);
    1103              : 
    1104           92 :   tree memset_call = build_call_expr_loc (BUILTINS_LOCATION, memset_builtin, 3,
    1105              :                                           dst_addr, constant_byte, size_expr);
    1106           92 :   ctx->add_statement (memset_call);
    1107              : 
    1108           92 :   auto return_statement
    1109           92 :     = Backend::return_statement (fndecl, dst, UNDEF_LOCATION);
    1110           92 :   ctx->add_statement (return_statement);
    1111              :   // BUILTIN size_of FN BODY END
    1112              : 
    1113           92 :   finalize_intrinsic_block (ctx, fndecl);
    1114              : 
    1115           92 :   return fndecl;
    1116              : }
    1117              : 
    1118              : tree
    1119            7 : prefetch_read_data (Context *ctx, TyTy::FnType *fntype)
    1120              : {
    1121            7 :   return prefetch_data (ctx, fntype, Prefetch::Read);
    1122              : }
    1123              : tree
    1124            7 : prefetch_write_data (Context *ctx, TyTy::FnType *fntype)
    1125              : {
    1126            7 :   return prefetch_data (ctx, fntype, Prefetch::Write);
    1127              : }
    1128              : 
    1129              : tree
    1130           14 : prefetch_data (Context *ctx, TyTy::FnType *fntype, Prefetch kind)
    1131              : {
    1132           14 :   rust_assert (fntype->get_params ().size () == 2);
    1133              : 
    1134           14 :   tree lookup = NULL_TREE;
    1135           14 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1136            0 :     return lookup;
    1137              : 
    1138           14 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1139              : 
    1140              :   // prefetching isn't pure and shouldn't be discarded after GIMPLE
    1141           14 :   TREE_READONLY (fndecl) = 0;
    1142           14 :   TREE_SIDE_EFFECTS (fndecl) = 1;
    1143              : 
    1144           14 :   std::vector<Bvariable *> args;
    1145           14 :   compile_fn_params (ctx, fntype, fndecl, &args);
    1146              : 
    1147           14 :   if (!Backend::function_set_parameters (fndecl, args))
    1148            0 :     return error_mark_node;
    1149              : 
    1150           14 :   enter_intrinsic_block (ctx, fndecl);
    1151              : 
    1152           14 :   auto addr = Backend::var_expression (args[0], UNDEF_LOCATION);
    1153              : 
    1154              :   // The core library technically allows you to pass any i32 value as a
    1155              :   // locality, but LLVM will then complain if the value cannot be constant
    1156              :   // evaluated. For now, we ignore the locality argument and instead always
    1157              :   // pass `3` (the most restrictive value). This allows us to still have
    1158              :   // prefetch behavior, just not as granular as expected. In future Rust
    1159              :   // versions, we hope that prefetch intrinsics will be split up according to
    1160              :   // locality, similarly to atomic intrinsics.
    1161              :   // The solution is to try and perform constant folding for the locality
    1162              :   // argument, or instead of creating a new function definition, modify the call
    1163              :   // site directly This has the bad side-effect of creating warnings about
    1164              :   // `unused name - locality`, which we hack away here:
    1165              :   // TODO: Take care of handling locality properly
    1166           14 :   Backend::var_expression (args[1], UNDEF_LOCATION);
    1167              : 
    1168           14 :   auto rw_flag = make_unsigned_long_tree (kind == Prefetch::Write ? 1 : 0);
    1169              : 
    1170           14 :   auto prefetch_raw = NULL_TREE;
    1171           14 :   auto ok = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_prefetch",
    1172              :                                                            &prefetch_raw);
    1173           14 :   rust_assert (ok);
    1174           14 :   auto prefetch = build_fold_addr_expr_loc (UNKNOWN_LOCATION, prefetch_raw);
    1175              : 
    1176           28 :   auto prefetch_call = Backend::call_expression (prefetch,
    1177              :                                                  {addr, rw_flag,
    1178              :                                                   // locality arg
    1179           14 :                                                   make_unsigned_long_tree (3)},
    1180              :                                                  nullptr, UNDEF_LOCATION);
    1181              : 
    1182           14 :   TREE_READONLY (prefetch_call) = 0;
    1183           14 :   TREE_SIDE_EFFECTS (prefetch_call) = 1;
    1184              : 
    1185           14 :   ctx->add_statement (prefetch_call);
    1186              : 
    1187           14 :   finalize_intrinsic_block (ctx, fndecl);
    1188              : 
    1189           14 :   return fndecl;
    1190           14 : }
    1191              : 
    1192              : tree
    1193          353 : rotate (Context *ctx, TyTy::FnType *fntype, tree_code op)
    1194              : {
    1195              :   // rotate intrinsic has two parameter
    1196          353 :   rust_assert (fntype->get_params ().size () == 2);
    1197              : 
    1198          353 :   tree lookup = NULL_TREE;
    1199          353 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1200            0 :     return lookup;
    1201              : 
    1202          353 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1203              : 
    1204              :   // setup the params
    1205          353 :   std::vector<Bvariable *> param_vars;
    1206          353 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
    1207              : 
    1208          353 :   auto &x_param = param_vars.at (0);
    1209          353 :   auto &y_param = param_vars.at (1);
    1210          353 :   rust_assert (param_vars.size () == 2);
    1211          353 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    1212            0 :     return error_mark_node;
    1213              : 
    1214          353 :   enter_intrinsic_block (ctx, fndecl);
    1215              : 
    1216              :   // BUILTIN rotate FN BODY BEGIN
    1217          353 :   tree x = Backend::var_expression (x_param, UNDEF_LOCATION);
    1218          353 :   tree y = Backend::var_expression (y_param, UNDEF_LOCATION);
    1219          353 :   tree rotate_expr
    1220          353 :     = fold_build2_loc (BUILTINS_LOCATION, op, TREE_TYPE (x), x, y);
    1221          353 :   auto return_statement
    1222          353 :     = Backend::return_statement (fndecl, rotate_expr, UNDEF_LOCATION);
    1223          353 :   ctx->add_statement (return_statement);
    1224              :   // BUILTIN rotate FN BODY END
    1225              : 
    1226          353 :   finalize_intrinsic_block (ctx, fndecl);
    1227              : 
    1228          353 :   return fndecl;
    1229          353 : }
    1230              : 
    1231              : tree
    1232          191 : transmute (Context *ctx, TyTy::FnType *fntype)
    1233              : {
    1234              :   // transmute intrinsic has one parameter
    1235          191 :   rust_assert (fntype->get_params ().size () == 1);
    1236              : 
    1237          191 :   tree lookup = NULL_TREE;
    1238          191 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1239            0 :     return lookup;
    1240              : 
    1241          191 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1242              : 
    1243          191 :   std::vector<Bvariable *> param_vars;
    1244          191 :   std::vector<tree_node *> compiled_types;
    1245          191 :   compile_fn_params (ctx, fntype, fndecl, &param_vars, &compiled_types);
    1246              : 
    1247          191 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    1248            0 :     return error_mark_node;
    1249              : 
    1250              :   // param to convert
    1251          191 :   Bvariable *convert_me_param = param_vars.at (0);
    1252          191 :   tree convert_me_expr
    1253          191 :     = Backend::var_expression (convert_me_param, UNDEF_LOCATION);
    1254              : 
    1255              :   // check for transmute pre-conditions
    1256          191 :   tree target_type_expr = TREE_TYPE (DECL_RESULT (fndecl));
    1257          191 :   tree source_type_expr = compiled_types.at (0);
    1258          191 :   tree target_size_expr = TYPE_SIZE (target_type_expr);
    1259          191 :   tree source_size_expr = TYPE_SIZE (source_type_expr);
    1260              :   // for some reason, unit types and other zero-sized types return NULL for the
    1261              :   // size expressions
    1262          191 :   unsigned HOST_WIDE_INT target_size
    1263          191 :     = target_size_expr ? TREE_INT_CST_LOW (target_size_expr) : 0;
    1264          191 :   unsigned HOST_WIDE_INT source_size
    1265          191 :     = source_size_expr ? TREE_INT_CST_LOW (source_size_expr) : 0;
    1266              : 
    1267              :   // size check for concrete types
    1268              :   // TODO(liushuyu): check alignment for pointers; check for dependently-sized
    1269              :   // types
    1270          191 :   if (target_size != source_size)
    1271              :     {
    1272            7 :       rust_error_at (fntype->get_locus (),
    1273              :                      "cannot transmute between types of different sizes, or "
    1274              :                      "dependently-sized types");
    1275           14 :       rust_inform (
    1276            7 :         fntype->get_ident ().locus, "source type: %qs (%lu bits)",
    1277            7 :         fntype->get_params ().at (0).get_type ()->as_string ().c_str (),
    1278              :         (unsigned long) source_size);
    1279            7 :       rust_inform (fntype->get_ident ().locus, "target type: %qs (%lu bits)",
    1280           14 :                    fntype->get_return_type ()->as_string ().c_str (),
    1281              :                    (unsigned long) target_size);
    1282              :     }
    1283              : 
    1284          191 :   enter_intrinsic_block (ctx, fndecl);
    1285              : 
    1286              :   // BUILTIN transmute FN BODY BEGIN
    1287              : 
    1288              :   // Return *((orig_type*)&decl)  */
    1289              : 
    1290          191 :   tree t = build_fold_addr_expr_loc (UNKNOWN_LOCATION, convert_me_expr);
    1291          191 :   t = fold_build1_loc (UNKNOWN_LOCATION, NOP_EXPR,
    1292              :                        build_pointer_type (target_type_expr), t);
    1293          191 :   tree result_expr = build_fold_indirect_ref_loc (UNKNOWN_LOCATION, t);
    1294              : 
    1295          191 :   auto return_statement
    1296          191 :     = Backend::return_statement (fndecl, result_expr, UNDEF_LOCATION);
    1297          191 :   ctx->add_statement (return_statement);
    1298              :   // BUILTIN transmute FN BODY END
    1299              : 
    1300          191 :   finalize_intrinsic_block (ctx, fndecl);
    1301              : 
    1302          191 :   return fndecl;
    1303          191 : }
    1304              : 
    1305              : tree
    1306          474 : sizeof_handler (Context *ctx, TyTy::FnType *fntype)
    1307              : {
    1308              :   // size_of has _zero_ parameters its parameter is the generic one
    1309          474 :   rust_assert (fntype->get_params ().size () == 0);
    1310              : 
    1311          474 :   tree lookup = NULL_TREE;
    1312          474 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1313            0 :     return lookup;
    1314              : 
    1315          474 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1316              : 
    1317              :   // get the template parameter type tree fn size_of<T>();
    1318          474 :   rust_assert (fntype->get_num_substitutions () == 1);
    1319          474 :   auto &param_mapping = fntype->get_substs ().at (0);
    1320          474 :   const auto param_tyty = param_mapping.get_param_ty ();
    1321          474 :   auto resolved_tyty = param_tyty->resolve ();
    1322          474 :   tree template_parameter_type
    1323          474 :     = TyTyResolveCompile::compile (ctx, resolved_tyty);
    1324              : 
    1325          474 :   enter_intrinsic_block (ctx, fndecl);
    1326              : 
    1327              :   // BUILTIN size_of FN BODY BEGIN
    1328          474 :   tree size_expr = TYPE_SIZE_UNIT (template_parameter_type);
    1329          474 :   auto return_statement
    1330          474 :     = Backend::return_statement (fndecl, size_expr, UNDEF_LOCATION);
    1331          474 :   ctx->add_statement (return_statement);
    1332              :   // BUILTIN size_of FN BODY END
    1333              : 
    1334          474 :   finalize_intrinsic_block (ctx, fndecl);
    1335              : 
    1336          474 :   return fndecl;
    1337              : }
    1338              : 
    1339              : tree
    1340           72 : offset (Context *ctx, TyTy::FnType *fntype)
    1341              : {
    1342              :   // offset intrinsic has two params dst pointer and offset isize
    1343           72 :   rust_assert (fntype->get_params ().size () == 2);
    1344              : 
    1345           72 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1346              : 
    1347           72 :   std::vector<Bvariable *> param_vars;
    1348           72 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
    1349              : 
    1350           72 :   auto &dst_param = param_vars.at (0);
    1351           72 :   auto &size_param = param_vars.at (1);
    1352           72 :   rust_assert (param_vars.size () == 2);
    1353           72 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    1354            0 :     return error_mark_node;
    1355              : 
    1356           72 :   enter_intrinsic_block (ctx, fndecl);
    1357              : 
    1358              :   // BUILTIN offset FN BODY BEGIN
    1359           72 :   tree dst = Backend::var_expression (dst_param, UNDEF_LOCATION);
    1360           72 :   tree size = Backend::var_expression (size_param, UNDEF_LOCATION);
    1361           72 :   tree pointer_offset_expr
    1362           72 :     = pointer_offset_expression (dst, size, BUILTINS_LOCATION);
    1363           72 :   auto return_statement
    1364           72 :     = Backend::return_statement (fndecl, pointer_offset_expr, UNDEF_LOCATION);
    1365           72 :   ctx->add_statement (return_statement);
    1366              :   // BUILTIN offset FN BODY END
    1367              : 
    1368           72 :   finalize_intrinsic_block (ctx, fndecl);
    1369              : 
    1370           72 :   return fndecl;
    1371           72 : }
    1372              : 
    1373              : /**
    1374              :  * pub const fn bswap<T: Copy>(x: T) -> T;
    1375              :  */
    1376              : tree
    1377            9 : bswap_handler (Context *ctx, TyTy::FnType *fntype)
    1378              : {
    1379            9 :   rust_assert (fntype->get_params ().size () == 1);
    1380              : 
    1381            9 :   tree lookup = NULL_TREE;
    1382            9 :   if (check_for_cached_intrinsic (ctx, fntype, &lookup))
    1383            0 :     return lookup;
    1384              : 
    1385            9 :   auto fndecl = compile_intrinsic_function (ctx, fntype);
    1386              : 
    1387            9 :   auto locus = fntype->get_locus ();
    1388              : 
    1389            9 :   std::vector<Bvariable *> param_vars;
    1390            9 :   compile_fn_params (ctx, fntype, fndecl, &param_vars);
    1391              : 
    1392            9 :   auto &x_param = param_vars.at (0);
    1393            9 :   rust_assert (param_vars.size () == 1);
    1394            9 :   if (!Backend::function_set_parameters (fndecl, param_vars))
    1395            0 :     return error_mark_node;
    1396              : 
    1397            9 :   auto *monomorphized_type
    1398            9 :     = fntype->get_substs ().at (0).get_param_ty ()->resolve ();
    1399              : 
    1400            9 :   check_for_basic_integer_type ("bswap", fntype->get_locus (),
    1401              :                                 monomorphized_type);
    1402              : 
    1403            9 :   tree template_parameter_type
    1404            9 :     = TyTyResolveCompile::compile (ctx, monomorphized_type);
    1405              : 
    1406            9 :   tree size_expr = TYPE_SIZE_UNIT (template_parameter_type);
    1407            9 :   unsigned HOST_WIDE_INT size = TREE_INT_CST_LOW (size_expr);
    1408              : 
    1409            9 :   enter_intrinsic_block (ctx, fndecl);
    1410              : 
    1411              :   // BUILTIN bswap FN BODY BEGIN
    1412              : 
    1413            9 :   auto expr_x = Backend::var_expression (x_param, locus);
    1414            9 :   tree result = NULL_TREE;
    1415              : 
    1416            9 :   if (size == 1)
    1417              :     {
    1418              :       result = expr_x;
    1419              :     }
    1420              :   else
    1421              :     {
    1422            8 :       tree target_type = NULL_TREE;
    1423            8 :       const char *builtin_name = nullptr;
    1424            8 :       switch (size)
    1425              :         {
    1426            2 :         case 2:
    1427            2 :           builtin_name = "__builtin_bswap16";
    1428            2 :           target_type = uint16_type_node;
    1429            2 :           break;
    1430            2 :         case 4:
    1431            2 :           builtin_name = "__builtin_bswap32";
    1432            2 :           target_type = uint32_type_node;
    1433            2 :           break;
    1434            2 :         case 8:
    1435            2 :           builtin_name = "__builtin_bswap64";
    1436            2 :           target_type = uint64_type_node;
    1437            2 :           break;
    1438            2 :         case 16:
    1439            2 :           builtin_name = "__builtin_bswap128";
    1440            2 :           target_type = uint128_type_node;
    1441            2 :           break;
    1442            0 :         default:
    1443            0 :           return error_mark_node;
    1444              :         }
    1445              : 
    1446            8 :       tree bswap_raw = nullptr;
    1447            8 :       auto ok = BuiltinsContext::get ().lookup_simple_builtin (builtin_name,
    1448              :                                                                &bswap_raw);
    1449              : 
    1450            8 :       if (ok)
    1451              :         {
    1452            8 :           tree bswap_fn = build_fold_addr_expr_loc (locus, bswap_raw);
    1453              : 
    1454            8 :           auto bswap_x = build1 (CONVERT_EXPR, target_type, expr_x);
    1455              : 
    1456            8 :           auto bswap_call
    1457            8 :             = Backend::call_expression (bswap_fn, {bswap_x}, NULL_TREE, locus);
    1458              : 
    1459            8 :           result = build1 (CONVERT_EXPR, template_parameter_type, bswap_call);
    1460              :         }
    1461              :       else
    1462              :         {
    1463            0 :           auto ok2 = BuiltinsContext::get ().lookup_simple_builtin (
    1464            0 :             "__builtin_bswap64", &bswap_raw);
    1465            0 :           rust_assert (ok2);
    1466              : 
    1467            0 :           tree bswap_fn = build_fold_addr_expr_loc (locus, bswap_raw);
    1468              : 
    1469            0 :           tree tmp_in_stmt = error_mark_node;
    1470            0 :           Bvariable *in_var
    1471            0 :             = Backend::temporary_variable (fndecl, NULL_TREE,
    1472              :                                            template_parameter_type, expr_x,
    1473              :                                            true, locus, &tmp_in_stmt);
    1474            0 :           ctx->add_statement (tmp_in_stmt);
    1475              : 
    1476            0 :           tree addr_x
    1477            0 :             = build_fold_addr_expr_loc (locus, in_var->get_tree (locus));
    1478            0 :           tree u64_ptr_type = build_pointer_type (uint64_type_node);
    1479              : 
    1480            0 :           tree low_ptr = fold_convert (u64_ptr_type, addr_x);
    1481            0 :           tree low = build_fold_indirect_ref_loc (locus, low_ptr);
    1482              : 
    1483            0 :           tree high_ptr = fold_build2 (POINTER_PLUS_EXPR, u64_ptr_type, low_ptr,
    1484              :                                        size_int (8));
    1485            0 :           tree high = build_fold_indirect_ref_loc (locus, high_ptr);
    1486              : 
    1487            0 :           auto new_high
    1488            0 :             = Backend::call_expression (bswap_fn, {low}, NULL_TREE, locus);
    1489            0 :           auto new_low
    1490            0 :             = Backend::call_expression (bswap_fn, {high}, NULL_TREE, locus);
    1491              : 
    1492            0 :           tree tmp_stmt = error_mark_node;
    1493            0 :           Bvariable *result_var
    1494            0 :             = Backend::temporary_variable (fndecl, NULL_TREE,
    1495              :                                            template_parameter_type, NULL_TREE,
    1496              :                                            true, locus, &tmp_stmt);
    1497            0 :           ctx->add_statement (tmp_stmt);
    1498              : 
    1499            0 :           tree addr_res
    1500            0 :             = build_fold_addr_expr_loc (locus, result_var->get_tree (locus));
    1501            0 :           tree res_ptr = fold_convert (u64_ptr_type, addr_res);
    1502              : 
    1503            0 :           tree store_low
    1504            0 :             = build2 (MODIFY_EXPR, void_type_node,
    1505              :                       build_fold_indirect_ref_loc (locus, res_ptr), new_low);
    1506            0 :           ctx->add_statement (store_low);
    1507              : 
    1508            0 :           tree res_high_ptr = fold_build2 (POINTER_PLUS_EXPR, u64_ptr_type,
    1509              :                                            res_ptr, size_int (8));
    1510            0 :           tree store_high
    1511            0 :             = build2 (MODIFY_EXPR, void_type_node,
    1512              :                       build_fold_indirect_ref_loc (locus, res_high_ptr),
    1513              :                       new_high);
    1514            0 :           ctx->add_statement (store_high);
    1515              : 
    1516            0 :           result = result_var->get_tree (locus);
    1517              :         }
    1518              :     }
    1519              : 
    1520            9 :   auto return_statement = Backend::return_statement (fndecl, result, locus);
    1521              : 
    1522            9 :   TREE_READONLY (result) = 1;
    1523              : 
    1524            9 :   ctx->add_statement (return_statement);
    1525              : 
    1526              :   // BUILTIN bswap FN BODY END
    1527              : 
    1528            9 :   finalize_intrinsic_block (ctx, fndecl);
    1529              : 
    1530            9 :   return fndecl;
    1531            9 : }
    1532              : 
    1533              : } // namespace handlers
    1534              : } // namespace Compile
    1535              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.