Skip to main content

safe_arch/x86_x64/
m256_.rs

1//! This module is for the `m256` wrapper type, its bonus methods, and all
2//! necessary trait impls.
3//!
4//! Intrinsics should _not_ be in this module! They should all be free-functions
5//! in the other modules, sorted by CPU target feature.
6
7use super::*;
8
9/// The data for a 256-bit AVX register of eight `f32` lanes.
10///
11/// * This is _very similar to_ having `[f32; 8]`. The main difference is that
12///   it's aligned to 32 instead of just 4, and of course you can perform
13///   various intrinsic operations on it.
14#[repr(transparent)]
15#[allow(non_camel_case_types)]
16pub struct m256(pub __m256);
17
18#[cfg(feature = "bytemuck")]
19unsafe impl bytemuck::Zeroable for m256 {}
20#[cfg(feature = "bytemuck")]
21unsafe impl bytemuck::Pod for m256 {}
22#[cfg(feature = "bytemuck")]
23unsafe impl bytemuck::TransparentWrapper<__m256> for m256 {}
24
25impl m256 {
26  /// Transmutes the `m256` to an array.
27  ///
28  /// Same as `m.into()`, just lets you be more explicit about what's happening.
29  #[must_use]
30  #[inline(always)]
31  pub fn to_array(self) -> [f32; 8] {
32    self.into()
33  }
34
35  /// Transmutes an array into `m256`.
36  ///
37  /// Same as `m256::from(arr)`, it just lets you be more explicit about what's
38  /// happening.
39  #[must_use]
40  #[inline(always)]
41  pub fn from_array(f: [f32; 8]) -> Self {
42    f.into()
43  }
44
45  /// Converts into the bit patterns of these floats (`[u32;8]`).
46  ///
47  /// Like [`f32::to_bits`](f32::to_bits), but all eight lanes at once.
48  #[must_use]
49  #[inline(always)]
50  pub fn to_bits(self) -> [u32; 8] {
51    unsafe { core::mem::transmute(self) }
52  }
53
54  /// Converts from the bit patterns of these floats (`[u32;8]`).
55  ///
56  /// Like [`f32::from_bits`](f32::from_bits), but all eight lanes at once.
57  #[must_use]
58  #[inline(always)]
59  pub fn from_bits(bits: [u32; 8]) -> Self {
60    unsafe { core::mem::transmute(bits) }
61  }
62}
63
64impl Clone for m256 {
65  #[inline(always)]
66  fn clone(&self) -> Self {
67    *self
68  }
69}
70impl Copy for m256 {}
71
72impl Default for m256 {
73  #[inline(always)]
74  fn default() -> Self {
75    unsafe { core::mem::zeroed() }
76  }
77}
78
79impl From<[f32; 8]> for m256 {
80  #[inline(always)]
81  fn from(arr: [f32; 8]) -> Self {
82    // Safety: because this semantically moves the value from the input position
83    // (align4) to the output position (align16) it is fine to increase our
84    // required alignment without worry.
85    unsafe { core::mem::transmute(arr) }
86  }
87}
88
89impl From<m256> for [f32; 8] {
90  #[inline(always)]
91  fn from(m: m256) -> Self {
92    // We can of course transmute to a lower alignment
93    unsafe { core::mem::transmute(m) }
94  }
95}
96
97//
98// PLEASE KEEP ALL THE FORMAT IMPL JUNK AT THE END OF THE FILE
99//
100
101impl Debug for m256 {
102  /// Debug formats each float.
103  /// ```
104  /// # use safe_arch::*;
105  /// let f = format!("{:?}", m256::default());
106  /// assert_eq!(&f, "m256(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)");
107  /// ```
108  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
109    write!(f, "m256(")?;
110    for (i, float) in self.to_array().iter().enumerate() {
111      if i != 0 {
112        write!(f, ", ")?;
113      }
114      Debug::fmt(float, f)?;
115    }
116    write!(f, ")")
117  }
118}
119
120impl Display for m256 {
121  /// Display formats each float, and leaves the type name off of the font.
122  /// ```
123  /// # use safe_arch::*;
124  /// let f = format!("{}", m256::default());
125  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
126  /// ```
127  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
128    write!(f, "(")?;
129    for (i, float) in self.to_array().iter().enumerate() {
130      if i != 0 {
131        write!(f, ", ")?;
132      }
133      Display::fmt(float, f)?;
134    }
135    write!(f, ")")
136  }
137}
138
139impl Binary for m256 {
140  /// Binary formats each float's bit pattern (via [`f32::to_bits`]).
141  /// ```
142  /// # use safe_arch::*;
143  /// let f = format!("{:b}", m256::default());
144  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
145  /// ```
146  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
147    write!(f, "(")?;
148    for (i, float) in self.to_array().iter().enumerate() {
149      if i != 0 {
150        write!(f, ", ")?;
151      }
152      Binary::fmt(&float.to_bits(), f)?;
153    }
154    write!(f, ")")
155  }
156}
157
158impl LowerExp for m256 {
159  /// LowerExp formats each float.
160  /// ```
161  /// # use safe_arch::*;
162  /// let f = format!("{:e}", m256::default());
163  /// assert_eq!(&f, "(0e0, 0e0, 0e0, 0e0, 0e0, 0e0, 0e0, 0e0)");
164  /// ```
165  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
166    write!(f, "(")?;
167    for (i, float) in self.to_array().iter().enumerate() {
168      if i != 0 {
169        write!(f, ", ")?;
170      }
171      LowerExp::fmt(float, f)?;
172    }
173    write!(f, ")")
174  }
175}
176
177impl UpperExp for m256 {
178  /// UpperExp formats each float.
179  /// ```
180  /// # use safe_arch::*;
181  /// let f = format!("{:E}", m256::default());
182  /// assert_eq!(&f, "(0E0, 0E0, 0E0, 0E0, 0E0, 0E0, 0E0, 0E0)");
183  /// ```
184  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
185    write!(f, "(")?;
186    for (i, float) in self.to_array().iter().enumerate() {
187      if i != 0 {
188        write!(f, ", ")?;
189      }
190      UpperExp::fmt(float, f)?;
191    }
192    write!(f, ")")
193  }
194}
195
196impl LowerHex for m256 {
197  /// LowerHex formats each float's bit pattern (via [`f32::to_bits`]).
198  /// ```
199  /// # use safe_arch::*;
200  /// let f = format!("{:x}", m256::default());
201  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
202  /// ```
203  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
204    write!(f, "(")?;
205    for (i, float) in self.to_array().iter().enumerate() {
206      if i != 0 {
207        write!(f, ", ")?;
208      }
209      LowerHex::fmt(&float.to_bits(), f)?;
210    }
211    write!(f, ")")
212  }
213}
214
215impl UpperHex for m256 {
216  /// UpperHex formats each float's bit pattern (via [`f32::to_bits`]).
217  /// ```
218  /// # use safe_arch::*;
219  /// let f = format!("{:X}", m256::default());
220  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
221  /// ```
222  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
223    write!(f, "(")?;
224    for (i, float) in self.to_array().iter().enumerate() {
225      if i != 0 {
226        write!(f, ", ")?;
227      }
228      UpperHex::fmt(&float.to_bits(), f)?;
229    }
230    write!(f, ")")
231  }
232}
233
234impl Octal for m256 {
235  /// Octal formats each float's bit pattern (via [`f32::to_bits`]).
236  /// ```
237  /// # use safe_arch::*;
238  /// let f = format!("{:o}", m256::default());
239  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
240  /// ```
241  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
242    write!(f, "(")?;
243    for (i, float) in self.to_array().iter().enumerate() {
244      if i != 0 {
245        write!(f, ", ")?;
246      }
247      Octal::fmt(&float.to_bits(), f)?;
248    }
249    write!(f, ")")
250  }
251}