diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:39 +0000 |
commit | 1376c5a617be5c25655d0d7cb63e3beaa5a6e026 (patch) | |
tree | 3bb8d61aee02bc7a15eab3f36e3b921afc2075d0 /library/stdarch/crates/stdarch-gen/src | |
parent | Releasing progress-linux version 1.69.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.tar.xz rustc-1376c5a617be5c25655d0d7cb63e3beaa5a6e026.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/stdarch/crates/stdarch-gen/src')
-rw-r--r-- | library/stdarch/crates/stdarch-gen/src/main.rs | 389 |
1 files changed, 241 insertions, 148 deletions
diff --git a/library/stdarch/crates/stdarch-gen/src/main.rs b/library/stdarch/crates/stdarch-gen/src/main.rs index 750e88091..652aee88c 100644 --- a/library/stdarch/crates/stdarch-gen/src/main.rs +++ b/library/stdarch/crates/stdarch-gen/src/main.rs @@ -1,6 +1,7 @@ use self::Suffix::*; use self::TargetFeature::*; use std::env; +use std::fmt; use std::fs::File; use std::io::prelude::*; use std::io::{self, BufReader}; @@ -470,6 +471,199 @@ enum TargetFeature { FTTS, } +impl TargetFeature { + /// A string for use with `#[target_feature(...)]`. + fn as_target_feature_arg_aarch64(&self) -> &str { + match *self { + // Features included with AArch64 NEON. + Self::Default => "neon", + Self::ArmV7 => "neon", + Self::Vfp4 => "neon", + Self::FPArmV8 => "neon", + // Optional features. + Self::AES => "neon,aes", + Self::FCMA => "neon,fcma", + Self::Dotprod => "neon,dotprod", + Self::I8MM => "neon,i8mm", + Self::SHA3 => "neon,sha3", + Self::RDM => "rdm", + Self::SM4 => "neon,sm4", + Self::FTTS => "neon,frintts", + } + } + + /// A string for use with #[simd_test(...)] (or `is_aarch64_feature_detected!(...)`). + fn as_simd_test_arg_aarch64(&self) -> &str { + self.as_target_feature_arg_aarch64() + } + + /// A string for use with `#[target_feature(...)]`. + fn as_target_feature_arg_arm(&self) -> &str { + match *self { + Self::Default => "neon,v7", + Self::ArmV7 => "neon,v7", + Self::Vfp4 => "neon,vfp4", + Self::FPArmV8 => "neon,fp-armv8,v8", + Self::AES => "neon,v8,aes", + Self::FCMA => "neon,v8,fcma", + Self::Dotprod => "neon,v8,dotprod", + Self::I8MM => "neon,v8,i8mm", + // Features not supported on 32-bit "arm". + Self::SHA3 => unimplemented!(), + Self::RDM => unimplemented!(), + Self::SM4 => unimplemented!(), + Self::FTTS => unimplemented!(), + } + } + + /// A string for use with #[simd_test(...)] (or `is_arm_feature_detected!(...)`). + fn as_simd_test_arg_arm(&self) -> &str { + // TODO: Ideally, these would match the target_feature strings (as for AArch64). + match *self { + // We typically specify the "v7" or "v8" target_features for codegen, but we can't test + // them at runtime. However, in many cases we can test a specific named feature, and + // this is sufficient. For example, Neon always requires at least Armv7. + + // "v7" extensions. + Self::Default => "neon", + Self::ArmV7 => "neon", + + // TODO: We can specify these features for code generation, but they have no runtime + // detection, so we can't provide an accurate string for simd_test. For now, we use a + // common Armv8 feature as a proxy, but we should improve std_detect support here and + // update these accordingly. + Self::Vfp4 => "neon,crc", + Self::FPArmV8 => "neon,crc", + + // "v8" extensions. + Self::AES => "neon,aes", + Self::FCMA => "neon,fcma", + Self::Dotprod => "neon,dotprod", + Self::I8MM => "neon,i8mm", + + // Features not supported on 32-bit "arm". + Self::SHA3 => unimplemented!(), + Self::RDM => unimplemented!(), + Self::SM4 => unimplemented!(), + Self::FTTS => unimplemented!(), + } + } + + fn attr(name: &str, value: impl fmt::Display) -> String { + format!(r#"#[{name}(enable = "{value}")]"#) + } + + fn attr_for_arch(arch: &str, name: &str, value: impl fmt::Display) -> String { + format!(r#"#[cfg_attr(target_arch = "{arch}", {name}(enable = "{value}"))]"#) + } + + /// Generate target_feature attributes for a test that will compile for both "arm" and "aarch64". + fn to_target_feature_attr_shared(&self) -> Lines { + let arm = self.as_target_feature_arg_arm().split(","); + let aarch64 = self.as_target_feature_arg_aarch64().split(","); + + // Combine common features into an unconditional `target_feature` annotation, but guard + // others behind `cfg_attr`. + // TODO: It's much simpler to emit separate, guarded attributes for each architecture (as + // for `simd_test`). However, this has an unfortunate impact on documentation, since + // rustdoc can't currently look inside `cfg_attr` (stdarch/issues/1268). + let mut aarch64: Vec<_> = aarch64.collect(); + let (both, arm): (Vec<_>, Vec<_>) = arm.partition(|v| aarch64.contains(v)); + aarch64.retain(|v| !both.contains(v)); + let mut lines = Vec::new(); + if !both.is_empty() { + lines.push(Self::attr("target_feature", both.join(","))); + }; + if !arm.is_empty() { + lines.push(Self::attr_for_arch("arm", "target_feature", arm.join(","))); + } + if !aarch64.is_empty() { + lines.push(Self::attr_for_arch( + "aarch64", + "target_feature", + aarch64.join(","), + )); + } + lines.into() + } + + /// Generate a target_feature attribute for a test that will compile only for "aarch64". + fn to_target_feature_attr_aarch64(&self) -> Lines { + Lines::single(Self::attr( + "target_feature", + self.as_target_feature_arg_aarch64(), + )) + } + + /// Generate a target_feature attribute for a test that will compile only for "arm". + fn to_target_feature_attr_arm(&self) -> Lines { + Lines::single(Self::attr( + "target_feature", + self.as_target_feature_arg_arm(), + )) + } + + /// Generate simd_test attributes for a test that will compile for both "arm" and "aarch64". + fn to_simd_test_attr_shared(&self) -> Lines { + let arm = self.as_simd_test_arg_arm(); + let aarch64 = self.as_simd_test_arg_aarch64(); + if arm == aarch64 { + Lines::single(Self::attr("simd_test", arm)) + } else { + vec![ + Self::attr_for_arch("arm", "simd_test", arm), + Self::attr_for_arch("aarch64", "simd_test", aarch64), + ] + .into() + } + } + + /// Generate a simd_test attribute for a test that will compile only for "aarch64". + fn to_simd_test_attr_aarch64(&self) -> Lines { + Lines::single(Self::attr("simd_test", self.as_simd_test_arg_aarch64())) + } +} + +/// Complete lines of generated source. +/// +/// This enables common generation tasks to be factored out without precluding basic +/// context-specific formatting. +/// +/// The convention in this generator is to prefix (not suffix) lines with a newline, so the +/// implementation of `std::fmt::Display` behaves in the same way. +struct Lines { + indent: usize, + lines: Vec<String>, +} + +impl Lines { + fn indented(self, indent: usize) -> Self { + Self { + indent: indent + self.indent, + ..self + } + } + + fn single(line: String) -> Self { + Self::from(vec![line]) + } +} + +impl From<Vec<String>> for Lines { + fn from(lines: Vec<String>) -> Self { + Self { indent: 0, lines } + } +} + +impl std::fmt::Display for Lines { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { + for line in self.lines.iter() { + write!(f, "\n{:width$}{line}", "", width = self.indent)?; + } + Ok(()) + } +} + #[derive(Clone, Copy)] enum Fntype { Normal, @@ -1106,20 +1300,6 @@ fn gen_aarch64( Rot => type_to_rot_suffix(current_name, type_to_suffix(out_t)), RotLane => type_to_rot_suffix(current_name, &type_to_lane_suffixes(out_t, in_t[2], false)), }; - let current_target = match target { - Default => "neon", - ArmV7 => "neon", - Vfp4 => "neon", - FPArmV8 => "neon", - AES => "neon,aes", - FCMA => "neon,fcma", - Dotprod => "neon,dotprod", - I8MM => "neon,i8mm", - SHA3 => "neon,sha3", - RDM => "rdm", - SM4 => "neon,sm4", - FTTS => "neon,frintts", - }; let current_fn = if let Some(current_fn) = current_fn.clone() { if link_aarch64.is_some() { panic!("[{name}] Can't specify link and fn at the same time.") @@ -1267,7 +1447,6 @@ fn gen_aarch64( calls.push_str(&get_call( &multi_fn[i], current_name, - &const_declare, in_t, out_t, fixed, @@ -1415,33 +1594,18 @@ fn gen_aarch64( RDM => String::from("\n#[stable(feature = \"rdm_intrinsics\", since = \"1.62.0\")]"), _ => String::new(), }; - let function_doc = create_doc_string(current_comment, &name); let function = format!( r#" -{} -#[inline] -#[target_feature(enable = "{}")] -#[cfg_attr(test, assert_instr({}{}))]{}{} -{}{{ - {} +{function_doc} +#[inline]{target_feature} +#[cfg_attr(test, assert_instr({current_aarch64}{const_assert}))]{const_legacy}{stable} +{fn_decl}{{ + {call_params} }} "#, - function_doc, - current_target, - current_aarch64, - const_assert, - const_legacy, - stable, - fn_decl, - call_params + function_doc = create_doc_string(current_comment, &name), + target_feature = target.to_target_feature_attr_aarch64() ); - let test_target = match target { - I8MM => "neon,i8mm", - SM4 => "neon,sm4", - SHA3 => "neon,sha3", - FTTS => "neon,frintts", - _ => "neon", - }; let test = match fn_type { Fntype::Normal => gen_test( &name, @@ -1451,7 +1615,7 @@ fn gen_aarch64( [type_len(in_t[0]), type_len(in_t[1]), type_len(in_t[2])], type_len(out_t), para_num, - test_target, + target.to_simd_test_attr_aarch64(), ), Fntype::Load => gen_load_test(&name, in_t, &out_t, current_tests, type_len(out_t)), Fntype::Store => gen_store_test(&name, in_t, &out_t, current_tests, type_len(in_t[1])), @@ -1473,10 +1637,9 @@ fn gen_load_test( type_len: usize, ) -> String { let mut test = format!( - r#" - #[simd_test(enable = "neon")] - unsafe fn test_{}() {{"#, - name, + r#"{simd_test} + unsafe fn test_{name}() {{"#, + simd_test = Default.to_simd_test_attr_shared().indented(4) ); for (a, b, _, n, e) in current_tests { let a: Vec<String> = a.iter().take(type_len + 1).cloned().collect(); @@ -1571,10 +1734,9 @@ fn gen_store_test( type_len: usize, ) -> String { let mut test = format!( - r#" - #[simd_test(enable = "neon")] - unsafe fn test_{}() {{"#, - name, + r#"{simd_test} + unsafe fn test_{name}() {{"#, + simd_test = Default.to_simd_test_attr_shared().indented(4) ); for (a, _, _, constn, e) in current_tests { let a: Vec<String> = a.iter().take(type_len + 1).cloned().collect(); @@ -1639,14 +1801,10 @@ fn gen_test( len_in: [usize; 3], len_out: usize, para_num: i32, - target: &str, + attributes: Lines, ) -> String { - let mut test = format!( - r#" - #[simd_test(enable = "{}")] - unsafe fn test_{}() {{"#, - target, name, - ); + let mut test = attributes.indented(4).to_string(); + test.push_str(&format!("\n unsafe fn test_{name}() {{")); for (a, b, c, n, e) in current_tests { let a: Vec<String> = a.iter().take(len_in[0]).cloned().collect(); let b: Vec<String> = b.iter().take(len_in[1]).cloned().collect(); @@ -1833,34 +1991,6 @@ fn gen_arm( let current_aarch64 = current_aarch64 .clone() .unwrap_or_else(|| current_arm.to_string()); - let current_target_aarch64 = match target { - Default => "neon", - ArmV7 => "neon", - Vfp4 => "neon", - FPArmV8 => "neon", - AES => "neon,aes", - FCMA => "neon,fcma", - Dotprod => "neon,dotprod", - I8MM => "neon,i8mm", - SHA3 => "neon,sha3", - RDM => "rdm", - SM4 => "neon,sm4", - FTTS => "neon,frintts", - }; - let current_target_arm = match target { - Default => "v7", - ArmV7 => "v7", - Vfp4 => "vfp4", - FPArmV8 => "fp-armv8,v8", - AES => "aes,v8", - FCMA => "v8", // v8.3a - Dotprod => "v8", // v8.2a - I8MM => "v8,i8mm", - RDM => unreachable!(), - SM4 => unreachable!(), - SHA3 => unreachable!(), - FTTS => unreachable!(), - }; let current_fn = if let Some(current_fn) = current_fn.clone() { if link_aarch64.is_some() || link_arm.is_some() { panic!( @@ -2182,7 +2312,6 @@ fn gen_arm( calls.push_str(&get_call( &multi_fn[i], current_name, - &const_declare, in_t, out_t, fixed, @@ -2378,33 +2507,22 @@ fn gen_arm( let function_doc = create_doc_string(current_comment, &name); format!( r#" -{} +{function_doc} #[inline] -#[cfg(target_arch = "arm")] -#[target_feature(enable = "neon,{}")] -#[cfg_attr(test, assert_instr({}{}))]{} -{} +#[cfg(target_arch = "arm")]{target_feature_arm} +#[cfg_attr(test, assert_instr({assert_arm}{const_assert}))]{const_legacy} +{call_arm} -{} +{function_doc} #[inline] -#[cfg(target_arch = "aarch64")] -#[target_feature(enable = "{}")] -#[cfg_attr(test, assert_instr({}{}))]{}{} -{} +#[cfg(target_arch = "aarch64")]{target_feature_aarch64} +#[cfg_attr(test, assert_instr({assert_aarch64}{const_assert}))]{const_legacy}{stable_aarch64} +{call_aarch64} "#, - function_doc, - current_target_arm, - expand_intrinsic(¤t_arm, in_t[1]), - const_assert, - const_legacy, - call_arm, - function_doc, - current_target_aarch64, - expand_intrinsic(¤t_aarch64, in_t[1]), - const_assert, - const_legacy, - stable_aarch64, - call_aarch64, + target_feature_arm = target.to_target_feature_attr_arm(), + target_feature_aarch64 = target.to_target_feature_attr_aarch64(), + assert_arm = expand_intrinsic(¤t_arm, in_t[1]), + assert_aarch64 = expand_intrinsic(¤t_aarch64, in_t[1]), ) } else { let call = { @@ -2444,36 +2562,20 @@ fn gen_arm( RDM => String::from("\n#[cfg_attr(not(target_arch = \"arm\"), stable(feature = \"rdm_intrinsics\", since = \"1.62.0\"))]"), _ => String::new(), }; - let function_doc = create_doc_string(current_comment, &name); format!( r#" -{} -#[inline] -#[target_feature(enable = "{}")] -#[cfg_attr(target_arch = "arm", target_feature(enable = "{}"))] -#[cfg_attr(all(test, target_arch = "arm"), assert_instr({}{}))] -#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr({}{}))]{}{} -{} +{function_doc} +#[inline]{target_feature} +#[cfg_attr(all(test, target_arch = "arm"), assert_instr({assert_arm}{const_assert}))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr({assert_aarch64}{const_assert}))]{const_legacy}{stable_aarch64} +{call} "#, - function_doc, - current_target_aarch64, - current_target_arm, - expand_intrinsic(¤t_arm, in_t[1]), - const_assert, - expand_intrinsic(¤t_aarch64, in_t[1]), - const_assert, - const_legacy, - stable_aarch64, - call, + function_doc = create_doc_string(current_comment, &name), + assert_arm = expand_intrinsic(¤t_arm, in_t[1]), + assert_aarch64 = expand_intrinsic(¤t_aarch64, in_t[1]), + target_feature = target.to_target_feature_attr_shared(), ) }; - let test_target = match target { - I8MM => "neon,i8mm", - SM4 => "neon,sm4", - SHA3 => "neon,sha3", - FTTS => "neon,frintts", - _ => "neon", - }; let test = match fn_type { Fntype::Normal => gen_test( &name, @@ -2483,7 +2585,7 @@ fn gen_arm( [type_len(in_t[0]), type_len(in_t[1]), type_len(in_t[2])], type_len(out_t), para_num, - test_target, + target.to_simd_test_attr_shared(), ), Fntype::Load => gen_load_test(&name, in_t, &out_t, current_tests, type_len(out_t)), Fntype::Store => gen_store_test(&name, in_t, &out_t, current_tests, type_len(in_t[1])), @@ -2603,7 +2705,6 @@ fn expand_intrinsic(intr: &str, t: &str) -> String { fn get_call( in_str: &str, current_name: &str, - const_declare: &str, in_t: &[&str; 3], out_t: &str, fixed: &Vec<String>, @@ -2643,7 +2744,7 @@ fn get_call( "halflen" => type_len(in_t[1]) / 2, _ => 0, }; - let mut s = format!("{const_declare} ["); + let mut s = format!("["); for i in 0..len { if i != 0 { s.push_str(", "); @@ -2674,7 +2775,7 @@ fn get_call( if fn_name.starts_with("base") { let fn_format: Vec<_> = fn_name.split('-').map(|v| v.to_string()).collect(); assert_eq!(fn_format.len(), 3); - let mut s = format!("<const {}: i32> [", &fn_format[2]); + let mut s = format!("["); let base_len = fn_format[1].parse::<usize>().unwrap(); for i in 0..type_len(in_t[1]) / base_len { for j in 0..base_len { @@ -2714,7 +2815,7 @@ fn get_call( "in0_len" => type_len(in_t[0]), _ => 0, }; - let mut s = format!("{const_declare} ["); + let mut s = format!("["); for i in 0..len { if i != 0 { s.push_str(", "); @@ -2743,12 +2844,9 @@ fn get_call( _ => 0, }; if len == 0 { - return format!( - r#"static_assert!({} : i32 where {} == 0);"#, - fn_format[2], fn_format[2] - ); + return format!(r#"static_assert!({} == 0);"#, fn_format[2]); } else { - return format!(r#"static_assert_imm{len}!({});"#, fn_format[2]); + return format!(r#"static_assert_uimm_bits!({}, {len});"#, fn_format[2]); } } if fn_name.starts_with("static_assert") { @@ -2768,14 +2866,11 @@ fn get_call( fn_format[3].clone() }; if lim1 == lim2 { - return format!( - r#"static_assert!({} : i32 where {} == {lim1});"#, - fn_format[1], fn_format[1] - ); + return format!(r#"static_assert!({} == {lim1});"#, fn_format[1]); } else { return format!( - r#"static_assert!({} : i32 where {} >= {lim1} && {} <= {lim2});"#, - fn_format[1], fn_format[1], fn_format[1] + r#"static_assert!({} >= {lim1} && {} <= {lim2});"#, + fn_format[1], fn_format[1] ); } } @@ -2824,7 +2919,6 @@ fn get_call( get_call( &sub_call, current_name, - const_declare, in_t, out_t, fixed, @@ -2873,7 +2967,6 @@ fn get_call( let sub_call = get_call( &sub_fn[1..sub_fn.len() - 1], current_name, - const_declare, in_t, out_t, fixed, |