LCOV - code coverage report
Current view: top level - gcc/rust/backend - rust-compile-intrinsic.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 89.0 % 718 639
Test Date: 2026-02-28 14:20:25 Functions: 95.0 % 40 38
Legend: Lines:     hit not hit

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