1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! 分支的事务性内存扩展 (TME)。
//!
//! 此 CPU 特性在 Aarch64 上可用 - 架构概要。
//! 此特性在非 neon 的特性集中。可以在 [TME Intrinsics 介绍][tme_intrinsics_intro] 上找到 TME 特定的供应商文档。
//!
//! 引用的是 [ACLE Q4 2019][acle_q4_2019_ref]。
//!
//! ACLE 有一个用于 TME 扩展的部分,以及用于中止和故障代码的状态掩码的部分。
//! [ARM A64 架构登记数据表][a_profile_future] 还描述了可能的故障代码场景。
//!
//! [acle_q4_2019_ref]: https://static.docs.arm.com/101028/0010/ACLE_2019Q4_release-0010.pdf
//! [tme_intrinsics_intro]: https://developer.arm.com/docs/101028/0010/transactional-memory-extension-tme-intrinsics
//! [llvm_aarch64_int]: https://github.com/llvm/llvm-project/commit/a36d31478c182903523e04eb271bbf102bfab2cc#diff-ff24e1c35f4d54f1110ce5d90c709319R626-R646
//! [a_profile_future]: https://static.docs.arm.com/ddi0601/a/SysReg_xml_futureA-2019-04.pdf?_ga=2.116560387.441514988.1590524918-1110153136.1588469296
//!

#[cfg(test)]
use stdarch_test::assert_instr;

extern "unadjusted" {
    #[link_name = "llvm.aarch64.tstart"]
    fn aarch64_tstart() -> u64;
    #[link_name = "llvm.aarch64.tcommit"]
    fn aarch64_tcommit() -> ();
    #[link_name = "llvm.aarch64.tcancel"]
    fn aarch64_tcancel(imm0: u64) -> ();
    #[link_name = "llvm.aarch64.ttest"]
    fn aarch64_ttest() -> u64;
}

/// 事务成功开始。
pub const _TMSTART_SUCCESS: u64 = 0x00_u64;

/// 故障原因的提取码
pub const _TMFAILURE_REASON: u64 = 0x00007FFF_u64;

/// 事务重试是可能的。
pub const _TMFAILURE_RTRY: u64 = 1 << 15;

/// 事务执行了 TCANCEL 指令
pub const _TMFAILURE_CNCL: u64 = 1 << 16;

/// 事务因发生冲突而中止
pub const _TMFAILURE_MEM: u64 = 1 << 17;

/// 后备错误类型 (由于任何其他原因)
pub const _TMFAILURE_IMP: u64 = 1 << 18;

/// 事务中止,因为尝试了不允许的操作
pub const _TMFAILURE_ERR: u64 = 1 << 19;

/// 事务由于超出读或写集限制而中止
pub const _TMFAILURE_SIZE: u64 = 1 << 20;

/// 由于超出了事务嵌套级别,事务中止了
pub const _TMFAILURE_NEST: u64 = 1 << 21;

/// 事务由于调试陷阱而中止。
pub const _TMFAILURE_DBG: u64 = 1 << 22;

/// 事务因中断而失败
pub const _TMFAILURE_INT: u64 = 1 << 23;

/// 表示 TM 的试用版可用
pub const _TMFAILURE_TRIVIAL: u64 = 1 << 24;

/// 开始新的事务。当交易开始成功时,返回值是 0.
/// 如果事务失败,则将丢弃所有状态修改,并将失败原因编码在返回值中。
///
///  [ARM TME Intrinsics](https://developer.arm.com/docs/101028/0010/transactional-memory-extension-tme-intrinsics).
///
#[inline]
#[target_feature(enable = "tme")]
#[cfg_attr(test, assert_instr(tstart))]
pub unsafe fn __tstart() -> u64 {
    aarch64_tstart()
}

/// 提交当前事务。
/// 对于嵌套事务,唯一的效果是减少了事务嵌套深度。
/// 对于外部事务,将事务执行的状态修改提交给体系结构状态。
///
///  [ARM TME Intrinsics](https://developer.arm.com/docs/101028/0010/transactional-memory-extension-tme-intrinsics).
#[inline]
#[target_feature(enable = "tme")]
#[cfg_attr(test, assert_instr(tcommit))]
pub unsafe fn __tcommit() {
    aarch64_tcommit()
}

/// 取消当前事务,并放弃所有通过事务执行的状态修改。
///  [ARM TME Intrinsics](https://developer.arm.com/docs/101028/0010/transactional-memory-extension-tme-intrinsics).
///
#[inline]
#[target_feature(enable = "tme")]
#[cfg_attr(test, assert_instr(tcancel, IMM16 = 0x0))]
#[rustc_legacy_const_generics(0)]
pub unsafe fn __tcancel<const IMM16: u64>() {
    static_assert!(IMM16 <= 65535);
    aarch64_tcancel(IMM16);
}

/// 测试是否在事务内执行。
/// 如果当前没有事务正在执行,则返回值为 0.
/// 否则,此内部函数将返回事务的深度。
///  [ARM TME Intrinsics](https://developer.arm.com/docs/101028/0010/transactional-memory-extension-tme-intrinsics).
#[inline]
#[target_feature(enable = "tme")]
#[cfg_attr(test, assert_instr(ttest))]
pub unsafe fn __ttest() -> u64 {
    aarch64_ttest()
}

#[cfg(test)]
mod tests {
    use stdarch_test::simd_test;

    use crate::core_arch::aarch64::*;

    const CANCEL_CODE: u64 = (0 | (0x123 & _TMFAILURE_REASON) as u64) as u64;

    #[simd_test(enable = "tme")]
    unsafe fn test_tstart() {
        let mut x = 0;
        for i in 0..10 {
            let code = tme::__tstart();
            if code == _TMSTART_SUCCESS {
                x += 1;
                assert_eq!(x, i + 1);
                break;
            }
            assert_eq!(x, 0);
        }
    }

    #[simd_test(enable = "tme")]
    unsafe fn test_tcommit() {
        let mut x = 0;
        for i in 0..10 {
            let code = tme::__tstart();
            if code == _TMSTART_SUCCESS {
                x += 1;
                assert_eq!(x, i + 1);
                tme::__tcommit();
            }
            assert_eq!(x, i + 1);
        }
    }

    #[simd_test(enable = "tme")]
    unsafe fn test_tcancel() {
        let mut x = 0;

        for i in 0..10 {
            let code = tme::__tstart();
            if code == _TMSTART_SUCCESS {
                x += 1;
                assert_eq!(x, i + 1);
                tme::__tcancel::<CANCEL_CODE>();
                break;
            }
        }

        assert_eq!(x, 0);
    }

    #[simd_test(enable = "tme")]
    unsafe fn test_ttest() {
        for _ in 0..10 {
            let code = tme::__tstart();
            if code == _TMSTART_SUCCESS {
                if tme::__ttest() == 2 {
                    tme::__tcancel::<CANCEL_CODE>();
                    break;
                }
            }
        }
    }
}