From: Enes Cevik <[email protected]>
This patch implements the 'arith_offset' compiler intrinsic. It moves a
pointer forward or backward by a given number of elements. It does not
cause Undefined Behavior if the pointer goes out of bounds.
gcc/rust/ChangeLog:
* backend/rust-compile-intrinsic.cc (generic_intrinsics): Add
arith_offset handler to map.
* backend/rust-intrinsic-handlers.cc (arith_offset_handler): New
function.
* backend/rust-intrinsic-handlers.h (arith_offset_handler): New
declaration.
* typecheck/rust-hir-type-check-intrinsic.cc
(IntrinsicChecker::intrinsic_rules): Add arith_offset rule.
* util/rust-intrinsic-values.h (class Intrinsics): Add
ARITH_OFFSET constexpr.
gcc/testsuite/ChangeLog:
* rust/execute/arith-offset.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/26ca5e38dbf233f9baabbf46684d55986ea4c7fa
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 | 39 +++++++++++++++++++
gcc/rust/backend/rust-intrinsic-handlers.h | 2 +
.../rust-hir-type-check-intrinsic.cc | 3 ++
gcc/rust/util/rust-intrinsic-values.h | 1 +
gcc/testsuite/rust/execute/arith-offset.rs | 23 +++++++++++
6 files changed, 69 insertions(+)
create mode 100644 gcc/testsuite/rust/execute/arith-offset.rs
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc
b/gcc/rust/backend/rust-compile-intrinsic.cc
index 51531de3c..e9407e051 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::ARITH_OFFSET, handlers::arith_offset_handler},
{IValue::WRITE_BYTES, handlers::write_bytes_handler},
{IValue::SIZE_OF, handlers::sizeof_handler},
{IValue::MIN_ALIGN_OF, handlers::min_align_of_handler},
diff --git a/gcc/rust/backend/rust-intrinsic-handlers.cc
b/gcc/rust/backend/rust-intrinsic-handlers.cc
index 24f831ec7..735529cc9 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.cc
+++ b/gcc/rust/backend/rust-intrinsic-handlers.cc
@@ -1935,6 +1935,45 @@ write_bytes_handler (Context *ctx, TyTy::FnType *fntype,
location_t)
return fndecl;
}
+/**
+ * pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
+ */
+tree
+arith_offset_handler (Context *ctx, TyTy::FnType *fntype, location_t
expr_locus)
+{
+ rust_assert (fntype->get_params ().size () == 2);
+
+ auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+ auto locus = fntype->get_locus ();
+
+ std::vector<Bvariable *> param_vars;
+ compile_fn_params (ctx, fntype, fndecl, ¶m_vars);
+
+ auto &dst_param = param_vars.at (0);
+ auto &size_param = param_vars.at (1);
+ rust_assert (param_vars.size () == 2);
+ if (!Backend::function_set_parameters (fndecl, param_vars))
+ return error_mark_node;
+
+ enter_intrinsic_block (ctx, fndecl);
+
+ // BUILTIN arith_offset FN BODY BEGIN
+
+ tree dst = Backend::var_expression (dst_param, locus);
+ tree size = Backend::var_expression (size_param, locus);
+ tree pointer_offset_expr = pointer_offset_expression (dst, size, expr_locus);
+ auto return_statement
+ = Backend::return_statement (fndecl, pointer_offset_expr, locus);
+ ctx->add_statement (return_statement);
+
+ // BUILTIN arith_offset FN BODY END
+
+ finalize_intrinsic_block (ctx, fndecl);
+
+ 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 c088f9ff4..1c81417b7 100644
--- a/gcc/rust/backend/rust-intrinsic-handlers.h
+++ b/gcc/rust/backend/rust-intrinsic-handlers.h
@@ -98,6 +98,8 @@ tree sorry (Context *ctx, TyTy::FnType *fntype, location_t
expr_locus);
tree write_bytes_handler (Context *ctx, TyTy::FnType *fntype,
location_t expr_locus);
+tree arith_offset_handler (Context *ctx, TyTy::FnType *fntype,
+ location_t expr_locus);
} // namespace handlers
diff --git a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
index af27a2ddb..0011e3203 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
@@ -301,6 +301,9 @@ const std::unordered_map<std::string, IntrinsicRules>
// pub fn black_box<T>(mut dummy: T) -> T
{IValue::BLACK_BOX, {1, {IRT::FirstGeneric}, IRT::FirstGeneric}},
+ // pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
+ {IValue::ARITH_OFFSET,
+ {1, {IRT::ConstPtrFirstGeneric, IRT::Isize}, IRT::ConstPtrFirstGeneric}},
// fn write_bytes<T>(dst: *mut T, val: u8, count: usize)
{IValue::WRITE_BYTES,
{1, {IRT::MutPtrFirstGeneric, IRT::U8, IRT::Usize}, IRT::Unit}},
diff --git a/gcc/rust/util/rust-intrinsic-values.h
b/gcc/rust/util/rust-intrinsic-values.h
index 10c5c1eb2..d47e66ce6 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 &ARITH_OFFSET = "arith_offset";
static constexpr auto &WRITE_BYTES = "write_bytes";
};
} // namespace Values
diff --git a/gcc/testsuite/rust/execute/arith-offset.rs
b/gcc/testsuite/rust/execute/arith-offset.rs
new file mode 100644
index 000000000..2daf1d7be
--- /dev/null
+++ b/gcc/testsuite/rust/execute/arith-offset.rs
@@ -0,0 +1,23 @@
+#![feature(no_core, intrinsics, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+extern "rust-intrinsic" {
+ fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
+}
+
+fn main() -> i32 {
+ let base_addr: usize = 0;
+ let ptr = base_addr as *const u64;
+
+ unsafe {
+ let wrap_ptr = arith_offset(ptr, -1);
+ if wrap_ptr as isize == -8_isize {
+ 0
+ } else {
+ 1
+ }
+ }
+}
--
2.54.0