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