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
//! CPU feature detection and capability proof tokens for x86 and AArch64.
//!
//! This crate is `no_std` by default and has no default dependencies. The `std`
//! feature enables environment-variable overrides; `aarch64-detect` enables
//! optional runtime detection on supported AArch64 operating systems.
//!
//! Capability tokens exist on every target, so a caller picks a backend without
//! writing architecture `cfg` checks. The branches for other architectures fold
//! away at compile time.
//!
//! ```
//! use tc_runtime::intrinsics::{aarch64, x86};
//!
//! let backend = if x86::Pclmulqdq::detect().is_some() {
//! "pclmulqdq"
//! } else if aarch64::Aes::detect().is_some() {
//! "pmull"
//! } else {
//! "portable"
//! };
//! # let _ = backend;
//! ```
//!
//! ```
//! use tc_runtime::intrinsics::x86::{Aes, Avx2, Sse2};
//!
//! assert_eq!(Sse2::detect().is_some(), Sse2::is_enabled());
//! assert_eq!(Aes::detect().is_some(), Aes::is_enabled());
//! assert_eq!(Avx2::detect().is_some(), Avx2::is_enabled());
//! ```
//!
//! # Calling an optimized backend
//!
//! A token records detected support. It does not apply `#[target_feature]` to
//! your function or remove an intrinsic's other safety requirements. Keep
//! architecture-specific code behind `cfg`, and provide a portable fallback.
//! This example computes the same wrapping addition on every target:
//!
//! ```
//! use tc_runtime::intrinsics::x86::Sse2;
//!
//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
//! #[target_feature(enable = "sse2")]
//! unsafe fn add_sse2(a: i32, b: i32, _proof: Sse2) -> i32 {
//! #[cfg(target_arch = "x86")]
//! use core::arch::x86::{_mm_add_epi32, _mm_cvtsi128_si32, _mm_set1_epi32};
//! #[cfg(target_arch = "x86_64")]
//! use core::arch::x86_64::{_mm_add_epi32, _mm_cvtsi128_si32, _mm_set1_epi32};
//! _mm_cvtsi128_si32(_mm_add_epi32(_mm_set1_epi32(a), _mm_set1_epi32(b)))
//! }
//!
//! fn add(a: i32, b: i32) -> i32 {
//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
//! if let Some(proof) = Sse2::detect() {
//! // SAFETY: the token establishes SSE2 support. No pointers are used.
//! return unsafe { add_sse2(a, b, proof) };
//! }
//! a.wrapping_add(b)
//! }
//!
//! assert_eq!(add(20, 22), 42);
//! assert_eq!(add(i32::MAX, 1), i32::MIN);
//! ```
//!
//! # Feature selection
//!
//! Default builds need neither `std` nor allocation. Enable `aarch64-detect`
//! for optional runtime probing on supported AArch64 operating systems; see
//! [`intrinsics::aarch64`] for coverage. The `std` feature enables `TC_DISABLE_*`
//! environment overrides. Set these before starting the process: their presence
//! disables a capability regardless of their value, and results are cached.
//!
//! Each capability's `is_enabled` documentation names its Cargo disable feature
//! and environment override on its native architecture. Cargo disable features
//! take precedence over detected support. These controls affect backend
//! selection, not instructions the compiler may emit elsewhere in the program.