gccrs#4620: Add write_bytes and arith_offset
Link: Rust-GCC/gccrs#4620
Definition:
#![allow(unused)]
fn main() {
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")]
pub fn arith_offset<T>(dst: *const T, offset: isize) -> *const T;
}
#![allow(unused)]
fn main() {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
extern "rust-intrinsic" {
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
}
debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer");
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
unsafe { write_bytes(dst, val, count) }
}
}
Objective
This PR implements arith_offset and write_bytes compiler intrinsics.
Changes Made
write_bytes: Lowered to GCC’s__builtin_memset.arith_offset: Lowered using GCC’sPOINTER_PLUS_EXPR.
Why is this needed for alloc?
The alloc crate relies heavily on these intrinsics for raw memory manipulation. arith_offset is required for pointer arithmetic (calculating offsets for data structures like Vec), and write_bytes is used to quickly set memory regions to a specific value.
Test Case
fn try_arith_offset() -> i32 {
let base_addr: usize = 0;
let ptr = base_addr as *const u64;
let wrap_ptr = ptr.wrapping_offset(-1);
if wrap_ptr as isize == -8_isize {
0
} else {
1
}
}
fn try_write_bytes() -> i32 {
let mut x: u32 = 0;
unsafe {
core::ptr::write_bytes(&mut x as *mut u32, 0xEC_u8, 1);
}
if x == 0xECECECEC_u32 {
0
} else {
1
}
}
fn main() {
println!("arith_offset result: {}", try_arith_offset());
println!("write_bytes result: {}", try_write_bytes());
}
The arith_offset correctly wraps around using two’s complement arithmetic without undefined behavior. write_bytes successfully acts as a memset, modifying the exact byte pattern of the memory block.