From: Enes Cevik <[email protected]>

This patch implements the 'write_bytes' compiler intrinsic. It performs
a write operation to memory using '__builtin_memset'.

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc (generic_intrinsics): Add
        write_bytes handler to map.
        * backend/rust-intrinsic-handlers.cc (write_bytes_handler): New
        function.
        * backend/rust-intrinsic-handlers.h (write_bytes_handler): New
        declaration.
        * typecheck/rust-hir-type-check-intrinsic.cc
        (IntrinsicChecker::intrinsic_rules): Add write_bytes rule.
        * util/rust-intrinsic-values.h (class Intrinsics): Add
        WRITE_BYTES constexpr.

gcc/testsuite/ChangeLog:

        * rust/execute/write-bytes.rs: New test.

Signed-off-by: Enes Cevik <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/bfa07ecd56171c68da6ba987ab490dbddb7c3fec

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4620

 gcc/rust/backend/rust-compile-intrinsic.cc    |  1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 70 +++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h    |  3 +
 .../rust-hir-type-check-intrinsic.cc          |  5 ++
 gcc/rust/util/rust-intrinsic-values.h         |  1 +
 gcc/testsuite/rust/execute/write-bytes.rs     | 17 +++++
 6 files changed, 97 insertions(+)
 create mode 100644 gcc/testsuite/rust/execute/write-bytes.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index a00b2a50e..51531de3c 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -29,6 +29,7 @@ using IValue = Values::Intrinsics;
 
 static const std::map<std::string, handlers::HandlerBuilder> generic_intrinsics
   = {{IValue::OFFSET, handlers::offset},
+     {IValue::WRITE_BYTES, handlers::write_bytes_handler},
      {IValue::SIZE_OF, handlers::sizeof_handler},
      {IValue::MIN_ALIGN_OF, handlers::min_align_of_handler},
      {IValue::TRANSMUTE, handlers::transmute},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc 
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 8ea93d7f7..24f831ec7 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1865,6 +1865,76 @@ cttz_nonzero_handler (Context *ctx, TyTy::FnType 
*fntype, location_t)
   return inner::cttz_handler (ctx, fntype, true);
 }
 
+/**
+ * pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+ */
+tree
+write_bytes_handler (Context *ctx, TyTy::FnType *fntype, location_t)
+{
+  rust_assert (fntype->get_params ().size () == 3);
+
+  tree lookup = NULL_TREE;
+  if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+    return lookup;
+
+  tree fndecl = compile_intrinsic_function (ctx, fntype);
+
+  auto locus = fntype->get_locus ();
+
+  std::vector<Bvariable *> param_vars;
+  compile_fn_params (ctx, fntype, fndecl, &param_vars);
+
+  auto &dst_param = param_vars.at (0);
+  auto &val_param = param_vars.at (1);
+  auto &count_param = param_vars.at (2);
+  rust_assert (param_vars.size () == 3);
+  if (!Backend::function_set_parameters (fndecl, param_vars))
+    return error_mark_node;
+
+  auto *monomorphized_type
+    = fntype->get_substs ().at (0).get_param_ty ()->resolve ();
+
+  tree template_parameter_type
+    = TyTyResolveCompile::compile (ctx, monomorphized_type);
+  tree dst_size_expr = TYPE_SIZE_UNIT (template_parameter_type);
+  rust_assert (dst_size_expr != NULL_TREE);
+
+  enter_intrinsic_block (ctx, fndecl);
+
+  // BUILTIN WRITE_BYTES FN BODY START
+
+  tree expr_dst = Backend::var_expression (dst_param, locus);
+  tree expr_val = Backend::var_expression (val_param, locus);
+  tree expr_count = Backend::var_expression (count_param, locus);
+
+  tree expr_count_final
+    = fold_build2_loc (locus, MULT_EXPR, size_type_node,
+                      fold_convert_loc (locus, size_type_node, expr_count),
+                      fold_convert_loc (locus, size_type_node, dst_size_expr));
+
+  tree write_bytes_raw = nullptr;
+  // void* memset( void* dest, int ch, size_t count );
+  bool ok = BuiltinsContext::get ().lookup_simple_builtin ("__builtin_memset",
+                                                          &write_bytes_raw);
+  rust_assert (ok);
+
+  tree write_bytes_fn = build_fold_addr_expr_loc (locus, write_bytes_raw);
+  tree write_bytes_call
+    = Backend::call_expression (write_bytes_fn,
+                               {expr_dst, expr_val, expr_count_final},
+                               NULL_TREE, locus);
+
+  ctx->add_statement (write_bytes_call);
+
+  // BUILTIN WRITE_BYTES FN BODY END
+
+  finalize_intrinsic_block (ctx, fndecl);
+
+  TREE_READONLY (fndecl) = 0;
+
+  return fndecl;
+}
+
 } // namespace handlers
 } // namespace Compile
 } // namespace Rust
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h 
b/gcc/rust/backend/rust-intrinsic-handlers.h
index 34e9f49d7..c088f9ff4 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -96,6 +96,9 @@ tree prefetch_write_data (Context *ctx, TyTy::FnType *fntype,
                          location_t expr_locus);
 tree sorry (Context *ctx, TyTy::FnType *fntype, location_t expr_locus);
 
+tree write_bytes_handler (Context *ctx, TyTy::FnType *fntype,
+                         location_t expr_locus);
+
 } // namespace handlers
 
 } // namespace Compile
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index 8f51cf135..af27a2ddb 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -300,6 +300,11 @@ const std::unordered_map<std::string, IntrinsicRules>
     {IValue::FORGET, {1, {IRT::FirstGeneric}, IRT::Unit}},
     // pub fn black_box<T>(mut dummy: T) -> T
     {IValue::BLACK_BOX, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+
+    // fn write_bytes<T>(dst: *mut T, val: u8, count: usize)
+    {IValue::WRITE_BYTES,
+     {1, {IRT::MutPtrFirstGeneric, IRT::U8, IRT::Usize}, IRT::Unit}},
+
 };
 
 IntrinsicCheckResult
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index 1c275e7b7..10c5c1eb2 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -157,6 +157,7 @@ public:
   static constexpr auto &TYPE_NAME = "type_name";
   static constexpr auto &FORGET = "forget";
   static constexpr auto &BLACK_BOX = "black_box";
+  static constexpr auto &WRITE_BYTES = "write_bytes";
 };
 } // namespace Values
 } // namespace Rust
diff --git a/gcc/testsuite/rust/execute/write-bytes.rs 
b/gcc/testsuite/rust/execute/write-bytes.rs
new file mode 100644
index 000000000..bc8fd8f46
--- /dev/null
+++ b/gcc/testsuite/rust/execute/write-bytes.rs
@@ -0,0 +1,17 @@
+#![feature(no_core, intrinsics, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "rust-intrinsic" {
+    fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+}
+
+fn main() -> i32 {
+    let mut x: u32 = 0;
+    unsafe { 
+        write_bytes(&mut x as *mut u32, 0xEC_u8, 1); 
+    }
+    if x == 0xECECECEC_u32 { 0 } else { 1 }
+}

base-commit: f1677688901c1e3ddadc941a89bfd1f7b8e2469e
-- 
2.54.0

Reply via email to