]>
git.proxmox.com Git - rustc.git/blob - library/stdarch/crates/stdarch-gen/src/main.rs
3 use std
::io
::prelude
::*;
4 use std
::io
::{self, BufReader}
;
5 use std
::path
::PathBuf
;
7 const IN
: &str = "neon.spec";
8 const ARM_OUT
: &str = "generated.rs";
9 const AARCH64_OUT
: &str = "generated.rs";
11 const UINT_TYPES
: [&str; 6] = [
20 const UINT_TYPES_64
: [&str; 2] = ["uint64x1_t", "uint64x2_t"];
22 const INT_TYPES
: [&str; 6] = [
31 const INT_TYPES_64
: [&str; 2] = ["int64x1_t", "int64x2_t"];
33 const FLOAT_TYPES
: [&str; 2] = [
34 //"float8x8_t", not supported by rust
35 //"float8x16_t", not supported by rust
36 //"float16x4_t", not supported by rust
37 //"float16x8_t", not supported by rust
42 const FLOAT_TYPES_64
: [&str; 2] = [
43 //"float8x8_t", not supported by rust
44 //"float8x16_t", not supported by rust
45 //"float16x4_t", not supported by rust
46 //"float16x8_t", not supported by rust
51 fn type_len(t
: &str) -> usize {
77 _
=> panic
!("unknown type: {}", t
),
81 fn type_to_suffix(t
: &str) -> &str {
84 "int8x16_t" => "q_s8",
85 "int16x4_t" => "_s16",
86 "int16x8_t" => "q_s16",
87 "int32x2_t" => "_s32",
88 "int32x4_t" => "q_s32",
89 "int64x1_t" => "_s64",
90 "int64x2_t" => "q_s64",
92 "uint8x16_t" => "q_u8",
93 "uint16x4_t" => "_u16",
94 "uint16x8_t" => "q_u16",
95 "uint32x2_t" => "_u32",
96 "uint32x4_t" => "q_u32",
97 "uint64x1_t" => "_u64",
98 "uint64x2_t" => "q_u64",
99 "float16x4_t" => "_f16",
100 "float16x8_t" => "q_f16",
101 "float32x2_t" => "_f32",
102 "float32x4_t" => "q_f32",
103 "float64x1_t" => "_f64",
104 "float64x2_t" => "q_f64",
105 "poly64x1_t" => "_p64",
106 "poly64x2_t" => "q_p64",
107 _
=> panic
!("unknown type: {}", t
),
111 fn type_to_global_type(t
: &str) -> &str {
113 "int8x8_t" => "i8x8",
114 "int8x16_t" => "i8x16",
115 "int16x4_t" => "i16x4",
116 "int16x8_t" => "i16x8",
117 "int32x2_t" => "i32x2",
118 "int32x4_t" => "i32x4",
119 "int64x1_t" => "i64x1",
120 "int64x2_t" => "i64x2",
121 "uint8x8_t" => "u8x8",
122 "uint8x16_t" => "u8x16",
123 "uint16x4_t" => "u16x4",
124 "uint16x8_t" => "u16x8",
125 "uint32x2_t" => "u32x2",
126 "uint32x4_t" => "u32x4",
127 "uint64x1_t" => "u64x1",
128 "uint64x2_t" => "u64x2",
129 "float16x4_t" => "f16x4",
130 "float16x8_t" => "f16x8",
131 "float32x2_t" => "f32x2",
132 "float32x4_t" => "f32x4",
133 "float64x1_t" => "f64",
134 "float64x2_t" => "f64x2",
135 "poly64x1_t" => "i64x1",
136 "poly64x2_t" => "i64x2",
137 _
=> panic
!("unknown type: {}", t
),
141 // fn type_to_native_type(t: &str) -> &str {
143 // "int8x8_t" => "i8",
144 // "int8x16_t" => "i8",
145 // "int16x4_t" => "i16",
146 // "int16x8_t" => "i16",
147 // "int32x2_t" => "i32",
148 // "int32x4_t" => "i32",
149 // "int64x1_t" => "i64",
150 // "int64x2_t" => "i64",
151 // "uint8x8_t" => "u8",
152 // "uint8x16_t" => "u8",
153 // "uint16x4_t" => "u16",
154 // "uint16x8_t" => "u16",
155 // "uint32x2_t" => "u32",
156 // "uint32x4_t" => "u32",
157 // "uint64x1_t" => "u64",
158 // "uint64x2_t" => "u64",
159 // "float16x4_t" => "f16",
160 // "float16x8_t" => "f16",
161 // "float32x2_t" => "f32",
162 // "float32x4_t" => "f32",
163 // "float64x1_t" => "f64",
164 // "float64x2_t" => "f64",
165 // "poly64x1_t" => "i64",
166 // "poly64x2_t" => "i64",
167 // _ => panic!("unknown type: {}", t),
171 fn type_to_ext(t
: &str) -> &str {
173 "int8x8_t" => "v8i8",
174 "int8x16_t" => "v16i8",
175 "int16x4_t" => "v4i16",
176 "int16x8_t" => "v8i16",
177 "int32x2_t" => "v2i32",
178 "int32x4_t" => "v4i32",
179 "int64x1_t" => "v1i64",
180 "int64x2_t" => "v2i64",
181 "uint8x8_t" => "v8i8",
182 "uint8x16_t" => "v16i8",
183 "uint16x4_t" => "v4i16",
184 "uint16x8_t" => "v8i16",
185 "uint32x2_t" => "v2i32",
186 "uint32x4_t" => "v4i32",
187 "uint64x1_t" => "v1i64",
188 "uint64x2_t" => "v2i64",
189 "float16x4_t" => "v4f16",
190 "float16x8_t" => "v8f16",
191 "float32x2_t" => "v2f32",
192 "float32x4_t" => "v4f32",
193 "float64x1_t" => "v1f64",
194 "float64x2_t" => "v2f64",
196 "poly64x1_t" => "i64x1",
197 "poly64x2_t" => "i64x2",
199 _
=> panic
!("unknown type for extension: {}", t
),
203 fn values(t
: &str, vs
: &[String
]) -> String
{
204 if vs
.len() == 1 && !t
.contains('x'
) {
205 format
!(": {} = {}", t
, vs
[0])
206 } else if vs
.len() == 1 && type_to_global_type(t
) == "f64" {
207 format
!(": {} = {}", type_to_global_type(t
), vs
[0])
210 ": {} = {}::new({})",
211 type_to_global_type(t
),
212 type_to_global_type(t
),
214 .map(|v
| map_val(type_to_global_type(t
), v
))
215 //.map(|v| format!("{}{}", v, type_to_native_type(t)))
222 fn max_val(t
: &str) -> &'
static str {
226 "u32" => "0xFF_FF_FF_FF",
227 "u64" => "0xFF_FF_FF_FF_FF_FF_FF_FF",
230 "i32" => "0x7F_FF_FF_FF",
231 "i64" => "0x7F_FF_FF_FF_FF_FF_FF_FF",
232 "f32" => "3.40282347e+38",
233 "f64" => "1.7976931348623157e+308",
234 _
=> panic
!("No TRUE for type {}", t
),
238 fn min_val(t
: &str) -> &'
static str {
246 "i32" => "-2147483648",
247 "i64" => "-9223372036854775808",
248 "f32" => "-3.40282347e+38",
249 "f64" => "-1.7976931348623157e+308",
250 _
=> panic
!("No TRUE for type {}", t
),
254 fn true_val(t
: &str) -> &'
static str {
258 "u32" => "0xFF_FF_FF_FF",
259 "u64" => "0xFF_FF_FF_FF_FF_FF_FF_FF",
260 _
=> panic
!("No TRUE for type {}", t
),
264 fn ff_val(t
: &str) -> &'
static str {
268 "u32" => "0xFF_FF_FF_FF",
269 "u64" => "0xFF_FF_FF_FF_FF_FF_FF_FF",
272 "i32" => "0xFF_FF_FF_FF",
273 "i64" => "0xFF_FF_FF_FF_FF_FF_FF_FF",
274 _
=> panic
!("No TRUE for type {}", t
),
278 fn false_val(_t
: &str) -> &'
static str {
281 fn map_val
<'v
>(t
: &str, v
: &'v
str) -> &'v
str {
283 "FALSE" => false_val(t
),
284 "TRUE" => true_val(t
),
292 #[allow(clippy::too_many_arguments)]
294 current_comment
: &str,
295 current_fn
: &Option
<String
>,
297 current_aarch64
: &Option
<String
>,
298 link_aarch64
: &Option
<String
>,
301 current_tests
: &[(Vec
<String
>, Vec
<String
>, Vec
<String
>)],
302 ) -> (String
, String
) {
303 let _global_t
= type_to_global_type(in_t
);
304 let _global_ret_t
= type_to_global_type(out_t
);
305 let current_fn
= if let Some(current_fn
) = current_fn
.clone() {
306 if link_aarch64
.is_some() {
307 panic
!("[{}] Can't specify link and fn at the same time.", name
)
311 if link_aarch64
.is_none() {
312 panic
!("[{}] Either fn or link-aarch have to be specified.", name
)
316 let current_aarch64
= current_aarch64
.clone().unwrap();
317 let ext_c
= if let Some(link_aarch64
) = link_aarch64
.clone() {
318 let ext
= type_to_ext(in_t
);
321 r
#"#[allow(improper_ctypes)]
323 #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.{}")]
324 fn {}(a: {}, a: {}) -> {};
327 link_aarch64
.replace("_EXT_", ext
),
336 let function
= format
!(
340 #[target_feature(enable = "neon")]
341 #[cfg_attr(test, assert_instr({}))]
342 pub unsafe fn {}(a: {}, b: {}) -> {} {{
346 current_comment
, current_aarch64
, name
, in_t
, in_t
, out_t
, ext_c
, current_fn
,
349 let test
= gen_test(name
, &in_t
, &out_t
, current_tests
, type_len(in_t
));
357 current_tests
: &[(Vec
<String
>, Vec
<String
>, Vec
<String
>)],
360 let mut test
= format
!(
362 #[simd_test(enable = "neon")]
363 unsafe fn test_{}() {{"#,
366 for (a
, b
, e
) in current_tests
{
367 let a
: Vec
<String
> = a
.iter().take(len
).cloned().collect();
368 let b
: Vec
<String
> = b
.iter().take(len
).cloned().collect();
369 let e
: Vec
<String
> = e
.iter().take(len
).cloned().collect();
375 let r: {} = transmute({}(transmute(a), transmute(b)));
381 type_to_global_type(out_t
),
386 test
.push_str(" }\n");
390 #[allow(clippy::too_many_arguments)]
392 current_comment
: &str,
393 current_fn
: &Option
<String
>,
396 link_arm
: &Option
<String
>,
397 current_aarch64
: &Option
<String
>,
398 link_aarch64
: &Option
<String
>,
401 current_tests
: &[(Vec
<String
>, Vec
<String
>, Vec
<String
>)],
402 ) -> (String
, String
) {
403 let _global_t
= type_to_global_type(in_t
);
404 let _global_ret_t
= type_to_global_type(out_t
);
405 let current_aarch64
= current_aarch64
407 .unwrap_or_else(|| current_arm
.to_string());
409 let current_fn
= if let Some(current_fn
) = current_fn
.clone() {
410 if link_aarch64
.is_some() || link_arm
.is_some() {
412 "[{}] Can't specify link and function at the same time. {} / {:?} / {:?}",
413 name
, current_fn
, link_aarch64
, link_arm
418 if link_aarch64
.is_none() || link_arm
.is_none() {
420 "[{}] Either fn or link-arm and link-aarch have to be specified.",
428 if let (Some(link_arm
), Some(link_aarch64
)) = (link_arm
.clone(), link_aarch64
.clone()) {
429 let ext
= type_to_ext(in_t
);
432 r
#"#[allow(improper_ctypes)]
434 #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.{}")]
435 #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.{}")]
436 fn {}(a: {}, b: {}) -> {};
439 link_arm
.replace("_EXT_", ext
),
440 link_aarch64
.replace("_EXT_", ext
),
450 let function
= format
!(
454 #[target_feature(enable = "neon")]
455 #[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))]
456 #[cfg_attr(all(test, target_arch = "arm"), assert_instr({}))]
457 #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr({}))]
458 pub unsafe fn {}(a: {}, b: {}) -> {} {{
463 expand_intrinsic(¤t_arm
, in_t
),
464 expand_intrinsic(¤t_aarch64
, in_t
),
472 let test
= gen_test(name
, &in_t
, &out_t
, current_tests
, type_len(in_t
));
477 fn expand_intrinsic(intr
: &str, t
: &str) -> String
{
478 if intr
.ends_with('
.'
) {
482 "int16x4_t" => "i16",
483 "int16x8_t" => "i16",
484 "int32x2_t" => "i32",
485 "int32x4_t" => "i32",
486 "int64x1_t" => "i64",
487 "int64x2_t" => "i64",
489 "uint8x16_t" => "i8",
490 "uint16x4_t" => "i16",
491 "uint16x8_t" => "i16",
492 "uint32x2_t" => "i32",
493 "uint32x4_t" => "i32",
494 "uint64x1_t" => "i64",
495 "uint64x2_t" => "i64",
496 "float16x4_t" => "f16",
497 "float16x8_t" => "f16",
498 "float32x2_t" => "f32",
499 "float32x4_t" => "f32",
500 "float64x1_t" => "f64",
501 "float64x2_t" => "f64",
503 "poly64x1_t" => "i64x1",
504 "poly64x2_t" => "i64x2",
506 _
=> panic
!("unknown type for extension: {}", t
),
508 format
!(r
#""{}{}""#, intr, ext)
509 } else if intr
.ends_with(".s") {
513 "int16x4_t" => "s16",
514 "int16x8_t" => "s16",
515 "int32x2_t" => "s32",
516 "int32x4_t" => "s32",
517 "int64x1_t" => "s64",
518 "int64x2_t" => "s64",
520 "uint8x16_t" => "u8",
521 "uint16x4_t" => "u16",
522 "uint16x8_t" => "u16",
523 "uint32x2_t" => "u32",
524 "uint32x4_t" => "u32",
525 "uint64x1_t" => "u64",
526 "uint64x2_t" => "u64",
527 "float16x4_t" => "f16",
528 "float16x8_t" => "f16",
529 "float32x2_t" => "f32",
530 "float32x4_t" => "f32",
531 "float64x1_t" => "f64",
532 "float64x2_t" => "f64",
534 "poly64x1_t" => "i64x1",
535 "poly64x2_t" => "i64x2",
537 _
=> panic
!("unknown type for extension: {}", t
),
539 format
!(r
#""{}{}""#, &intr[..intr.len() - 1], ext)
545 fn main() -> io
::Result
<()> {
546 let args
: Vec
<String
> = env
::args().collect();
547 let in_file
= args
.get(1).cloned().unwrap_or_else(|| IN
.to_string());
549 let f
= File
::open(in_file
).expect("Failed to open neon.spec");
550 let f
= BufReader
::new(f
);
552 let mut current_comment
= String
::new();
553 let mut current_name
: Option
<String
> = None
;
554 let mut current_fn
: Option
<String
> = None
;
555 let mut current_arm
: Option
<String
> = None
;
556 let mut current_aarch64
: Option
<String
> = None
;
557 let mut link_arm
: Option
<String
> = None
;
558 let mut link_aarch64
: Option
<String
> = None
;
559 let mut a
: Vec
<String
> = Vec
::new();
560 let mut b
: Vec
<String
> = Vec
::new();
561 let mut current_tests
: Vec
<(Vec
<String
>, Vec
<String
>, Vec
<String
>)> = Vec
::new();
564 // THIS FILE IS GENERATED FORM neon.spec DO NOT CHANGE IT MANUALLY
566 let mut out_arm
= String
::from(
567 r
#"// This code is automatically generated. DO NOT MODIFY.
569 // Instead, modify `crates/stdarch-gen/neon.spec` and run the following command to re-generate this file:
572 // OUT_DIR=`pwd`/crates/core_arch cargo run -p stdarch-gen -- crates/stdarch-gen/neon.spec
576 use stdarch_test::assert_instr;
579 let mut tests_arm
= String
::from(
582 #[allow(overflowing_literals)]
585 use crate::core_arch::simd::*;
586 use std::mem::transmute;
587 use stdarch_test::simd_test;
591 // THIS FILE IS GENERATED FORM neon.spec DO NOT CHANGE IT MANUALLY
593 let mut out_aarch64
= String
::from(
594 r
#"// This code is automatically generated. DO NOT MODIFY.
596 // Instead, modify `crates/stdarch-gen/neon.spec` and run the following command to re-generate this file:
599 // OUT_DIR=`pwd`/crates/core_arch cargo run -p stdarch-gen -- crates/stdarch-gen/neon.spec
603 use stdarch_test::assert_instr;
606 let mut tests_aarch64
= String
::from(
611 use crate::core_arch::simd::*;
612 use std::mem::transmute;
613 use stdarch_test::simd_test;
617 for line
in f
.lines() {
618 let line
= line
.unwrap();
622 if line
.starts_with("/// ") {
623 current_comment
= line
;
627 current_aarch64
= None
;
630 current_tests
= Vec
::new();
631 } else if line
.starts_with("//") {
632 } else if line
.starts_with("name = ") {
633 current_name
= Some(String
::from(&line
[7..]));
634 } else if line
.starts_with("fn = ") {
635 current_fn
= Some(String
::from(&line
[5..]));
636 } else if line
.starts_with("arm = ") {
637 current_arm
= Some(String
::from(&line
[6..]));
638 } else if line
.starts_with("aarch64 = ") {
639 current_aarch64
= Some(String
::from(&line
[10..]));
640 } else if line
.starts_with("a = ") {
641 a
= line
[4..].split('
,'
).map(|v
| v
.trim().to_string()).collect();
642 } else if line
.starts_with("b = ") {
643 b
= line
[4..].split('
,'
).map(|v
| v
.trim().to_string()).collect();
644 } else if line
.starts_with("validate ") {
645 let e
= line
[9..].split('
,'
).map(|v
| v
.trim().to_string()).collect();
646 current_tests
.push((a
.clone(), b
.clone(), e
));
647 } else if line
.starts_with("link-aarch64 = ") {
648 link_aarch64
= Some(String
::from(&line
[15..]));
649 } else if line
.starts_with("link-arm = ") {
650 link_arm
= Some(String
::from(&line
[11..]));
651 } else if line
.starts_with("generate ") {
652 let line
= &line
[9..];
653 let types
: Vec
<String
> = line
655 .map(|v
| v
.trim().to_string())
656 .flat_map(|v
| match v
.as_str() {
657 "uint*_t" => UINT_TYPES
.iter().map(|v
| v
.to_string()).collect(),
658 "uint64x*_t" => UINT_TYPES_64
.iter().map(|v
| v
.to_string()).collect(),
659 "int*_t" => INT_TYPES
.iter().map(|v
| v
.to_string()).collect(),
660 "int64x*_t" => INT_TYPES_64
.iter().map(|v
| v
.to_string()).collect(),
661 "float*_t" => FLOAT_TYPES
.iter().map(|v
| v
.to_string()).collect(),
662 "float64x*_t" => FLOAT_TYPES_64
.iter().map(|v
| v
.to_string()).collect(),
668 let spec
: Vec
<&str> = line
.split('
:'
).map(|e
| e
.trim()).collect();
674 } else if spec
.len() == 2 {
678 panic
!("Bad spec: {}", line
)
680 let current_name
= current_name
.clone().unwrap();
681 let name
= format
!("{}{}", current_name
, type_to_suffix(in_t
),);
683 if let Some(current_arm
) = current_arm
.clone() {
684 let (function
, test
) = gen_arm(
696 out_arm
.push_str(&function
);
697 tests_arm
.push_str(&test
);
699 let (function
, test
) = gen_aarch64(
709 out_aarch64
.push_str(&function
);
710 tests_aarch64
.push_str(&test
);
716 tests_arm
.push('
\n'
);
717 tests_aarch64
.push('
}'
);
718 tests_aarch64
.push('
\n'
);
720 let arm_out_path
: PathBuf
= PathBuf
::from(env
::var("OUT_DIR").unwrap())
724 std
::fs
::create_dir_all(&arm_out_path
)?
;
726 let mut file_arm
= File
::create(arm_out_path
.join(ARM_OUT
))?
;
727 file_arm
.write_all(out_arm
.as_bytes())?
;
728 file_arm
.write_all(tests_arm
.as_bytes())?
;
730 let aarch64_out_path
: PathBuf
= PathBuf
::from(env
::var("OUT_DIR").unwrap())
734 std
::fs
::create_dir_all(&aarch64_out_path
)?
;
736 let mut file_aarch
= File
::create(aarch64_out_path
.join(AARCH64_OUT
))?
;
737 file_aarch
.write_all(out_aarch64
.as_bytes())?
;
738 file_aarch
.write_all(tests_aarch64
.as_bytes())?
;
740 if let Err(e) = Command::new("rustfmt")
742 .arg(&aarch64_out_path)
744 eprintln!("Could not format `{}`: {}", arm_out_path.to_str().unwrap(), e);
745 eprintln!("Could not format `{}`: {}", aarch64_out_path.to_str().unwrap(), e);