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  #[must_use]
66  #[inline(always)]
67  fn clone(&self) -> Self {
68    *self
69  }
70}
71impl Copy for m256 {}
72
73impl Default for m256 {
74  #[must_use]
75  #[inline(always)]
76  fn default() -> Self {
77    unsafe { core::mem::zeroed() }
78  }
79}
80
81impl From<[f32; 8]> for m256 {
82  #[must_use]
83  #[inline(always)]
84  fn from(arr: [f32; 8]) -> Self {
85    // Safety: because this semantically moves the value from the input position
86    // (align4) to the output position (align16) it is fine to increase our
87    // required alignment without worry.
88    unsafe { core::mem::transmute(arr) }
89  }
90}
91
92impl From<m256> for [f32; 8] {
93  #[must_use]
94  #[inline(always)]
95  fn from(m: m256) -> Self {
96    // We can of course transmute to a lower alignment
97    unsafe { core::mem::transmute(m) }
98  }
99}
100
101//
102// PLEASE KEEP ALL THE FORMAT IMPL JUNK AT THE END OF THE FILE
103//
104
105impl Debug for m256 {
106  /// Debug formats each float.
107  /// ```
108  /// # use safe_arch::*;
109  /// let f = format!("{:?}", m256::default());
110  /// assert_eq!(&f, "m256(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)");
111  /// ```
112  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
113    write!(f, "m256(")?;
114    for (i, float) in self.to_array().iter().enumerate() {
115      if i != 0 {
116        write!(f, ", ")?;
117      }
118      Debug::fmt(float, f)?;
119    }
120    write!(f, ")")
121  }
122}
123
124impl Display for m256 {
125  /// Display formats each float, and leaves the type name off of the font.
126  /// ```
127  /// # use safe_arch::*;
128  /// let f = format!("{}", m256::default());
129  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
130  /// ```
131  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
132    write!(f, "(")?;
133    for (i, float) in self.to_array().iter().enumerate() {
134      if i != 0 {
135        write!(f, ", ")?;
136      }
137      Display::fmt(float, f)?;
138    }
139    write!(f, ")")
140  }
141}
142
143impl Binary for m256 {
144  /// Binary formats each float's bit pattern (via [`f32::to_bits`]).
145  /// ```
146  /// # use safe_arch::*;
147  /// let f = format!("{:b}", m256::default());
148  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
149  /// ```
150  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
151    write!(f, "(")?;
152    for (i, float) in self.to_array().iter().enumerate() {
153      if i != 0 {
154        write!(f, ", ")?;
155      }
156      Binary::fmt(&float.to_bits(), f)?;
157    }
158    write!(f, ")")
159  }
160}
161
162impl LowerExp for m256 {
163  /// LowerExp formats each float.
164  /// ```
165  /// # use safe_arch::*;
166  /// let f = format!("{:e}", m256::default());
167  /// assert_eq!(&f, "(0e0, 0e0, 0e0, 0e0, 0e0, 0e0, 0e0, 0e0)");
168  /// ```
169  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
170    write!(f, "(")?;
171    for (i, float) in self.to_array().iter().enumerate() {
172      if i != 0 {
173        write!(f, ", ")?;
174      }
175      LowerExp::fmt(float, f)?;
176    }
177    write!(f, ")")
178  }
179}
180
181impl UpperExp for m256 {
182  /// UpperExp formats each float.
183  /// ```
184  /// # use safe_arch::*;
185  /// let f = format!("{:E}", m256::default());
186  /// assert_eq!(&f, "(0E0, 0E0, 0E0, 0E0, 0E0, 0E0, 0E0, 0E0)");
187  /// ```
188  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
189    write!(f, "(")?;
190    for (i, float) in self.to_array().iter().enumerate() {
191      if i != 0 {
192        write!(f, ", ")?;
193      }
194      UpperExp::fmt(float, f)?;
195    }
196    write!(f, ")")
197  }
198}
199
200impl LowerHex for m256 {
201  /// LowerHex formats each float's bit pattern (via [`f32::to_bits`]).
202  /// ```
203  /// # use safe_arch::*;
204  /// let f = format!("{:x}", m256::default());
205  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
206  /// ```
207  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
208    write!(f, "(")?;
209    for (i, float) in self.to_array().iter().enumerate() {
210      if i != 0 {
211        write!(f, ", ")?;
212      }
213      LowerHex::fmt(&float.to_bits(), f)?;
214    }
215    write!(f, ")")
216  }
217}
218
219impl UpperHex for m256 {
220  /// UpperHex formats each float's bit pattern (via [`f32::to_bits`]).
221  /// ```
222  /// # use safe_arch::*;
223  /// let f = format!("{:X}", m256::default());
224  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
225  /// ```
226  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
227    write!(f, "(")?;
228    for (i, float) in self.to_array().iter().enumerate() {
229      if i != 0 {
230        write!(f, ", ")?;
231      }
232      UpperHex::fmt(&float.to_bits(), f)?;
233    }
234    write!(f, ")")
235  }
236}
237
238impl Octal for m256 {
239  /// Octal formats each float's bit pattern (via [`f32::to_bits`]).
240  /// ```
241  /// # use safe_arch::*;
242  /// let f = format!("{:o}", m256::default());
243  /// assert_eq!(&f, "(0, 0, 0, 0, 0, 0, 0, 0)");
244  /// ```
245  fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
246    write!(f, "(")?;
247    for (i, float) in self.to_array().iter().enumerate() {
248      if i != 0 {
249        write!(f, ", ")?;
250      }
251      Octal::fmt(&float.to_bits(), f)?;
252    }
253    write!(f, ")")
254  }
255}