https://gcc.gnu.org/g:574afa290276ce7bd67e905613d7b77f066b4a87
commit r17-2247-g574afa290276ce7bd67e905613d7b77f066b4a87 Author: Enes Cevik <[email protected]> Date: Fri Jun 26 16:40:51 2026 +0300 gccrs: intrinsic: Add arith_offset 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]> Diff: --- gcc/rust/backend/rust-compile-intrinsic.cc | 1 + gcc/rust/backend/rust-intrinsic-handlers.cc | 39 ++++++++++++++++++++++ gcc/rust/backend/rust-intrinsic-handlers.h | 2 ++ .../typecheck/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(+) diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc index 51531de3c65e..e9407e051115 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 24f831ec7ae6..735529cc947a 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 c088f9ff4d85..1c81417b7024 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 af27a2ddb982..0011e3203d52 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 10c5c1eb2b00..d47e66ce6e9f 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 000000000000..2daf1d7bed6d --- /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 + } + } +}
