]> git.proxmox.com Git - rustc.git/blame - library/stdarch/crates/intrinsic-test/src/types.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / library / stdarch / crates / intrinsic-test / src / types.rs
CommitLineData
c295e0f8
XL
1use std::fmt;
2use std::str::FromStr;
3
f2b60f7d 4use crate::values::value_for_array;
c295e0f8
XL
5use crate::Language;
6
7#[derive(Debug, PartialEq, Copy, Clone)]
8pub enum TypeKind {
9 BFloat,
10 Float,
11 Int,
12 UInt,
13 Poly,
14 Void,
15}
16
17impl FromStr for TypeKind {
18 type Err = String;
19
20 fn from_str(s: &str) -> Result<Self, Self::Err> {
21 match s {
22 "bfloat" => Ok(Self::BFloat),
23 "float" => Ok(Self::Float),
24 "int" => Ok(Self::Int),
25 "poly" => Ok(Self::Poly),
26 "uint" | "unsigned" => Ok(Self::UInt),
27 "void" => Ok(Self::Void),
9ffffee4 28 _ => Err(format!("Impossible to parse argument kind {s}")),
c295e0f8
XL
29 }
30 }
31}
32
33impl fmt::Display for TypeKind {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(
36 f,
37 "{}",
38 match self {
39 Self::BFloat => "bfloat",
40 Self::Float => "float",
41 Self::Int => "int",
42 Self::UInt => "uint",
43 Self::Poly => "poly",
44 Self::Void => "void",
45 }
46 )
47 }
48}
49
50impl TypeKind {
51 /// Gets the type part of a c typedef for a type that's in the form of {type}{size}_t.
52 pub fn c_prefix(&self) -> &str {
53 match self {
54 Self::Float => "float",
55 Self::Int => "int",
56 Self::UInt => "uint",
57 Self::Poly => "poly",
58 _ => unreachable!("Not used: {:#?}", self),
59 }
60 }
61
62 /// Gets the rust prefix for the type kind i.e. i, u, f.
63 pub fn rust_prefix(&self) -> &str {
64 match self {
65 Self::Float => "f",
66 Self::Int => "i",
67 Self::UInt => "u",
68 Self::Poly => "u",
69 _ => unreachable!("Unused type kind: {:#?}", self),
70 }
71 }
72}
73
74#[derive(Debug, PartialEq, Clone)]
75pub enum IntrinsicType {
76 Ptr {
77 constant: bool,
78 child: Box<IntrinsicType>,
79 },
80 Type {
81 constant: bool,
82 kind: TypeKind,
83 /// The bit length of this type (e.g. 32 for u32).
84 bit_len: Option<u32>,
85
86 /// Length of the SIMD vector (i.e. 4 for uint32x4_t), A value of `None`
87 /// means this is not a simd type. A `None` can be assumed to be 1,
88 /// although in some places a distinction is needed between `u64` and
89 /// `uint64x1_t` this signals that.
90 simd_len: Option<u32>,
91
92 /// The number of rows for SIMD matrices (i.e. 2 for uint8x8x2_t).
93 /// A value of `None` represents a type that does not contain any
94 /// rows encoded in the type (e.g. uint8x8_t).
95 /// A value of `None` can be assumed to be 1 though.
96 vec_len: Option<u32>,
97 },
98}
99
100impl IntrinsicType {
101 /// Get the TypeKind for this type, recursing into pointers.
102 pub fn kind(&self) -> TypeKind {
103 match *self {
104 IntrinsicType::Ptr { ref child, .. } => child.kind(),
105 IntrinsicType::Type { kind, .. } => kind,
106 }
107 }
108
109 /// Get the size of a single element inside this type, recursing into
110 /// pointers, i.e. a pointer to a u16 would be 16 rather than the size
111 /// of a pointer.
112 pub fn inner_size(&self) -> u32 {
113 match *self {
114 IntrinsicType::Ptr { ref child, .. } => child.inner_size(),
115 IntrinsicType::Type {
116 bit_len: Some(bl), ..
117 } => bl,
118 _ => unreachable!(""),
119 }
120 }
121
122 pub fn num_lanes(&self) -> u32 {
123 match *self {
124 IntrinsicType::Ptr { ref child, .. } => child.num_lanes(),
125 IntrinsicType::Type {
126 simd_len: Some(sl), ..
127 } => sl,
128 _ => 1,
129 }
130 }
131
3c0e092e
XL
132 pub fn num_vectors(&self) -> u32 {
133 match *self {
134 IntrinsicType::Ptr { ref child, .. } => child.num_vectors(),
135 IntrinsicType::Type {
136 vec_len: Some(vl), ..
137 } => vl,
138 _ => 1,
139 }
140 }
141
c295e0f8
XL
142 /// Determine if the type is a simd type, this will treat a type such as
143 /// `uint64x1` as simd.
144 pub fn is_simd(&self) -> bool {
145 match *self {
146 IntrinsicType::Ptr { ref child, .. } => child.is_simd(),
147 IntrinsicType::Type {
148 simd_len: None,
149 vec_len: None,
150 ..
151 } => false,
152 _ => true,
153 }
154 }
155
156 pub fn is_ptr(&self) -> bool {
157 match *self {
158 IntrinsicType::Ptr { .. } => true,
159 IntrinsicType::Type { .. } => false,
160 }
161 }
162
f2b60f7d 163 pub fn c_scalar_type(&self) -> String {
c295e0f8
XL
164 format!(
165 "{prefix}{bits}_t",
166 prefix = self.kind().c_prefix(),
167 bits = self.inner_size()
168 )
169 }
170
f2b60f7d 171 pub fn rust_scalar_type(&self) -> String {
c295e0f8
XL
172 format!(
173 "{prefix}{bits}",
174 prefix = self.kind().rust_prefix(),
175 bits = self.inner_size()
176 )
177 }
178
179 /// Gets a string containing the typename for this type in C format.
180 pub fn c_type(&self) -> String {
181 match self {
182 IntrinsicType::Ptr { child, .. } => child.c_type(),
183 IntrinsicType::Type {
184 constant,
185 kind,
186 bit_len: Some(bit_len),
187 simd_len: None,
188 vec_len: None,
189 ..
190 } => format!(
191 "{}{}{}_t",
192 if *constant { "const " } else { "" },
193 kind.c_prefix(),
194 bit_len
195 ),
196 IntrinsicType::Type {
197 kind,
198 bit_len: Some(bit_len),
199 simd_len: Some(simd_len),
200 vec_len: None,
201 ..
9ffffee4 202 } => format!("{}{bit_len}x{simd_len}_t", kind.c_prefix()),
c295e0f8
XL
203 IntrinsicType::Type {
204 kind,
205 bit_len: Some(bit_len),
206 simd_len: Some(simd_len),
207 vec_len: Some(vec_len),
208 ..
9ffffee4 209 } => format!("{}{bit_len}x{simd_len}x{vec_len}_t", kind.c_prefix()),
c295e0f8
XL
210 _ => todo!("{:#?}", self),
211 }
212 }
213
3c0e092e
XL
214 pub fn c_single_vector_type(&self) -> String {
215 match self {
216 IntrinsicType::Ptr { child, .. } => child.c_single_vector_type(),
217 IntrinsicType::Type {
218 kind,
219 bit_len: Some(bit_len),
220 simd_len: Some(simd_len),
221 vec_len: Some(_),
222 ..
9ffffee4 223 } => format!("{}{bit_len}x{simd_len}_t", kind.c_prefix()),
3c0e092e
XL
224 _ => unreachable!("Shouldn't be called on this type"),
225 }
226 }
227
228 pub fn rust_type(&self) -> String {
229 match self {
230 IntrinsicType::Ptr { child, .. } => child.c_type(),
231 IntrinsicType::Type {
232 kind,
233 bit_len: Some(bit_len),
234 simd_len: None,
235 vec_len: None,
236 ..
9ffffee4 237 } => format!("{}{bit_len}", kind.rust_prefix()),
3c0e092e
XL
238 IntrinsicType::Type {
239 kind,
240 bit_len: Some(bit_len),
241 simd_len: Some(simd_len),
242 vec_len: None,
243 ..
9ffffee4 244 } => format!("{}{bit_len}x{simd_len}_t", kind.c_prefix()),
3c0e092e
XL
245 IntrinsicType::Type {
246 kind,
247 bit_len: Some(bit_len),
248 simd_len: Some(simd_len),
249 vec_len: Some(vec_len),
250 ..
9ffffee4 251 } => format!("{}{bit_len}x{simd_len}x{vec_len}_t", kind.c_prefix()),
3c0e092e
XL
252 _ => todo!("{:#?}", self),
253 }
254 }
255
c295e0f8
XL
256 /// Gets a cast for this type if needs promotion.
257 /// This is required for 8 bit types due to printing as the 8 bit types use
258 /// a char and when using that in `std::cout` it will print as a character,
259 /// which means value of 0 will be printed as a null byte.
a2a8927a
XL
260 ///
261 /// This is also needed for polynomial types because we want them to be
262 /// printed as unsigned integers to match Rust's `Debug` impl.
c295e0f8
XL
263 pub fn c_promotion(&self) -> &str {
264 match *self {
265 IntrinsicType::Type {
266 kind,
267 bit_len: Some(bit_len),
268 ..
269 } if bit_len == 8 => match kind {
270 TypeKind::Int => "(int)",
271 TypeKind::UInt => "(unsigned int)",
a2a8927a 272 TypeKind::Poly => "(unsigned int)(uint8_t)",
c295e0f8
XL
273 _ => "",
274 },
a2a8927a
XL
275 IntrinsicType::Type {
276 kind: TypeKind::Poly,
277 bit_len: Some(bit_len),
278 ..
279 } => match bit_len {
280 8 => unreachable!("handled above"),
281 16 => "(uint16_t)",
282 32 => "(uint32_t)",
283 64 => "(uint64_t)",
284 128 => "",
285 _ => panic!("invalid bit_len"),
286 },
c295e0f8
XL
287 _ => "",
288 }
289 }
290
f2b60f7d
FG
291 /// Generates a comma list of values that can be used to initialize the array that
292 /// an argument for the intrinsic call is loaded from.
c295e0f8
XL
293 /// This is determistic based on the pass number.
294 ///
f2b60f7d
FG
295 /// * `loads`: The number of values that need to be loaded from the argument array
296 /// * e.g for argument type uint32x2, loads=2 results in a string representing 4 32-bit values
c295e0f8
XL
297 ///
298 /// Returns a string such as
299 /// * `0x1, 0x7F, 0xFF` if `language` is `Language::C`
300 /// * `0x1 as _, 0x7F as _, 0xFF as _` if `language` is `Language::Rust`
f2b60f7d 301 pub fn populate_random(&self, loads: u32, language: &Language) -> String {
c295e0f8 302 match self {
f2b60f7d 303 IntrinsicType::Ptr { child, .. } => child.populate_random(loads, language),
c295e0f8
XL
304 IntrinsicType::Type {
305 bit_len: Some(bit_len),
306 kind,
307 simd_len,
308 vec_len,
309 ..
310 } if kind == &TypeKind::Int || kind == &TypeKind::UInt || kind == &TypeKind::Poly => (0
f2b60f7d 311 ..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
c295e0f8
XL
312 .map(|i| {
313 format!(
314 "{}{}",
f2b60f7d 315 value_for_array(*bit_len, i),
c295e0f8
XL
316 match language {
317 &Language::Rust => format!(" as {ty} ", ty = self.rust_scalar_type()),
318 &Language::C => String::from(""),
319 }
320 )
321 })
322 .collect::<Vec<_>>()
323 .join(","),
324 IntrinsicType::Type {
325 kind: TypeKind::Float,
326 bit_len: Some(32),
327 simd_len,
328 vec_len,
329 ..
f2b60f7d 330 } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
c295e0f8
XL
331 .map(|i| {
332 format!(
333 "{}({})",
334 match language {
f2b60f7d 335 &Language::Rust => "std::mem::transmute",
c295e0f8
XL
336 &Language::C => "cast<float, uint32_t>",
337 },
f2b60f7d 338 value_for_array(32, i),
c295e0f8
XL
339 )
340 })
341 .collect::<Vec<_>>()
342 .join(","),
343 IntrinsicType::Type {
344 kind: TypeKind::Float,
345 bit_len: Some(64),
346 simd_len,
347 vec_len,
348 ..
f2b60f7d 349 } => (0..(simd_len.unwrap_or(1) * vec_len.unwrap_or(1) + loads - 1))
c295e0f8
XL
350 .map(|i| {
351 format!(
352 "{}({}{})",
353 match language {
f2b60f7d 354 &Language::Rust => "std::mem::transmute",
c295e0f8
XL
355 &Language::C => "cast<double, uint64_t>",
356 },
f2b60f7d 357 value_for_array(64, i),
c295e0f8
XL
358 match language {
359 &Language::Rust => " as u64",
360 &Language::C => "",
361 }
362 )
363 })
364 .collect::<Vec<_>>()
365 .join(","),
366 _ => unreachable!("populate random: {:#?}", self),
367 }
368 }
369
370 /// Determines the load function for this type.
f2b60f7d 371 pub fn get_load_function(&self, armv7_p64_workaround: bool) -> String {
c295e0f8 372 match self {
f2b60f7d 373 IntrinsicType::Ptr { child, .. } => child.get_load_function(armv7_p64_workaround),
c295e0f8
XL
374 IntrinsicType::Type {
375 kind: k,
376 bit_len: Some(bl),
377 simd_len,
378 vec_len,
379 ..
380 } => {
f2b60f7d 381 let quad = if simd_len.unwrap_or(1) * bl > 64 {
c295e0f8
XL
382 "q"
383 } else {
384 ""
385 };
386 format!(
387 "vld{len}{quad}_{type}{size}",
388 type = match k {
389 TypeKind::UInt => "u",
390 TypeKind::Int => "s",
391 TypeKind::Float => "f",
f2b60f7d
FG
392 // The ACLE doesn't support 64-bit polynomial loads on Armv7
393 TypeKind::Poly => if armv7_p64_workaround && *bl == 64 {"s"} else {"p"},
c295e0f8
XL
394 x => todo!("get_load_function TypeKind: {:#?}", x),
395 },
396 size = bl,
397 quad = quad,
398 len = vec_len.unwrap_or(1),
399 )
400 }
401 _ => todo!("get_load_function IntrinsicType: {:#?}", self),
402 }
403 }
404
405 /// Determines the get lane function for this type.
406 pub fn get_lane_function(&self) -> String {
407 match self {
408 IntrinsicType::Ptr { child, .. } => child.get_lane_function(),
409 IntrinsicType::Type {
410 kind: k,
411 bit_len: Some(bl),
412 simd_len,
413 ..
414 } => {
415 let quad = if (simd_len.unwrap_or(1) * bl) > 64 {
416 "q"
417 } else {
418 ""
419 };
420 format!(
421 "vget{quad}_lane_{type}{size}",
422 type = match k {
423 TypeKind::UInt => "u",
424 TypeKind::Int => "s",
425 TypeKind::Float => "f",
426 TypeKind::Poly => "p",
427 x => todo!("get_load_function TypeKind: {:#?}", x),
428 },
429 size = bl,
430 quad = quad,
431 )
432 }
433 _ => todo!("get_lane_function IntrinsicType: {:#?}", self),
434 }
435 }
436}