]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: add variant_count intrinsic
authorPhilip Herron <herron.philip@googlemail.com>
Tue, 11 Feb 2025 17:42:24 +0000 (17:42 +0000)
committerArthur Cohen <arthur.cohen@embecosm.com>
Mon, 24 Mar 2025 12:07:04 +0000 (13:07 +0100)
Addresses Rust-GCC#3348

gcc/rust/ChangeLog:

* backend/rust-compile-intrinsic.cc (variant_count_handler): new intrinsic

gcc/testsuite/ChangeLog:

* rust/execute/torture/enum_intrinsics2.rs: New test.

Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/backend/rust-compile-intrinsic.cc
gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs [new file with mode: 0644]

index 1f93e82a93a95ba98e191a34dd44961f4b4d0a49..28c69d50b462816c0bf9b07e10ac82a7745adbea 100644 (file)
@@ -90,6 +90,8 @@ 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
 {
@@ -252,7 +254,8 @@ static const std::map<std::string,
      {"assume", assume_handler},
      {"try", try_handler (false)},
      {"catch_unwind", try_handler (true)},
-     {"discriminant_value", discriminant_value_handler}};
+     {"discriminant_value", discriminant_value_handler},
+     {"variant_count", variant_count_handler}};
 
 Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
 
@@ -1436,5 +1439,56 @@ discriminant_value_handler (Context *ctx, TyTy::FnType *fntype)
   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
diff --git a/gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs b/gcc/testsuite/rust/execute/torture/enum_intrinsics2.rs
new file mode 100644 (file)
index 0000000..c1bae35
--- /dev/null
@@ -0,0 +1,25 @@
+#![feature(intrinsics)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+enum BookFormat {
+    Paperback,
+    Hardback,
+    Ebook,
+}
+
+mod core {
+    mod intrinsics {
+        extern "rust-intrinsic" {
+            #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
+            pub fn variant_count<T>() -> usize;
+        }
+    }
+}
+
+pub fn main() -> i32 {
+    let count = core::intrinsics::variant_count::<BookFormat>();
+
+    (count as i32) - 3
+}