Skip to main content

tract_linalg/
lib.rs

1#![allow(clippy::missing_safety_doc)]
2#![allow(clippy::redundant_closure_call)]
3#![allow(clippy::len_zero)]
4#![allow(clippy::excessive_precision)]
5#![allow(clippy::approx_constant)]
6#![allow(clippy::manual_is_multiple_of)]
7#![allow(unexpected_cfgs)]
8#![allow(unused_macros)]
9#[macro_use]
10extern crate derive_new;
11extern crate lazy_static;
12extern crate log;
13extern crate num_traits;
14#[macro_use]
15extern crate pastey;
16#[cfg(test)]
17extern crate proptest;
18
19include!(concat!(env!("OUT_DIR"), "/extern_kernel_macro.rs"));
20
21/// Stands in for a function whose body only compiles in builds carrying the leading arch's
22/// instructions — an asm block, an intrinsic, a CPUID probe — taking the argument types of
23/// the real item and bailing when called. `wasm32` means wasm32 *with* `simd128`, the two
24/// conditions the wasm kernels need. Needed only where something names the function on every
25/// arch: a codegen macro, or a descriptor the arch tree declares everywhere while only the
26/// native host ever calls what it names. A plain `#[cfg]` covers the rest.
27macro_rules! bail_stub {
28    (arm; $($rest:tt)*) => { bail_stub!(@ target_arch = "arm"; $($rest)*); };
29    (aarch64; $($rest:tt)*) => { bail_stub!(@ target_arch = "aarch64"; $($rest)*); };
30    (x86_64; $($rest:tt)*) => { bail_stub!(@ target_arch = "x86_64"; $($rest)*); };
31    (riscv64; $($rest:tt)*) => { bail_stub!(@ target_arch = "riscv64"; $($rest)*); };
32    (wasm32; $($rest:tt)*) => {
33        bail_stub!(@ all(target_arch = "wasm32", target_feature = "simd128"); $($rest)*);
34    };
35
36    (@ $built:meta; $vis:vis unsafe fn $name:ident($($ty:ty),* $(,)?) $(-> $ret:ty)?) => {
37        #[cfg(not($built))]
38        #[allow(clippy::too_many_arguments)]
39        $vis unsafe fn $name($(_: $ty),*) $(-> $ret)? {
40            panic!(concat!(stringify!($name), ": not built for this target"))
41        }
42    };
43
44    (@ $built:meta; $vis:vis fn $name:ident($($ty:ty),* $(,)?) $(-> $ret:ty)?) => {
45        #[cfg(not($built))]
46        #[allow(clippy::too_many_arguments)]
47        $vis fn $name($(_: $ty),*) $(-> $ret)? {
48            panic!(concat!(stringify!($name), ": not built for this target"))
49        }
50    };
51}
52
53#[macro_use]
54mod frame;
55#[macro_use]
56pub mod routines;
57pub mod cache;
58pub mod generic;
59pub mod knobs;
60pub mod multithread;
61pub use frame::weights::WeightType;
62pub use generic::{ScaleShiftAndRound, Scaler};
63use tract_data::internal::TensorView;
64// An arch tree compiles when this build can run its kernels, and — for enumeration only —
65// when `foreign-inventory` asks for the others as well.
66#[cfg(any(target_arch = "x86_64", feature = "foreign-inventory"))]
67pub mod x86_64;
68
69pub mod hwbench;
70
71#[cfg(any(target_arch = "aarch64", feature = "foreign-inventory"))]
72pub mod arm64;
73
74#[cfg(any(target_arch = "aarch64", feature = "foreign-inventory"))]
75pub use arm64::has_fp16;
76
77/// True when the running CPU implements FEAT_FP16. No arm64 tree in this build, hence no
78/// kernel that could use it.
79#[cfg(not(any(target_arch = "aarch64", feature = "foreign-inventory")))]
80pub fn has_fp16() -> bool {
81    false
82}
83
84#[cfg(any(target_arch = "arm", feature = "foreign-inventory"))]
85pub mod arm32;
86
87#[cfg(any(target_arch = "riscv64", feature = "foreign-inventory"))]
88pub mod riscv64;
89
90#[cfg(any(all(target_arch = "wasm32", target_feature = "simd128"), feature = "foreign-inventory"))]
91pub mod wasm;
92
93pub mod isa;
94pub mod mmm_routines;
95pub mod mmm_tiers;
96
97pub use self::frame::mmm::MmmDispatch;
98pub use self::frame::*;
99pub use self::routines::Func;
100
101use tract_data::prelude::*;
102
103#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
104pub enum BinOp {
105    Min,
106    Max,
107    Add,
108    Mul,
109    Sub,
110    SubF,
111}
112
113impl BinOp {
114    pub fn flip(&self) -> BinOp {
115        use BinOp::*;
116        match self {
117            Sub => SubF,
118            SubF => Sub,
119            sym => *sym,
120        }
121    }
122}
123
124/// A binary operation over two tensor views, writing its result over the left one. What the two
125/// binary layouts erase to -- [`by_scalar::ByScalarKer::bin`] broadcasts a one-element right
126/// operand, [`unicast::UnicastKer::bin`] walks a right operand of the same length -- so a caller
127/// holding one needs to know neither which layout nor which kernel answered.
128pub type BinFn = dyn Fn(&mut TensorView, &TensorView) -> TractResult<()> + Send + Sync;
129use num_traits::*;
130use std::fmt::Debug;
131use std::ops::*;
132
133pub trait LADatum:
134    Sized
135    + std::fmt::Display
136    + Debug
137    + Copy
138    + Clone
139    + Zero
140    + One
141    + 'static
142    + Add<Output = Self>
143    + Sub<Output = Self>
144    + Mul
145    + AddAssign
146    + PartialOrd
147    + Bounded
148    + tract_data::prelude::Datum
149{
150    #[cfg(test)]
151    fn strat() -> proptest::prelude::BoxedStrategy<Self>;
152}
153
154#[cfg(test)]
155use proptest::prelude::*;
156
157impl LADatum for f16 {
158    #[cfg(test)]
159    fn strat() -> BoxedStrategy<Self> {
160        f32::strat().prop_map(|f| f.as_()).boxed()
161    }
162}
163
164impl LADatum for f32 {
165    #[cfg(test)]
166    fn strat() -> BoxedStrategy<Self> {
167        (-1000isize..1000).prop_map(|i| i as f32 / 1000.0).boxed()
168    }
169}
170
171impl LADatum for f64 {
172    #[cfg(test)]
173    fn strat() -> BoxedStrategy<Self> {
174        (-1000isize..1000).prop_map(|i| i as f64 / 1000.0).boxed()
175    }
176}
177
178impl LADatum for u8 {
179    #[cfg(test)]
180    fn strat() -> BoxedStrategy<Self> {
181        any::<u8>().boxed()
182    }
183}
184
185impl LADatum for i8 {
186    #[cfg(test)]
187    fn strat() -> BoxedStrategy<Self> {
188        any::<i8>().boxed()
189    }
190}
191
192impl LADatum for i32 {
193    #[cfg(test)]
194    fn strat() -> BoxedStrategy<Self> {
195        any::<i32>().boxed()
196    }
197}
198
199#[cfg(test)]
200#[allow(dead_code)]
201fn setup_test_logger() {
202    let _ = env_logger::Builder::from_env("TRACT_LOG").try_init();
203}