aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-intrinsic.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend/rust-compile-intrinsic.cc')
-rw-r--r--gcc/rust/backend/rust-compile-intrinsic.cc205
1 files changed, 160 insertions, 45 deletions
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc
index 0f05458..fb0c661 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -17,7 +17,6 @@
#include "rust-compile-intrinsic.h"
#include "rust-compile-context.h"
#include "rust-compile-type.h"
-#include "rust-compile-expr.h"
#include "rust-compile-fnparam.h"
#include "rust-builtins.h"
#include "rust-diagnostics.h"
@@ -27,14 +26,10 @@
#include "rust-tree.h"
#include "tree-core.h"
#include "rust-gcc.h"
-#include "print-tree.h"
#include "fold-const.h"
#include "langhooks.h"
-#include "rust-gcc.h"
#include "rust-constexpr.h"
-#include "print-tree.h"
-
// declaration taken from "stringpool.h"
// the get_identifier macro causes compilation issues
extern tree
@@ -93,6 +88,10 @@ static tree
move_val_init_handler (Context *ctx, TyTy::FnType *fntype);
static tree
assume_handler (Context *ctx, TyTy::FnType *fntype);
+static tree
+discriminant_value_handler (Context *ctx, TyTy::FnType *fntype);
+static tree
+variant_count_handler (Context *ctx, TyTy::FnType *fntype);
enum class Prefetch
{
@@ -217,45 +216,46 @@ sorry_handler (Context *ctx, TyTy::FnType *fntype)
static const std::map<std::string,
std::function<tree (Context *, TyTy::FnType *)>>
- generic_intrinsics = {
- {"offset", offset_handler},
- {"size_of", sizeof_handler},
- {"transmute", transmute_handler},
- {"rotate_left", rotate_left_handler},
- {"rotate_right", rotate_right_handler},
- {"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
- {"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
- {"wrapping_mul", wrapping_op_handler (MULT_EXPR)},
- {"add_with_overflow", op_with_overflow (PLUS_EXPR)},
- {"sub_with_overflow", op_with_overflow (MINUS_EXPR)},
- {"mul_with_overflow", op_with_overflow (MULT_EXPR)},
- {"copy", copy_handler (true)},
- {"copy_nonoverlapping", copy_handler (false)},
- {"prefetch_read_data", prefetch_read_data},
- {"prefetch_write_data", prefetch_write_data},
- {"atomic_store_seqcst", atomic_store_handler (__ATOMIC_SEQ_CST)},
- {"atomic_store_release", atomic_store_handler (__ATOMIC_RELEASE)},
- {"atomic_store_relaxed", atomic_store_handler (__ATOMIC_RELAXED)},
- {"atomic_store_unordered", atomic_store_handler (__ATOMIC_RELAXED)},
- {"atomic_load_seqcst", atomic_load_handler (__ATOMIC_SEQ_CST)},
- {"atomic_load_acquire", atomic_load_handler (__ATOMIC_ACQUIRE)},
- {"atomic_load_relaxed", atomic_load_handler (__ATOMIC_RELAXED)},
- {"atomic_load_unordered", atomic_load_handler (__ATOMIC_RELAXED)},
- {"unchecked_add", unchecked_op_handler (PLUS_EXPR)},
- {"unchecked_sub", unchecked_op_handler (MINUS_EXPR)},
- {"unchecked_mul", unchecked_op_handler (MULT_EXPR)},
- {"unchecked_div", unchecked_op_handler (TRUNC_DIV_EXPR)},
- {"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)},
- {"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)},
- {"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)},
- {"uninit", uninit_handler},
- {"move_val_init", move_val_init_handler},
- {"likely", expect_handler (true)},
- {"unlikely", expect_handler (false)},
- {"assume", assume_handler},
- {"try", try_handler (false)},
- {"catch_unwind", try_handler (true)},
-};
+ generic_intrinsics
+ = {{"offset", offset_handler},
+ {"size_of", sizeof_handler},
+ {"transmute", transmute_handler},
+ {"rotate_left", rotate_left_handler},
+ {"rotate_right", rotate_right_handler},
+ {"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
+ {"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
+ {"wrapping_mul", wrapping_op_handler (MULT_EXPR)},
+ {"add_with_overflow", op_with_overflow (PLUS_EXPR)},
+ {"sub_with_overflow", op_with_overflow (MINUS_EXPR)},
+ {"mul_with_overflow", op_with_overflow (MULT_EXPR)},
+ {"copy", copy_handler (true)},
+ {"copy_nonoverlapping", copy_handler (false)},
+ {"prefetch_read_data", prefetch_read_data},
+ {"prefetch_write_data", prefetch_write_data},
+ {"atomic_store_seqcst", atomic_store_handler (__ATOMIC_SEQ_CST)},
+ {"atomic_store_release", atomic_store_handler (__ATOMIC_RELEASE)},
+ {"atomic_store_relaxed", atomic_store_handler (__ATOMIC_RELAXED)},
+ {"atomic_store_unordered", atomic_store_handler (__ATOMIC_RELAXED)},
+ {"atomic_load_seqcst", atomic_load_handler (__ATOMIC_SEQ_CST)},
+ {"atomic_load_acquire", atomic_load_handler (__ATOMIC_ACQUIRE)},
+ {"atomic_load_relaxed", atomic_load_handler (__ATOMIC_RELAXED)},
+ {"atomic_load_unordered", atomic_load_handler (__ATOMIC_RELAXED)},
+ {"unchecked_add", unchecked_op_handler (PLUS_EXPR)},
+ {"unchecked_sub", unchecked_op_handler (MINUS_EXPR)},
+ {"unchecked_mul", unchecked_op_handler (MULT_EXPR)},
+ {"unchecked_div", unchecked_op_handler (TRUNC_DIV_EXPR)},
+ {"unchecked_rem", unchecked_op_handler (TRUNC_MOD_EXPR)},
+ {"unchecked_shl", unchecked_op_handler (LSHIFT_EXPR)},
+ {"unchecked_shr", unchecked_op_handler (RSHIFT_EXPR)},
+ {"uninit", uninit_handler},
+ {"move_val_init", move_val_init_handler},
+ {"likely", expect_handler (true)},
+ {"unlikely", expect_handler (false)},
+ {"assume", assume_handler},
+ {"try", try_handler (false)},
+ {"catch_unwind", try_handler (true)},
+ {"discriminant_value", discriminant_value_handler},
+ {"variant_count", variant_count_handler}};
Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
@@ -1273,7 +1273,7 @@ assume_handler (Context *ctx, TyTy::FnType *fntype)
TREE_SIDE_EFFECTS (assume_expr) = 1;
ctx->add_statement (assume_expr);
- // BUILTIN size_of FN BODY END
+ // BUILTIN assume FN BODY END
finalize_intrinsic_block (ctx, fndecl);
@@ -1375,5 +1375,120 @@ try_handler_inner (Context *ctx, TyTy::FnType *fntype, bool is_new_api)
return fndecl;
}
+static tree
+discriminant_value_handler (Context *ctx, TyTy::FnType *fntype)
+{
+ rust_assert (fntype->get_params ().size () == 1);
+ rust_assert (fntype->get_return_type ()->is<TyTy::PlaceholderType> ());
+ rust_assert (fntype->has_substitutions ());
+ rust_assert (fntype->get_num_type_params () == 1);
+ auto &mapping = fntype->get_substs ().at (0);
+ auto param_ty = mapping.get_param_ty ();
+ rust_assert (param_ty->can_resolve ());
+ auto resolved = param_ty->resolve ();
+ auto p = static_cast<TyTy::PlaceholderType *> (fntype->get_return_type ());
+
+ TyTy::BaseType *return_type = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_builtin ("isize", &return_type);
+ rust_assert (ok);
+
+ bool is_adt = resolved->is<TyTy::ADTType> ();
+ bool is_enum = false;
+ if (is_adt)
+ {
+ const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
+ return_type = adt.get_repr_options ().repr;
+ rust_assert (return_type != nullptr);
+ is_enum = adt.is_enum ();
+ }
+
+ p->set_associated_type (return_type->get_ref ());
+
+ tree lookup = NULL_TREE;
+ if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+ return lookup;
+
+ auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+ std::vector<Bvariable *> param_vars;
+ compile_fn_params (ctx, fntype, fndecl, &param_vars);
+
+ if (!Backend::function_set_parameters (fndecl, param_vars))
+ return error_mark_node;
+
+ enter_intrinsic_block (ctx, fndecl);
+
+ // BUILTIN disriminant_value FN BODY BEGIN
+
+ tree result = integer_zero_node;
+ if (is_enum)
+ {
+ tree val = Backend::var_expression (param_vars[0], UNDEF_LOCATION);
+ tree deref = build_fold_indirect_ref_loc (UNKNOWN_LOCATION, val);
+ result = Backend::struct_field_expression (deref, 0, UNKNOWN_LOCATION);
+ }
+
+ auto return_statement
+ = Backend::return_statement (fndecl, result, BUILTINS_LOCATION);
+ ctx->add_statement (return_statement);
+
+ // BUILTIN disriminant_value FN BODY END
+
+ finalize_intrinsic_block (ctx, fndecl);
+
+ return fndecl;
+}
+
+static tree
+variant_count_handler (Context *ctx, TyTy::FnType *fntype)
+{
+ rust_assert (fntype->get_num_type_params () == 1);
+ auto &mapping = fntype->get_substs ().at (0);
+ auto param_ty = mapping.get_param_ty ();
+ rust_assert (param_ty->can_resolve ());
+ auto resolved = param_ty->resolve ();
+
+ size_t variant_count = 0;
+ bool is_adt = resolved->is<TyTy::ADTType> ();
+ if (is_adt)
+ {
+ const auto &adt = *static_cast<TyTy::ADTType *> (resolved);
+ variant_count = adt.number_of_variants ();
+ }
+
+ tree lookup = NULL_TREE;
+ if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+ return lookup;
+
+ auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+ std::vector<Bvariable *> param_vars;
+ compile_fn_params (ctx, fntype, fndecl, &param_vars);
+
+ if (!Backend::function_set_parameters (fndecl, param_vars))
+ return error_mark_node;
+
+ enter_intrinsic_block (ctx, fndecl);
+
+ // BUILTIN disriminant_value FN BODY BEGIN
+ tree result_decl = DECL_RESULT (fndecl);
+ tree type = TREE_TYPE (result_decl);
+
+ mpz_t ival;
+ mpz_init_set_ui (ival, variant_count);
+ tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
+ mpz_clear (ival);
+
+ auto return_statement
+ = Backend::return_statement (fndecl, result, BUILTINS_LOCATION);
+ ctx->add_statement (return_statement);
+
+ // BUILTIN disriminant_value FN BODY END
+
+ finalize_intrinsic_block (ctx, fndecl);
+
+ return fndecl;
+}
+
} // namespace Compile
} // namespace Rust