Skip to content

Commit a1231ff

Browse files
dheaton-armAmanieu
authored andcommitted
Add MTE intrinsics
Adds intrinsic functions to `core_arch::aarch64` for MTE, as per the ACLE: - __arm_mte_create_random_tag - __arm_mte_increment_tag - __arm_mte_exclude_tag - __arm_mte_set_tag - __arm_mte_get_tag - __arm_mte_ptrdiff These are unavailable without the `mte` target feature.
1 parent ee3c01e commit a1231ff

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed

crates/core_arch/src/aarch64/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
//! [arm_ref]: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0073a/IHI0073A_arm_neon_intrinsics_ref.pdf
77
//! [arm_dat]: https://developer.arm.com/technologies/neon/intrinsics
88
9+
mod mte;
10+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
11+
pub use self::mte::*;
12+
913
// NEON intrinsics are currently broken on big-endian, so don't expose them. (#1484)
1014
#[cfg(target_endian = "little")]
1115
mod neon;

crates/core_arch/src/aarch64/mte.rs

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//! AArch64 Memory tagging intrinsics
2+
//!
3+
//! [ACLE documentation](https://arm-software.github.io/acle/main/acle.html#markdown-toc-mte-intrinsics)
4+
5+
extern "unadjusted" {
6+
#[cfg_attr(
7+
any(target_arch = "aarch64", target_arch = "arm64ec"),
8+
link_name = "llvm.aarch64.irg"
9+
)]
10+
fn irg_(ptr: *const (), exclude: i64) -> *const ();
11+
#[cfg_attr(
12+
any(target_arch = "aarch64", target_arch = "arm64ec"),
13+
link_name = "llvm.aarch64.gmi"
14+
)]
15+
fn gmi_(ptr: *const (), exclude: i64) -> i64;
16+
#[cfg_attr(
17+
any(target_arch = "aarch64", target_arch = "arm64ec"),
18+
link_name = "llvm.aarch64.ldg"
19+
)]
20+
fn ldg_(ptr: *const (), tag_ptr: *const ()) -> *const ();
21+
#[cfg_attr(
22+
any(target_arch = "aarch64", target_arch = "arm64ec"),
23+
link_name = "llvm.aarch64.stg"
24+
)]
25+
fn stg_(tagged_ptr: *const (), addr_to_tag: *const ());
26+
#[cfg_attr(
27+
any(target_arch = "aarch64", target_arch = "arm64ec"),
28+
link_name = "llvm.aarch64.addg"
29+
)]
30+
fn addg_(ptr: *const (), value: i64) -> *const ();
31+
#[cfg_attr(
32+
any(target_arch = "aarch64", target_arch = "arm64ec"),
33+
link_name = "llvm.aarch64.subp"
34+
)]
35+
fn subp_(ptr_a: *const (), ptr_b: *const ()) -> i64;
36+
}
37+
38+
/// Return a pointer containing a randomly generated logical address tag.
39+
///
40+
/// `src`: A pointer containing an address.
41+
/// `mask`: A mask where each of the lower 16 bits specifies logical
42+
/// tags which must be excluded from consideration. Zero excludes no
43+
/// tags.
44+
///
45+
/// The returned pointer contains a copy of the `src` address, but with a
46+
/// randomly generated logical tag, excluding any specified by `mask`.
47+
///
48+
/// SAFETY: The pointer provided by this intrinsic will be invalid until the memory
49+
/// has been appropriately tagged with `__arm_mte_set_tag`. If using that intrinsic
50+
/// on the provided pointer is itself invalid, then it will be permanently invalid
51+
/// and Undefined Behavior to dereference it.
52+
#[inline]
53+
#[target_feature(enable = "mte")]
54+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
55+
pub unsafe fn __arm_mte_create_random_tag<T>(src: *const T, mask: u64) -> *const T {
56+
irg_(src as *const (), mask as i64) as *const T
57+
}
58+
59+
/// Return a pointer with the logical address tag offset by a value.
60+
///
61+
/// `src`: A pointer containing an address and a logical tag.
62+
/// `OFFSET`: A compile-time constant value in the range [0, 15].
63+
///
64+
/// Adds offset to the logical address tag in `src`, wrapping if the result is
65+
/// outside of the valid 16 tags.
66+
///
67+
/// SAFETY: See `__arm_mte_create_random_tag`.
68+
#[inline]
69+
#[target_feature(enable = "mte")]
70+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
71+
pub unsafe fn __arm_mte_increment_tag<const OFFSET: i64, T>(src: *const T) -> *const T {
72+
addg_(src as *const (), OFFSET) as *const T
73+
}
74+
75+
/// Add a logical tag to the set of excluded logical tags.
76+
///
77+
/// `src`: A pointer containing an address and a logical tag.
78+
/// `excluded`: A mask where the lower 16 bits each specify currently-excluded
79+
/// logical tags.
80+
///
81+
/// Adds the logical tag stored in `src` to the set in `excluded`, and returns
82+
/// the result.
83+
#[inline]
84+
#[target_feature(enable = "mte")]
85+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
86+
pub unsafe fn __arm_mte_exclude_tag<T>(src: *const T, excluded: u64) -> u64 {
87+
gmi_(src as *const (), excluded as i64) as u64
88+
}
89+
90+
/// Store an allocation tag for the 16-byte granule of memory.
91+
///
92+
/// `tag_address`: A pointer containing an address and a logical tag, which
93+
/// must be 16-byte aligned.
94+
///
95+
/// SAFETY: `tag_address` must be 16-byte aligned. The tag will apply to the
96+
/// entire 16-byte memory granule.
97+
#[inline]
98+
#[target_feature(enable = "mte")]
99+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
100+
pub unsafe fn __arm_mte_set_tag<T>(tag_address: *const T) {
101+
stg_(tag_address as *const (), tag_address as *const ());
102+
}
103+
104+
/// Load an allocation tag from memory, returning a new pointer with the
105+
/// corresponding logical tag.
106+
///
107+
/// `address`: A pointer containing an address from which allocation tag memory
108+
/// is read. This does not need to be 16-byte aligned.
109+
#[inline]
110+
#[target_feature(enable = "mte")]
111+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
112+
pub unsafe fn __arm_mte_get_tag<T>(address: *const T) -> *const T {
113+
ldg_(address as *const (), address as *const ()) as *const T
114+
}
115+
116+
/// Calculate the difference between the address parts of two pointers, ignoring
117+
/// the tags, and sign-extending the result.
118+
#[inline]
119+
#[target_feature(enable = "mte")]
120+
#[unstable(feature = "stdarch_aarch64_mte", issue = "129010")]
121+
pub unsafe fn __arm_mte_ptrdiff<T, U>(a: *const T, b: *const U) -> i64 {
122+
subp_(a as *const (), b as *const ())
123+
}
124+
125+
#[cfg(test)]
126+
mod test {
127+
use super::*;
128+
use stdarch_test::assert_instr;
129+
130+
#[cfg_attr(test, assert_instr(irg))]
131+
#[allow(dead_code)]
132+
#[target_feature(enable = "mte")]
133+
pub unsafe fn __test_create_random_tag(src: *const (), mask: u64) -> *const () {
134+
__arm_mte_create_random_tag(src, mask)
135+
}
136+
137+
#[cfg_attr(test, assert_instr(addg))]
138+
#[allow(dead_code)]
139+
#[target_feature(enable = "mte")]
140+
pub unsafe fn __test_increment_tag(src: *const ()) -> *const () {
141+
__arm_mte_increment_tag::<1, _>(src)
142+
}
143+
144+
#[cfg_attr(test, assert_instr(gmi))]
145+
#[allow(dead_code)]
146+
#[target_feature(enable = "mte")]
147+
pub unsafe fn __test_exclude_tag(src: *const (), excluded: u64) -> u64 {
148+
__arm_mte_exclude_tag(src, excluded)
149+
}
150+
151+
#[cfg_attr(test, assert_instr(stg))]
152+
#[allow(dead_code)]
153+
#[target_feature(enable = "mte")]
154+
pub unsafe fn __test_set_tag(src: *const ()) {
155+
__arm_mte_set_tag(src)
156+
}
157+
158+
#[cfg_attr(test, assert_instr(ldg))]
159+
#[allow(dead_code)]
160+
#[target_feature(enable = "mte")]
161+
pub unsafe fn __test_get_tag(src: *const ()) -> *const () {
162+
__arm_mte_get_tag(src)
163+
}
164+
165+
#[cfg_attr(test, assert_instr(subp))]
166+
#[allow(dead_code)]
167+
#[target_feature(enable = "mte")]
168+
pub unsafe fn __test_ptrdiff(a: *const (), b: *const ()) -> i64 {
169+
__arm_mte_ptrdiff(a, b)
170+
}
171+
}

0 commit comments

Comments
 (0)