]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: intrinsic: Add arith_offset
authorEnes Cevik <enes@nsvke.com>
Fri, 26 Jun 2026 13:40:51 +0000 (16:40 +0300)
committerArthur Cohen <arthur.cohen@embecosm.com>
Wed, 8 Jul 2026 15:22:50 +0000 (17:22 +0200)
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 <enes@nsvke.com>
gcc/rust/backend/rust-compile-intrinsic.cc
gcc/rust/backend/rust-intrinsic-handlers.cc
gcc/rust/backend/rust-intrinsic-handlers.h
gcc/rust/typecheck/rust-hir-type-check-intrinsic.cc
gcc/rust/util/rust-intrinsic-values.h
gcc/testsuite/rust/execute/arith-offset.rs [new file with mode: 0644]

index 51531de3c65e96c88abdbec3ca458cddceadfdb8..e9407e0511150190de99ca2f894d46ae65fb60d4 100644 (file)
@@ -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},
index 24f831ec7ae670bf3eb788b09f5184481e023cea..735529cc947a6eeed67194c794f8190f3e4e394d 100644 (file)
@@ -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, &param_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
index c088f9ff4d853461eb5469f35e5250c1169f9763..1c81417b70240c7648144d3e8f30856bf0719090 100644 (file)
@@ -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
 
index af27a2ddb982d9931985f5c2f4bd5eb9e4546418..0011e3203d52a88697fb564f36e26198b1e33bb1 100644 (file)
@@ -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}},
index 10c5c1eb2b0093015adaeb5933baa53fcc02af62..d47e66ce6e9f30b1f80cef5bbd222290d465b106 100644 (file)
@@ -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 (file)
index 0000000..2daf1d7
--- /dev/null
@@ -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 
+        }
+    }
+}