1//! AArch64 Memory tagging intrinsics
2//!
3//! [ACLE documentation](https://arm-software.github.io/acle/main/acle.html#markdown-toc-mte-intrinsics)
45unsafe extern "unadjusted" {
6#[cfg_attr(
7 any(target_arch = "aarch64", target_arch = "arm64ec"),
8 link_name = "llvm.aarch64.irg"
9)]
10fn irg_(ptr: *const (), exclude: i64) -> *const ();
11#[cfg_attr(
12 any(target_arch = "aarch64", target_arch = "arm64ec"),
13 link_name = "llvm.aarch64.gmi"
14)]
15fn gmi_(ptr: *const (), exclude: i64) -> i64;
16#[cfg_attr(
17 any(target_arch = "aarch64", target_arch = "arm64ec"),
18 link_name = "llvm.aarch64.ldg"
19)]
20fn 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)]
25fn 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)]
30fn addg_(ptr: *const (), value: i64) -> *const ();
31#[cfg_attr(
32 any(target_arch = "aarch64", target_arch = "arm64ec"),
33 link_name = "llvm.aarch64.subp"
34)]
35fn subp_(ptr_a: *const (), ptr_b: *const ()) -> i64;
36}
3738/// 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")]
55pub 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}
5859/// 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")]
71pub 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}
7475/// 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")]
86pub unsafe fn __arm_mte_exclude_tag<T>(src: *const T, excluded: u64) -> u64 {
87 gmi_(src as *const (), excluded as i64) as u64
88}
8990/// 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")]
100pub unsafe fn __arm_mte_set_tag<T>(tag_address: *const T) {
101 stg_(tag_address as *const (), tag_address as *const ());
102}
103104/// 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")]
112pub unsafe fn __arm_mte_get_tag<T>(address: *const T) -> *const T {
113 ldg_(address as *const (), address as *const ()) as *const T
114}
115116/// 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")]
121pub unsafe fn __arm_mte_ptrdiff<T, U>(a: *const T, b: *const U) -> i64 {
122 subp_(a as *const (), b as *const ())
123}
124125#[cfg(test)]
126mod test {
127use super::*;
128use stdarch_test::assert_instr;
129130#[cfg_attr(test, assert_instr(irg))]
131 #[allow(dead_code)]
132 #[target_feature(enable = "mte")]
133unsafe fn test_arm_mte_create_random_tag(src: *const (), mask: u64) -> *const () {
134 __arm_mte_create_random_tag(src, mask)
135 }
136137#[cfg_attr(test, assert_instr(addg))]
138 #[allow(dead_code)]
139 #[target_feature(enable = "mte")]
140unsafe fn test_arm_mte_increment_tag(src: *const ()) -> *const () {
141 __arm_mte_increment_tag::<1, _>(src)
142 }
143144#[cfg_attr(test, assert_instr(gmi))]
145 #[allow(dead_code)]
146 #[target_feature(enable = "mte")]
147unsafe fn test_arm_mte_exclude_tag(src: *const (), excluded: u64) -> u64 {
148 __arm_mte_exclude_tag(src, excluded)
149 }
150151#[cfg_attr(test, assert_instr(stg))]
152 #[allow(dead_code)]
153 #[target_feature(enable = "mte")]
154unsafe fn test_arm_mte_set_tag(src: *const ()) {
155 __arm_mte_set_tag(src)
156 }
157158#[cfg_attr(test, assert_instr(ldg))]
159 #[allow(dead_code)]
160 #[target_feature(enable = "mte")]
161unsafe fn test_arm_mte_get_tag(src: *const ()) -> *const () {
162 __arm_mte_get_tag(src)
163 }
164165#[cfg_attr(test, assert_instr(subp))]
166 #[allow(dead_code)]
167 #[target_feature(enable = "mte")]
168unsafe fn test_arm_mte_ptrdiff(a: *const (), b: *const ()) -> i64 {
169 __arm_mte_ptrdiff(a, b)
170 }
171}