Skip to content

Commit

Permalink
Add TBI helpers for AArch64
Browse files Browse the repository at this point in the history
Adds a trait to `core_arch` for AArch64 to set a value in the top byte of a pointer (which should logically become the canonical address of the allocation), and to retrieve the value stored in the top byte of a pointer, if any.
  • Loading branch information
dheaton-arm committed Jul 30, 2024
1 parent fb90dfa commit 91238bc
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 1 deletion.
4 changes: 4 additions & 0 deletions crates/core_arch/src/aarch64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
//! [arm_ref]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf
//! [arm_dat]: https://developer.arm.com/technologies/neon/intrinsics

mod tbi;
#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
pub use self::tbi::*;

// NEON intrinsics are currently broken on big-endian, so don't expose them. (#1484)
#[cfg(target_endian = "little")]
mod neon;
Expand Down
94 changes: 94 additions & 0 deletions crates/core_arch/src/aarch64/tbi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/// Provides additional methods on pointers to get and set any values set in the top byte of the pointer,
/// as per AArch64's Top-Byte Ignore (TBI) feature.
#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
pub trait TBIPointer: Sized {
/// Returns a new pointer with the top byte set to a given value, invalidating the original pointer.
///
/// Continuing to use the pointer passed in to this function is Undefined Behavior; you should replace it with the returned pointer instead.
#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
fn with_top_byte(self, b: u8) -> Self;

/// Returns the value (if any) stored in the top byte of the pointer.
#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
fn top_byte(&self) -> u8;
}

macro_rules! tbi_ptr_impl {
() => {
fn with_top_byte(self, b: u8) -> Self {
// We can't actually call `realloc` here as we don't have `std`, and the pointer may not be valid for `realloc` anyway (if the value's stored on the stack, for example).
let addr = self.addr() & 0x00ffffffffffffff;
let p = addr | ((b as usize) << 56);
self.with_addr(p)
}

fn top_byte(&self) -> u8 {
(self.addr() >> 56) as u8
}
};
}

#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
impl<T> TBIPointer for *const T {
tbi_ptr_impl!();
}

#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
impl<T> TBIPointer for *mut T {
tbi_ptr_impl!();
}

#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
impl<T> TBIPointer for *const [T] {
tbi_ptr_impl!();
}

#[unstable(feature = "stdarch_aarch64_tbi", issue = "none")]
impl<T> TBIPointer for *mut [T] {
tbi_ptr_impl!();
}

#[cfg(test)]
mod test {
use super::*;

#[test]
fn tbi_const() {
let value: u32 = 10;
let mut address = &value as *const u32;
address = address.with_top_byte(0x80);
assert_eq!(address.top_byte(), 0x80);
assert_eq!(unsafe { *address }, 10);
}

#[test]
fn tbi_mut() {
let mut value: u32 = 10;
let mut address = &mut value as *mut u32;
address = address.with_top_byte(0x80);
assert_eq!(address.top_byte(), 0x80);
assert_eq!(unsafe { *address }, 10);
unsafe { *address = 255 };
assert_eq!(unsafe { *address }, 255);
}

#[test]
fn tbi_const_array() {
let value: [u32; 4] = [10, 255, 65535, 0xffffffff];
let mut address = &value as *const [u32; 4];
address = address.with_top_byte(0x80);
assert_eq!(address.top_byte(), 0x80);
assert_eq!(unsafe { *address }, [10, 255, 65535, 0xffffffff]);
}

#[test]
fn tbi_mut_array() {
let mut value: [u32; 4] = [10, 255, 65535, 0xffffffff];
let mut address = &mut value as *mut [u32; 4];
address = address.with_top_byte(0x80);
assert_eq!(address.top_byte(), 0x80);
assert_eq!(unsafe { *address }, [10, 255, 65535, 0xffffffff]);
unsafe { (*address)[0] = 25 };
assert_eq!(unsafe { *address }, [25, 255, 65535, 0xffffffff]);
}
}
4 changes: 3 additions & 1 deletion crates/core_arch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
generic_arg_infer,
asm_experimental_arch,
sha512_sm_x86,
f16
f16,
ptr_metadata,
strict_provenance
)]
#![cfg_attr(test, feature(test, abi_vectorcall, stdarch_internal))]
#![deny(clippy::missing_inline_in_public_items)]
Expand Down

0 comments on commit 91238bc

Please sign in to comment.