From: Arthur Cohen <[email protected]>

The Rust doc indicates that this is equivalent to ptr.write(val) but with an 
extra performance
hint, so do just that - without the performance hint, as GCC has no way to 
indicate that a
move should be nontemporal as far as I can tell.

gcc/rust/ChangeLog:

        * backend/rust-compile-intrinsic.cc: Add new handler for 
nontemporal_store.
        * backend/rust-intrinsic-handlers.cc (move_val_init): Add soundness 
comment.
        (nontemporal_store): New function.
        * backend/rust-intrinsic-handlers.h (nontemporal_store): Likewise.
        * typecheck/rust-hir-type-check-intrinsic.cc: New entry for 
nontemporal_store.
        * util/rust-intrinsic-values.h: Likewise.

gcc/testsuite/ChangeLog:

        * rust/compile/nontemporal_store.rs: New test.
---
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/a87ec0b8756f69aac7da755eb923e7da41fe7cd3

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/5026

 gcc/rust/backend/rust-compile-intrinsic.cc    |  1 +
 gcc/rust/backend/rust-intrinsic-handlers.cc   | 39 +++++++++++++++++++
 gcc/rust/backend/rust-intrinsic-handlers.h    |  2 +
 .../rust-hir-type-check-intrinsic.cc          |  4 ++
 gcc/rust/util/rust-intrinsic-values.h         |  2 +
 .../rust/compile/nontemporal_store.rs         | 19 +++++++++
 6 files changed, 67 insertions(+)
 create mode 100644 gcc/testsuite/rust/compile/nontemporal_store.rs

diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc 
b/gcc/rust/backend/rust-compile-intrinsic.cc
index a1ee04de7..862d9a3ad 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -228,6 +228,7 @@ static const std::map<std::string, Intrinsic::CompileFn> 
intrinsics = {
    handlers::fop_fast (ArithmeticOrLogicalOperator::MODULUS)},
   {IValue::FLOAT_TO_INT_UNCHECKED, handlers::float_to_int_unchecked},
   {IValue::EXACT_DIV, handlers::exact_div_handler},
+  {IValue::NONTEMPORAL_STORE, handlers::nontemporal_store},
   {IValue::BREAKPOINT, handlers::breakpoint},
   {IValue::PREF_ALIGN_OF, handlers::sorry},
   {IValue::ASSERT_ZERO_VALID, handlers::type_assert (TyAssert::ZeroValid)},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc 
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 4ace3fcf4..f95bed7d8 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1508,6 +1508,30 @@ variant_count (IntrinsicCtx &ctx)
 void
 move_val_init (IntrinsicCtx &ctx)
 {
+  // NOTE: Per rustc 1.49, `move_val_init` has magic semantics - code is down
+  // below. We need to ensure that we have the correct behavior by doing a
+  // memcpy here.
+
+  // if let Some(sym::move_val_init) = intrinsic {
+  //     `move_val_init` has "magic" semantics - the second argument is always
+  //     evaluated "directly" into the first one.
+
+  //     let mut args = args.into_iter();
+  //     let ptr = args.next().expect("0 arguments to `move_val_init`");
+  //     let val = args.next().expect("1 argument to `move_val_init`");
+  //     assert!(args.next().is_none(), ">2 arguments to `move_val_init`");
+
+  //     let ptr = this.hir.mirror(ptr);
+  //     let ptr_ty = ptr.ty;
+  //     // Create an *internal* temp for the pointer, so that unsafety
+  //     // checking won't complain about the raw pointer assignment.
+  //     let ptr_temp = this
+  //         .local_decls
+  //         .push(LocalDecl::with_source_info(ptr_ty, 
source_info).internal());
+  //     let ptr_temp = Place::from(ptr_temp);
+  //     let block = unpack!(this.into(ptr_temp, block, ptr));
+  //     this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
+
   // Most intrinsic functions are pure - not `move_val_init`
   TREE_READONLY (ctx.fn) = 0;
   TREE_SIDE_EFFECTS (ctx.fn) = 1;
@@ -2132,6 +2156,21 @@ exact_div_handler (IntrinsicCtx &ctx)
   ctx.add_statement (return_stmt);
 }
 
+void
+nontemporal_store (IntrinsicCtx &ctx)
+{
+  // https://doc.rust-lang.org/std/intrinsics/fn.nontemporal_store.html
+  // Equivalent to ptr.write(value), but with an extra performance hint.
+  // AFAICT, GCC currently has no way to indicate that a write like this
+  // *should* be nontemporal - there are no tree attributes for it, and the 
code
+  // to check whether a store is nontemporal (nontemporal_store_p in
+  // tree-ssa-loop-prefetch.cc) checks manually if the store upholds certain
+  // conditions - it does not account for a flag on the `tree` or anything like
+  // that.
+
+  return move_val_init (ctx);
+}
+
 void
 float_to_int_unchecked (IntrinsicCtx &ctx)
 {
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.h 
b/gcc/rust/backend/rust-intrinsic-handlers.h
index cdf753be9..7654497c0 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -201,6 +201,8 @@ void assert_zero_valid_handler (IntrinsicCtx &ctx);
 
 void exact_div_handler (IntrinsicCtx &ctx);
 
+void nontemporal_store (IntrinsicCtx &ctx);
+
 Intrinsic::CompileFn op_with_overflow (tree_code op);
 
 Intrinsic::CompileFn wrapping_op (tree_code op);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc 
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index 56a4888dc..afa633c38 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -533,6 +533,10 @@ const std::unordered_map<std::string, IntrinsicRules>
     // fn exact_div<T>(lhs: T, rhs: T) -> T
     {IValue::EXACT_DIV,
      {1, {IRT::FirstGeneric, IRT::FirstGeneric}, IRT::FirstGeneric}},
+
+    // fn nontemporal_store<T>(ptr: *mut T, value: T)
+    {IValue::NONTEMPORAL_STORE,
+     {1, {IRT::MutPtrFirstGeneric, IRT::FirstGeneric}, IRT::Unit}},
 };
 
 IntrinsicCheckResult
diff --git a/gcc/rust/util/rust-intrinsic-values.h 
b/gcc/rust/util/rust-intrinsic-values.h
index d2dad8d3a..1bd5d1652 100644
--- a/gcc/rust/util/rust-intrinsic-values.h
+++ b/gcc/rust/util/rust-intrinsic-values.h
@@ -284,6 +284,8 @@ public:
   static constexpr auto &FLOAT_TO_INT_UNCHECKED = "float_to_int_unchecked";
 
   static constexpr auto &EXACT_DIV = "exact_div";
+
+  static constexpr auto &NONTEMPORAL_STORE = "nontemporal_store";
 };
 } // namespace Values
 } // namespace Rust
diff --git a/gcc/testsuite/rust/compile/nontemporal_store.rs 
b/gcc/testsuite/rust/compile/nontemporal_store.rs
new file mode 100644
index 000000000..8ef810a48
--- /dev/null
+++ b/gcc/testsuite/rust/compile/nontemporal_store.rs
@@ -0,0 +1,19 @@
+#![feature(no_core)]
+#![feature(intrinsics)]
+#![feature(lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+extern "rust-intrinsic" {
+    fn nontemporal_store<T>(ptr: *mut T, value: T);
+}
+
+fn main() {
+    let mut a = 15i32;
+
+    unsafe {
+        nontemporal_store(&mut a as *mut i32, 16);
+    }
+}

base-commit: aa74e9a32411367390f8a6e3448d596ade1b6c03
-- 
2.56.0

Reply via email to