From 703007f699b1461355439c31f8a44711710db791 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Fri, 14 Jun 2024 18:05:09 +0100 Subject: [PATCH 01/13] rustc_target: Add various aarch64 features Add various aarch64 features already supported by LLVM and Linux. The features are marked as unstable using a newly added symbol, i.e. aarch64_unstable_target_feature. Additionally include some comment fixes to ensure consistency of feature names with the Arm ARM and support for architecture version target features up to v9.5a. This commit adds compiler support for the following features: - FEAT_CSSC - FEAT_ECV - FEAT_FAMINMAX - FEAT_FLAGM2 - FEAT_FP8 - FEAT_FP8DOT2 - FEAT_FP8DOT4 - FEAT_FP8FMA - FEAT_FPMR - FEAT_HBC - FEAT_LSE128 - FEAT_LSE2 - FEAT_LUT - FEAT_MOPS - FEAT_LRCPC3 - FEAT_SVE_B16B16 - FEAT_SVE2p1 - FEAT_WFxT --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 2 + compiler/rustc_feature/src/unstable.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/target_features.rs | 54 ++++++++++++++++++-- library/std/tests/run-time-detect.rs | 21 ++++++++ tests/ui/target-feature/gate.rs | 1 + 6 files changed, 75 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9fd8ca43789dd..cf72b1ccef31a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -234,6 +234,8 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { ("aarch64", "pmuv3") => LLVMFeature::new("perfmon"), ("aarch64", "paca") => LLVMFeature::new("pauth"), ("aarch64", "pacg") => LLVMFeature::new("pauth"), + ("aarch64", "sve-b16b16") => LLVMFeature::new("b16b16"), + ("aarch64", "flagm2") => LLVMFeature::new("altnzcv"), // Rust ties fp and neon together. ("aarch64", "neon") => { LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8")) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 88a4b5a838246..f41793fb446a2 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -300,6 +300,7 @@ declare_features! ( // FIXME: Document these and merge with the list below. // Unstable `#[target_feature]` directives. + (unstable, aarch64_unstable_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)), (unstable, arm_target_feature, "1.27.0", Some(44839)), (unstable, avx512_target_feature, "1.27.0", Some(44839)), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 32fca6733bb55..2c9a30ce4f871 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -356,6 +356,7 @@ symbols! { _task_context, a32, aarch64_target_feature, + aarch64_unstable_target_feature, aarch64_ver_target_feature, abi, abi_amdgpu_kernel, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index da66ba270b33c..d4b5a5ff675b3 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -99,6 +99,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("bti", Stable, &[]), // FEAT_CRC ("crc", Stable, &[]), + // FEAT_CSSC + ("cssc", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_DIT ("dit", Stable, &[]), // FEAT_DotProd @@ -107,21 +109,39 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("dpb", Stable, &[]), // FEAT_DPB2 ("dpb2", Stable, &["dpb"]), + // FEAT_ECV + ("ecv", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_F32MM ("f32mm", Stable, &["sve"]), // FEAT_F64MM ("f64mm", Stable, &["sve"]), + // FEAT_FAMINMAX + ("faminmax", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_FCMA ("fcma", Stable, &["neon"]), // FEAT_FHM ("fhm", Stable, &["fp16"]), // FEAT_FLAGM ("flagm", Stable, &[]), + // FEAT_FLAGM2 + ("flagm2", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_FP16 // Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608 ("fp16", Stable, &["neon"]), + // FEAT_FP8 + ("fp8", Unstable(sym::aarch64_unstable_target_feature), &["faminmax", "lut", "bf16"]), + // FEAT_FP8DOT2 + ("fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["fp8dot4"]), + // FEAT_FP8DOT4 + ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), + // FEAT_FP8FMA + ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), + // FEAT_FPMR + ("fpmr", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_FRINTTS ("frintts", Stable, &[]), + // FEAT_HBC + ("hbc", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_I8MM ("i8mm", Stable, &[]), // FEAT_JSCVT @@ -131,6 +151,14 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("lor", Stable, &[]), // FEAT_LSE ("lse", Stable, &[]), + // FEAT_LSE128 + ("lse128", Unstable(sym::aarch64_unstable_target_feature), &["lse"]), + // FEAT_LSE2 + ("lse2", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_LUT + ("lut", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_MOPS + ("mops", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_MTE & FEAT_MTE2 ("mte", Stable, &[]), // FEAT_AdvSimd & FEAT_FP @@ -143,14 +171,16 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("pan", Stable, &[]), // FEAT_PMUv3 ("pmuv3", Stable, &[]), - // FEAT_RAND + // FEAT_RNG ("rand", Stable, &[]), // FEAT_RAS & FEAT_RASv1p1 ("ras", Stable, &[]), - // FEAT_RCPC + // FEAT_LRCPC ("rcpc", Stable, &[]), - // FEAT_RCPC2 + // FEAT_LRCPC2 ("rcpc2", Stable, &["rcpc"]), + // FEAT_LRCPC3 + ("rcpc3", Unstable(sym::aarch64_unstable_target_feature), &["rcpc2"]), // FEAT_RDM ("rdm", Stable, &["neon"]), // FEAT_SB @@ -173,9 +203,11 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // // "For backwards compatibility, Neon and VFP are required in the latest architectures." ("sve", Stable, &["neon"]), + // FEAT_SVE_B16B16 (SVE or SME Instructions) + ("sve-b16b16", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), // FEAT_SVE2 ("sve2", Stable, &["sve"]), - // FEAT_SVE2_AES + // FEAT_SVE_AES & FEAT_SVE_PMULL128 ("sve2-aes", Stable, &["sve2", "aes"]), // FEAT_SVE2_BitPerm ("sve2-bitperm", Stable, &["sve2"]), @@ -183,6 +215,8 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sve2-sha3", Stable, &["sve2", "sha3"]), // FEAT_SVE2_SM4 ("sve2-sm4", Stable, &["sve2", "sm4"]), + // FEAT_SVE2p1 + ("sve2p1", Unstable(sym::aarch64_unstable_target_feature), &["sve2"]), // FEAT_TME ("tme", Stable, &[]), ( @@ -199,9 +233,19 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("v8.4a", Unstable(sym::aarch64_ver_target_feature), &["v8.3a", "dotprod", "dit", "flagm"]), ("v8.5a", Unstable(sym::aarch64_ver_target_feature), &["v8.4a", "ssbs", "sb", "dpb2", "bti"]), ("v8.6a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "bf16", "i8mm"]), - ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &[]), + ("v8.7a", Unstable(sym::aarch64_ver_target_feature), &["v8.6a", "wfxt"]), + ("v8.8a", Unstable(sym::aarch64_ver_target_feature), &["v8.7a", "hbc", "mops"]), + ("v8.9a", Unstable(sym::aarch64_ver_target_feature), &["v8.8a", "cssc"]), + ("v9.1a", Unstable(sym::aarch64_ver_target_feature), &["v9a", "v8.6a"]), + ("v9.2a", Unstable(sym::aarch64_ver_target_feature), &["v9.1a", "v8.7a"]), + ("v9.3a", Unstable(sym::aarch64_ver_target_feature), &["v9.2a", "v8.8a"]), + ("v9.4a", Unstable(sym::aarch64_ver_target_feature), &["v9.3a", "v8.9a"]), + ("v9.5a", Unstable(sym::aarch64_ver_target_feature), &["v9.4a"]), + ("v9a", Unstable(sym::aarch64_ver_target_feature), &["v8.5a", "sve2"]), // FEAT_VHE ("vh", Stable, &[]), + // FEAT_WFxT + ("wfxt", Unstable(sym::aarch64_unstable_target_feature), &[]), // tidy-alphabetical-end ]; diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 6948670565662..779f0d1a9b892 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -4,6 +4,10 @@ all(target_arch = "arm", any(target_os = "linux", target_os = "android")), feature(stdarch_arm_feature_detection) )] +#![cfg_attr( + all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")), + feature(stdarch_aarch64_feature_detection) +)] #![cfg_attr( all(target_arch = "powerpc", target_os = "linux"), feature(stdarch_powerpc_feature_detection) @@ -36,21 +40,34 @@ fn aarch64_linux() { println!("bf16: {}", is_aarch64_feature_detected!("bf16")); println!("bti: {}", is_aarch64_feature_detected!("bti")); println!("crc: {}", is_aarch64_feature_detected!("crc")); + println!("cssc: {}", is_aarch64_feature_detected!("cssc")); println!("dit: {}", is_aarch64_feature_detected!("dit")); println!("dotprod: {}", is_aarch64_feature_detected!("dotprod")); println!("dpb2: {}", is_aarch64_feature_detected!("dpb2")); println!("dpb: {}", is_aarch64_feature_detected!("dpb")); + println!("ecv: {}", is_aarch64_feature_detected!("ecv")); println!("f32mm: {}", is_aarch64_feature_detected!("f32mm")); println!("f64mm: {}", is_aarch64_feature_detected!("f64mm")); + println!("faminmax: {}", is_aarch64_feature_detected!("faminmax")); println!("fcma: {}", is_aarch64_feature_detected!("fcma")); println!("fhm: {}", is_aarch64_feature_detected!("fhm")); + println!("flagm2: {}", is_aarch64_feature_detected!("flagm2")); println!("flagm: {}", is_aarch64_feature_detected!("flagm")); println!("fp16: {}", is_aarch64_feature_detected!("fp16")); + println!("fp8: {}", is_aarch64_feature_detected!("fp8")); + println!("fp8dot2: {}", is_aarch64_feature_detected!("fp8dot2")); + println!("fp8dot4: {}", is_aarch64_feature_detected!("fp8dot4")); + println!("fp8fma: {}", is_aarch64_feature_detected!("fp8fma")); + println!("fpmr: {}", is_aarch64_feature_detected!("fpmr")); println!("frintts: {}", is_aarch64_feature_detected!("frintts")); + println!("hbc: {}", is_aarch64_feature_detected!("hbc")); println!("i8mm: {}", is_aarch64_feature_detected!("i8mm")); println!("jsconv: {}", is_aarch64_feature_detected!("jsconv")); + println!("lse128: {}", is_aarch64_feature_detected!("lse128")); println!("lse2: {}", is_aarch64_feature_detected!("lse2")); println!("lse: {}", is_aarch64_feature_detected!("lse")); + println!("lut: {}", is_aarch64_feature_detected!("lut")); + println!("mops: {}", is_aarch64_feature_detected!("mops")); println!("mte: {}", is_aarch64_feature_detected!("mte")); println!("neon: {}", is_aarch64_feature_detected!("neon")); println!("paca: {}", is_aarch64_feature_detected!("paca")); @@ -58,6 +75,7 @@ fn aarch64_linux() { println!("pmull: {}", is_aarch64_feature_detected!("pmull")); println!("rand: {}", is_aarch64_feature_detected!("rand")); println!("rcpc2: {}", is_aarch64_feature_detected!("rcpc2")); + println!("rcpc3: {}", is_aarch64_feature_detected!("rcpc3")); println!("rcpc: {}", is_aarch64_feature_detected!("rcpc")); println!("rdm: {}", is_aarch64_feature_detected!("rdm")); println!("sb: {}", is_aarch64_feature_detected!("sb")); @@ -65,13 +83,16 @@ fn aarch64_linux() { println!("sha3: {}", is_aarch64_feature_detected!("sha3")); println!("sm4: {}", is_aarch64_feature_detected!("sm4")); println!("ssbs: {}", is_aarch64_feature_detected!("ssbs")); + println!("sve-b16b16: {}", is_aarch64_feature_detected!("sve-b16b16")); println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes")); println!("sve2-bitperm: {}", is_aarch64_feature_detected!("sve2-bitperm")); println!("sve2-sha3: {}", is_aarch64_feature_detected!("sve2-sha3")); println!("sve2-sm4: {}", is_aarch64_feature_detected!("sve2-sm4")); println!("sve2: {}", is_aarch64_feature_detected!("sve2")); + println!("sve2p1: {}", is_aarch64_feature_detected!("sve2p1")); println!("sve: {}", is_aarch64_feature_detected!("sve")); println!("tme: {}", is_aarch64_feature_detected!("tme")); + println!("wfxt: {}", is_aarch64_feature_detected!("wfxt")); // tidy-alphabetical-end } diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index 94d79d56c5920..5c4fb8479324f 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -17,6 +17,7 @@ // gate-test-ermsb_target_feature // gate-test-bpf_target_feature // gate-test-aarch64_ver_target_feature +// gate-test-aarch64_unstable_target_feature // gate-test-csky_target_feature // gate-test-loongarch_target_feature // gate-test-lahfsahf_target_feature From 8be8db5aa7dbe396707f390573f5bd11a6cb9865 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Mon, 17 Jun 2024 15:37:46 +0100 Subject: [PATCH 02/13] rustc_target: Add SME aarch64 features Add SME aarch64 features already supported by LLVM and Linux. This commit adds compiler support for the following features: - FEAT_SME - FEAT_SME_F16F16 - FEAT_SME_F64F64 - FEAT_SME_F8F16 - FEAT_SME_F8F32 - FEAT_SME_FA64 - FEAT_SME_I16I64 - FEAT_SME_LUTv2 - FEAT_SME2 - FEAT_SME2p1 - FEAT_SSVE_FP8DOT2 - FEAT_SSVE_FP8DOT4 - FEAT_SSVE_FP8FMA --- compiler/rustc_target/src/target_features.rs | 26 ++++++++++++++++++++ library/std/tests/run-time-detect.rs | 13 ++++++++++ 2 files changed, 39 insertions(+) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index d4b5a5ff675b3..b48d1d1a49ceb 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -191,10 +191,36 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("sha3", Stable, &["sha2"]), // FEAT_SM3 & FEAT_SM4 ("sm4", Stable, &["neon"]), + // FEAT_SME + ("sme", Unstable(sym::aarch64_unstable_target_feature), &["bf16"]), + // FEAT_SME_F16F16 + ("sme-f16f16", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), + // FEAT_SME_F64F64 + ("sme-f64f64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), + // FEAT_SME_F8F16 + ("sme-f8f16", Unstable(sym::aarch64_unstable_target_feature), &["sme-f8f32"]), + // FEAT_SME_F8F32 + ("sme-f8f32", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), + // FEAT_SME_FA64 + ("sme-fa64", Unstable(sym::aarch64_unstable_target_feature), &["sme", "sve2"]), + // FEAT_SME_I16I64 + ("sme-i16i64", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), + // FEAT_SME_LUTv2 + ("sme-lutv2", Unstable(sym::aarch64_unstable_target_feature), &[]), + // FEAT_SME2 + ("sme2", Unstable(sym::aarch64_unstable_target_feature), &["sme"]), + // FEAT_SME2p1 + ("sme2p1", Unstable(sym::aarch64_unstable_target_feature), &["sme2"]), // FEAT_SPE ("spe", Stable, &[]), // FEAT_SSBS & FEAT_SSBS2 ("ssbs", Stable, &[]), + // FEAT_SSVE_FP8FDOT2 + ("ssve-fp8dot2", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8dot4"]), + // FEAT_SSVE_FP8FDOT4 + ("ssve-fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["ssve-fp8fma"]), + // FEAT_SSVE_FP8FMA + ("ssve-fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["sme2", "fp8"]), // FEAT_SVE // It was decided that SVE requires Neon: https://github.com/rust-lang/rust/pull/91608 // diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 779f0d1a9b892..dcd5cd7f6b9c7 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -82,7 +82,20 @@ fn aarch64_linux() { println!("sha2: {}", is_aarch64_feature_detected!("sha2")); println!("sha3: {}", is_aarch64_feature_detected!("sha3")); println!("sm4: {}", is_aarch64_feature_detected!("sm4")); + println!("sme-f16f16: {}", is_aarch64_feature_detected!("sme-f16f16")); + println!("sme-f64f64: {}", is_aarch64_feature_detected!("sme-f64f64")); + println!("sme-f8f16: {}", is_aarch64_feature_detected!("sme-f8f16")); + println!("sme-f8f32: {}", is_aarch64_feature_detected!("sme-f8f32")); + println!("sme-fa64: {}", is_aarch64_feature_detected!("sme-fa64")); + println!("sme-i16i64: {}", is_aarch64_feature_detected!("sme-i16i64")); + println!("sme-lutv2: {}", is_aarch64_feature_detected!("sme-lutv2")); + println!("sme2: {}", is_aarch64_feature_detected!("sme2")); + println!("sme2p1: {}", is_aarch64_feature_detected!("sme2p1")); + println!("sme: {}", is_aarch64_feature_detected!("sme")); println!("ssbs: {}", is_aarch64_feature_detected!("ssbs")); + println!("ssve-fp8dot2: {}", is_aarch64_feature_detected!("ssve-fp8dot2")); + println!("ssve-fp8dot4: {}", is_aarch64_feature_detected!("ssve-fp8dot4")); + println!("ssve-fp8fma: {}", is_aarch64_feature_detected!("ssve-fp8fma")); println!("sve-b16b16: {}", is_aarch64_feature_detected!("sve-b16b16")); println!("sve2-aes: {}", is_aarch64_feature_detected!("sve2-aes")); println!("sve2-bitperm: {}", is_aarch64_feature_detected!("sve2-bitperm")); From 3a18512072d14202fc6e382c4061e1b597d5e922 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Mon, 29 Jul 2024 13:08:31 +0100 Subject: [PATCH 03/13] rustc_target: Remove fpmr target feature FEAT_FPMR has been removed from upstream LLVM as of LLVM 19. Remove the feature from the target features list and temporarily hack the LLVM codegen to always enable it until the minimum LLVM version is bumped to 19. --- compiler/rustc_codegen_llvm/src/attributes.rs | 6 ++++++ compiler/rustc_target/src/target_features.rs | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index fde95104093e5..1f37a32b6ad94 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -528,6 +528,12 @@ pub fn llfn_attrs_from_instance<'ll, 'tcx>( InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(), InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(), })) + // HACK: LLVM versions 19+ do not have the FPMR feature and treat it as always enabled + // It only exists as a feature in LLVM 18, cannot be passed down for any other version + .chain(match &*cx.tcx.sess.target.arch { + "aarch64" if llvm_util::get_version().0 == 18 => vec!["+fpmr".to_string()], + _ => vec![], + }) .collect::>(); if cx.tcx.sess.target.is_like_wasm { diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b48d1d1a49ceb..8319cb880cc79 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -136,8 +136,6 @@ const AARCH64_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("fp8dot4", Unstable(sym::aarch64_unstable_target_feature), &["fp8fma"]), // FEAT_FP8FMA ("fp8fma", Unstable(sym::aarch64_unstable_target_feature), &["fp8"]), - // FEAT_FPMR - ("fpmr", Unstable(sym::aarch64_unstable_target_feature), &[]), // FEAT_FRINTTS ("frintts", Stable, &[]), // FEAT_HBC From 23a693650bc91ebe8cf34fe53b2ab2f05a896531 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Fri, 9 Aug 2024 16:41:43 +0100 Subject: [PATCH 04/13] rustc_codegen_llvm: Filter out unavailable LLVM features Convert to_llvm_features to return Option so that it can return None if the requested feature is not available for the current LLVM version. Add match rules to filter out aarch64 features not available in LLVM 17. --- compiler/rustc_codegen_llvm/src/attributes.rs | 7 +- compiler/rustc_codegen_llvm/src/llvm_util.rs | 94 ++++++++++++------- 2 files changed, 63 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 1f37a32b6ad94..fee5a3bd12b5f 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -521,9 +521,10 @@ pub fn llfn_attrs_from_instance<'ll, 'tcx>( let function_features = function_features .iter() - .flat_map(|feat| { - llvm_util::to_llvm_features(cx.tcx.sess, feat).into_iter().map(|f| format!("+{f}")) - }) + // Convert to LLVMFeatures and filter out unavailable ones + .flat_map(|feat| llvm_util::to_llvm_features(cx.tcx.sess, feat)) + // Convert LLVMFeatures & dependencies to +s + .flat_map(|feat| feat.into_iter().map(|f| format!("+{f}"))) .chain(codegen_fn_attrs.instruction_set.iter().map(|x| match x { InstructionSetAttr::ArmA32 => "-thumb-mode".to_string(), InstructionSetAttr::ArmT32 => "+thumb-mode".to_string(), diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index cf72b1ccef31a..ef449e99607a2 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -209,7 +209,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> { // Though note that Rust can also be build with an external precompiled version of LLVM // which might lead to failures if the oldest tested / supported LLVM version // doesn't yet support the relevant intrinsics -pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { +pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option> { let arch = if sess.target.arch == "x86_64" { "x86" } else if sess.target.arch == "arm64ec" { @@ -218,42 +218,59 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> { &*sess.target.arch }; match (arch, s) { - ("x86", "sse4.2") => { - LLVMFeature::with_dependency("sse4.2", TargetFeatureFoldStrength::EnableOnly("crc32")) - } - ("x86", "pclmulqdq") => LLVMFeature::new("pclmul"), - ("x86", "rdrand") => LLVMFeature::new("rdrnd"), - ("x86", "bmi1") => LLVMFeature::new("bmi"), - ("x86", "cmpxchg16b") => LLVMFeature::new("cx16"), - ("x86", "lahfsahf") => LLVMFeature::new("sahf"), - ("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"), - ("aarch64", "dpb") => LLVMFeature::new("ccpp"), - ("aarch64", "dpb2") => LLVMFeature::new("ccdp"), - ("aarch64", "frintts") => LLVMFeature::new("fptoint"), - ("aarch64", "fcma") => LLVMFeature::new("complxnum"), - ("aarch64", "pmuv3") => LLVMFeature::new("perfmon"), - ("aarch64", "paca") => LLVMFeature::new("pauth"), - ("aarch64", "pacg") => LLVMFeature::new("pauth"), - ("aarch64", "sve-b16b16") => LLVMFeature::new("b16b16"), - ("aarch64", "flagm2") => LLVMFeature::new("altnzcv"), + ("x86", "sse4.2") => Some(LLVMFeature::with_dependency( + "sse4.2", + TargetFeatureFoldStrength::EnableOnly("crc32"), + )), + ("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")), + ("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")), + ("x86", "bmi1") => Some(LLVMFeature::new("bmi")), + ("x86", "cmpxchg16b") => Some(LLVMFeature::new("cx16")), + ("x86", "lahfsahf") => Some(LLVMFeature::new("sahf")), + ("aarch64", "rcpc2") => Some(LLVMFeature::new("rcpc-immo")), + ("aarch64", "dpb") => Some(LLVMFeature::new("ccpp")), + ("aarch64", "dpb2") => Some(LLVMFeature::new("ccdp")), + ("aarch64", "frintts") => Some(LLVMFeature::new("fptoint")), + ("aarch64", "fcma") => Some(LLVMFeature::new("complxnum")), + ("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")), + ("aarch64", "paca") => Some(LLVMFeature::new("pauth")), + ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")), + ("aarch64", "sve-b16b16") => Some(LLVMFeature::new("b16b16")), + ("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")), // Rust ties fp and neon together. ("aarch64", "neon") => { - LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8")) + Some(LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8"))) } // In LLVM neon implicitly enables fp, but we manually enable // neon when a feature only implicitly enables fp - ("aarch64", "fhm") => LLVMFeature::new("fp16fml"), - ("aarch64", "fp16") => LLVMFeature::new("fullfp16"), + ("aarch64", "fhm") => Some(LLVMFeature::new("fp16fml")), + ("aarch64", "fp16") => Some(LLVMFeature::new("fullfp16")), + // Filter out features that are not supported by the current LLVM version + ("aarch64", "faminmax") if get_version().0 < 18 => None, + ("aarch64", "fp8") if get_version().0 < 18 => None, + ("aarch64", "fp8dot2") if get_version().0 < 18 => None, + ("aarch64", "fp8dot4") if get_version().0 < 18 => None, + ("aarch64", "fp8fma") if get_version().0 < 18 => None, + ("aarch64", "fpmr") if get_version().0 != 18 => None, + ("aarch64", "lut") if get_version().0 < 18 => None, + ("aarch64", "sme-f8f16") if get_version().0 < 18 => None, + ("aarch64", "sme-f8f32") if get_version().0 < 18 => None, + ("aarch64", "sme-fa64") if get_version().0 < 18 => None, + ("aarch64", "sme-lutv2") if get_version().0 < 18 => None, + ("aarch64", "ssve-fp8dot2") if get_version().0 < 18 => None, + ("aarch64", "ssve-fp8dot4") if get_version().0 < 18 => None, + ("aarch64", "ssve-fp8fma") if get_version().0 < 18 => None, + ("aarch64", "v9.5a") if get_version().0 < 18 => None, // In LLVM 18, `unaligned-scalar-mem` was merged with `unaligned-vector-mem` into a single feature called // `fast-unaligned-access`. In LLVM 19, it was split back out. ("riscv32" | "riscv64", "unaligned-scalar-mem") if get_version().0 == 18 => { - LLVMFeature::new("fast-unaligned-access") + Some(LLVMFeature::new("fast-unaligned-access")) } // For LLVM 18, enable the evex512 target feature if a avx512 target feature is enabled. ("x86", s) if get_version().0 >= 18 && s.starts_with("avx512") => { - LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")) + Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) } - (_, s) => LLVMFeature::new(s), + (_, s) => Some(LLVMFeature::new(s)), } } @@ -293,13 +310,17 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec { return true; } // check that all features in a given smallvec are enabled - for llvm_feature in to_llvm_features(sess, feature) { - let cstr = SmallCStr::new(llvm_feature); - if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } { - return false; + if let Some(feat) = to_llvm_features(sess, feature) { + for llvm_feature in feat { + let cstr = SmallCStr::new(llvm_feature); + if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } { + return false; + } } + true + } else { + false } - true }) .map(|(feature, _, _)| Symbol::intern(feature)), ); @@ -388,9 +409,9 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach .target .supported_target_features() .iter() - .map(|(feature, _gate, _implied)| { + .filter_map(|(feature, _gate, _implied)| { // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings. - let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name; + let llvm_feature = to_llvm_features(sess, *feature)?.llvm_feature_name; let desc = match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() { Some(index) => { @@ -400,7 +421,7 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach None => "", }; - (*feature, desc) + Some((*feature, desc)) }) .collect::>(); @@ -597,7 +618,7 @@ pub(crate) fn global_llvm_features( if feature_state.is_none() { let rust_feature = supported_features.iter().find_map(|&(rust_feature, _, _)| { - let llvm_features = to_llvm_features(sess, rust_feature); + let llvm_features = to_llvm_features(sess, rust_feature)?; if llvm_features.contains(feature) && !llvm_features.contains(rust_feature) { @@ -643,7 +664,7 @@ pub(crate) fn global_llvm_features( // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two // different names when the LLVM name and the Rust name differ. - let llvm_feature = to_llvm_features(sess, feature); + let llvm_feature = to_llvm_features(sess, feature)?; Some( std::iter::once(format!( @@ -693,6 +714,9 @@ fn backend_feature_name<'a>(sess: &Session, s: &'a str) -> Option<&'a str> { let feature = s .strip_prefix(&['+', '-'][..]) .unwrap_or_else(|| sess.dcx().emit_fatal(InvalidTargetFeaturePrefix { feature: s })); + if s.is_empty() { + return None; + } // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { From 27628690791410b89705a751d4df8c1077d59009 Mon Sep 17 00:00:00 2001 From: Kajetan Puchalski Date: Fri, 9 Aug 2024 18:24:55 +0000 Subject: [PATCH 05/13] tests/ui: Update error messages with aarch64 target features --- tests/ui/check-cfg/mix.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 2 +- tests/ui/target-feature/gate.stderr | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 520cffc4b0268..9b6448fe5a033 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 201 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 239 more = note: see for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index d780e04e729a2..d3925a49b6f0c 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `cssc`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `ecv`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `faminmax`, `fcma`, `fdivdu`, `fhm`, `flagm`, `flagm2`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fp8`, `fp8dot2`, `fp8dot4`, `fp8fma`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `hbc`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lse128`, `lse2`, `lsx`, `lut`, `lvz`, `lzcnt`, `m`, `mclass`, `mops`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rcpc3`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sha512`, `sign-ext`, `simd128`, `sm3`, `sm4`, `sme`, `sme-f16f16`, `sme-f64f64`, `sme-f8f16`, `sme-f8f32`, `sme-fa64`, `sme-i16i64`, `sme-lutv2`, `sme2`, `sme2p1`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `ssve-fp8dot2`, `ssve-fp8dot4`, `ssve-fp8fma`, `sve`, `sve-b16b16`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `sve2p1`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `v8.8a`, `v8.9a`, `v9.1a`, `v9.2a`, `v9.3a`, `v9.4a`, `v9.5a`, `v9a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `wfxt`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index a69020e6864d2..37c5ed0168890 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:26:18 + --> $DIR/gate.rs:27:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ From 803cbaf5fb5021eafaa60578ed33d708370ba3c0 Mon Sep 17 00:00:00 2001 From: Rezwan ahmed sami Date: Sun, 18 Aug 2024 01:11:18 +0600 Subject: [PATCH 06/13] Add f16 and f128 to tests/ui/consts/const-float-bits-conv.rs --- tests/ui/consts/const-float-bits-conv.rs | 65 +++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs index 45e8ea570ed73..2c4df96562a9d 100644 --- a/tests/ui/consts/const-float-bits-conv.rs +++ b/tests/ui/consts/const-float-bits-conv.rs @@ -3,8 +3,9 @@ #![feature(const_float_bits_conv)] #![feature(const_float_classify)] +#![feature(f16)] +#![feature(f128)] #![allow(unused_macro_rules)] - // Don't promote const fn nop(x: T) -> T { x } @@ -28,6 +29,36 @@ fn has_broken_floats() -> bool { std::env::var("TARGET").is_ok_and(|v| v.contains("i586")) } +fn f16(){ + const_assert!((1f16).to_bits(), 0x3c00); + const_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00); + const_assert!((12.5f16).to_bits(), 0x4a40); + const_assert!(u16::from_le_bytes(12.5f16.to_le_bytes()), 0x4a40); + const_assert!((1337f16).to_bits(), 0x6539); + const_assert!(u16::from_ne_bytes(1337f16.to_ne_bytes()), 0x6539); + const_assert!((-14.25f16).to_bits(), 0xcb20); + const_assert!(f16::from_bits(0x3c00), 1.0); + const_assert!(f16::from_be_bytes(0x3c00u16.to_be_bytes()), 1.0); + const_assert!(f16::from_bits(0x4a40), 12.5); + const_assert!(f16::from_le_bytes(0x4a40u16.to_le_bytes()), 12.5); + const_assert!(f16::from_bits(0x5be0), 252.0); + const_assert!(f16::from_ne_bytes(0x5be0u16.to_ne_bytes()), 252.0); + const_assert!(f16::from_bits(0xcb20), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u16 = f16::NAN.to_bits() ^ 0x0155; + const SIGNALING_NAN: u16 = f16::NAN.to_bits() ^ 0x02AA; + + const_assert!(f16::from_bits(QUIET_NAN).is_nan()); + const_assert!(f16::from_bits(SIGNALING_NAN).is_nan()); + const_assert!(f16::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + const_assert!(f16::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + fn f32() { const_assert!((1f32).to_bits(), 0x3f800000); const_assert!(u32::from_be_bytes(1f32.to_be_bytes()), 0x3f800000); @@ -88,7 +119,39 @@ fn f64() { } } +fn f128() { + const_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000); + const_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000); + const_assert!((12.5f128).to_bits(), 0x40029000000000000000000000000000); + const_assert!(u128::from_le_bytes(12.5f128.to_le_bytes()), 0x40029000000000000000000000000000); + const_assert!((1337f128).to_bits(), 0x40094e40000000000000000000000000); + const_assert!(u128::from_ne_bytes(1337f128.to_ne_bytes()), 0x40094e40000000000000000000000000); + const_assert!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000); + const_assert!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0); + const_assert!(f128::from_be_bytes(0x3fff0000000000000000000000000000u128.to_be_bytes()), 1.0); + const_assert!(f128::from_bits(0x40029000000000000000000000000000), 12.5); + const_assert!(f128::from_le_bytes(0x40029000000000000000000000000000u128.to_le_bytes()), 12.5); + const_assert!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0); + assert_eq!(f128::from_ne_bytes(0x40094e40000000000000000000000000u128.to_ne_bytes()), 1337.0); + const_assert!(f128::from_bits(0xc002c800000000000000000000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signalingness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + // NOTE: These names assume `f{BITS}::NAN` is a quiet NAN and IEEE754-2008's NaN rules apply! + const QUIET_NAN: u128 = f128::NAN.to_bits() | 0x0000_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA_AAAA; + const SIGNALING_NAN: u128 = f128::NAN.to_bits() ^ 0x0000_5555_5555_5555_5555_5555_5555_5555; + + const_assert!(f128::from_bits(QUIET_NAN).is_nan()); + const_assert!(f128::from_bits(SIGNALING_NAN).is_nan()); + const_assert!(f128::from_bits(QUIET_NAN).to_bits(), QUIET_NAN); + if !has_broken_floats() { + const_assert!(f128::from_bits(SIGNALING_NAN).to_bits(), SIGNALING_NAN); + } +} + fn main() { + f16(); f32(); f64(); + f128(); } From 9f39427228d09d7a06b9dd55a4f52b4b9ac15817 Mon Sep 17 00:00:00 2001 From: Rezwan ahmed sami Date: Sun, 18 Aug 2024 11:12:40 +0600 Subject: [PATCH 07/13] Added #[cfg(target_arch = x86_64)] to f16 and f128 --- tests/ui/consts/const-float-bits-conv.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/ui/consts/const-float-bits-conv.rs b/tests/ui/consts/const-float-bits-conv.rs index 2c4df96562a9d..3a526c54dc376 100644 --- a/tests/ui/consts/const-float-bits-conv.rs +++ b/tests/ui/consts/const-float-bits-conv.rs @@ -29,6 +29,7 @@ fn has_broken_floats() -> bool { std::env::var("TARGET").is_ok_and(|v| v.contains("i586")) } +#[cfg(target_arch = "x86_64")] fn f16(){ const_assert!((1f16).to_bits(), 0x3c00); const_assert!(u16::from_be_bytes(1f16.to_be_bytes()), 0x3c00); @@ -119,6 +120,7 @@ fn f64() { } } +#[cfg(target_arch = "x86_64")] fn f128() { const_assert!((1f128).to_bits(), 0x3fff0000000000000000000000000000); const_assert!(u128::from_be_bytes(1f128.to_be_bytes()), 0x3fff0000000000000000000000000000); @@ -150,8 +152,11 @@ fn f128() { } fn main() { - f16(); + #[cfg(target_arch = "x86_64")] + { + f16(); + f128(); + } f32(); f64(); - f128(); } From dbad7581348d71822573e906c165bd08c366f196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eduardo=20S=C3=A1nchez=20Mu=C3=B1oz?= Date: Mon, 19 Aug 2024 20:31:48 +0200 Subject: [PATCH 08/13] Stabilize feature `char_indices_offset` --- library/core/src/lib.rs | 1 - library/core/src/str/iter.rs | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e3640627c562a..bbfe412fbcf1b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -110,7 +110,6 @@ #![cfg_attr(bootstrap, feature(offset_of_nested))] #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] -#![feature(char_indices_offset)] #![feature(const_align_of_val)] #![feature(const_align_of_val_raw)] #![feature(const_align_offset)] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 06f796f9f3ad8..681ec79c0b7bf 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -241,24 +241,35 @@ impl<'a> CharIndices<'a> { /// Returns the byte position of the next character, or the length /// of the underlying string if there are no more characters. /// + /// This means that, when the iterator has not been fully consumed, + /// the returned value will match the index that will be returned + /// by the next call to [`next()`](Self::next). + /// /// # Examples /// /// ``` - /// #![feature(char_indices_offset)] /// let mut chars = "a楽".char_indices(); /// + /// // `next()` has not been called yet, so `offset()` returns the byte + /// // index of the first character of the string, which is always 0. /// assert_eq!(chars.offset(), 0); + /// // As expected, the first call to `next()` also returns 0 as index. /// assert_eq!(chars.next(), Some((0, 'a'))); /// + /// // `next()` has been called once, so `offset()` returns the byte index + /// // of the second character ... /// assert_eq!(chars.offset(), 1); + /// // ... which matches the index returned by the next call to `next()`. /// assert_eq!(chars.next(), Some((1, '楽'))); /// + /// // Once the iterator has been consumed, `offset()` returns the length + /// // in bytes of the string. /// assert_eq!(chars.offset(), 4); /// assert_eq!(chars.next(), None); /// ``` #[inline] #[must_use] - #[unstable(feature = "char_indices_offset", issue = "83871")] + #[stable(feature = "char_indices_offset", since = "CURRENT_RUSTC_VERSION")] pub fn offset(&self) -> usize { self.front_offset } From f1fac42f4a6aa2f9535a32db91c7f9c93220d5a4 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Wed, 21 Aug 2024 09:21:29 +0000 Subject: [PATCH 09/13] llvm 20: adapt integer comparison tests The LLVM commit https://github.com/llvm/llvm-project/commit/abf69a167bbc99054871e3f9cc8810bbebcb6747 changed the IR in a few comparison tests: https://buildkite.com/llvm-project/rust-llvm-integrate-prototype/builds/30500#01917017-26fe-4a4d-956b-725a2903e5a8 Adapted accordingly. --- tests/assembly/x86_64-cmp.rs | 42 ++++++++++++++++++++++++------------ tests/codegen/integer-cmp.rs | 21 +++++++++++------- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/tests/assembly/x86_64-cmp.rs b/tests/assembly/x86_64-cmp.rs index 31efdda1bfafa..67b7ff99ae2d9 100644 --- a/tests/assembly/x86_64-cmp.rs +++ b/tests/assembly/x86_64-cmp.rs @@ -1,6 +1,9 @@ -//@ revisions: DEBUG OPTIM +//@ revisions: DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM //@ [DEBUG] compile-flags: -C opt-level=0 -//@ [OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-PRE-20-OPTIM] ignore-llvm-version: 20 - 99 +//@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3 +//@ [LLVM-20-OPTIM] min-llvm-version: 20 //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel //@ only-x86_64 @@ -21,12 +24,18 @@ pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { // DEBUG: and // DEBUG: sub - // OPTIM: xor - // OPTIM: cmp - // OPTIM: setne - // OPTIM: mov - // OPTIM: cmovge - // OPTIM: ret + // LLVM-PRE-20-OPTIM: xor + // LLVM-PRE-20-OPTIM: cmp + // LLVM-PRE-20-OPTIM: setne + // LLVM-PRE-20-OPTIM: mov + // LLVM-PRE-20-OPTIM: cmovge + // LLVM-PRE-20-OPTIM: ret + // + // LLVM-20-OPTIM: cmp + // LLVM-20-OPTIM: setl + // LLVM-20-OPTIM: setg + // LLVM-20-OPTIM: sub + // LLVM-20-OPTIM: ret three_way_compare(a, b) } @@ -41,11 +50,16 @@ pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { // DEBUG: and // DEBUG: sub - // OPTIM: xor - // OPTIM: cmp - // OPTIM: setne - // OPTIM: mov - // OPTIM: cmovae - // OPTIM: ret + // LLVM-PRE-20-OPTIM: xor + // LLVM-PRE-20-OPTIM: cmp + // LLVM-PRE-20-OPTIM: setne + // LLVM-PRE-20-OPTIM: mov + // LLVM-PRE-20-OPTIM: cmovae + // LLVM-PRE-20-OPTIM: ret + // + // LLVM-20-OPTIM: cmp + // LLVM-20-OPTIM: seta + // LLVM-20-OPTIM: sbb + // LLVM-20-OPTIM: ret three_way_compare(a, b) } diff --git a/tests/codegen/integer-cmp.rs b/tests/codegen/integer-cmp.rs index bba112b246f3f..8df68d8d4906e 100644 --- a/tests/codegen/integer-cmp.rs +++ b/tests/codegen/integer-cmp.rs @@ -1,6 +1,9 @@ // This is test for more optimal Ord implementation for integers. // See for more info. +//@ revisions: llvm-pre-20 llvm-20 +//@ [llvm-20] min-llvm-version: 20 +//@ [llvm-pre-20] ignore-llvm-version: 20 - 99 //@ compile-flags: -C opt-level=3 #![crate_type = "lib"] @@ -10,19 +13,21 @@ use std::cmp::Ordering; // CHECK-LABEL: @cmp_signed #[no_mangle] pub fn cmp_signed(a: i64, b: i64) -> Ordering { - // CHECK: icmp slt - // CHECK: icmp ne - // CHECK: zext i1 - // CHECK: select i1 + // llvm-20: @llvm.scmp.i8.i64 + // llvm-pre-20: icmp slt + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 a.cmp(&b) } // CHECK-LABEL: @cmp_unsigned #[no_mangle] pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { - // CHECK: icmp ult - // CHECK: icmp ne - // CHECK: zext i1 - // CHECK: select i1 + // llvm-20: @llvm.ucmp.i8.i32 + // llvm-pre-20: icmp ult + // llvm-pre-20: icmp ne + // llvm-pre-20: zext i1 + // llvm-pre-20: select i1 a.cmp(&b) } From 18b77354eff7dc810a4d924d4d9bf726bc3d6727 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 1 Aug 2024 13:17:34 -0400 Subject: [PATCH 10/13] rewrite libtest-thread-limit to rmake --- Cargo.lock | 1 + src/tools/run-make-support/Cargo.toml | 1 + src/tools/run-make-support/src/lib.rs | 1 + .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/libtest-thread-limit/Makefile | 7 --- tests/run-make/libtest-thread-limit/rmake.rs | 62 +++++++++++++++++++ tests/run-make/libtest-thread-limit/test.rs | 7 ++- 7 files changed, 71 insertions(+), 9 deletions(-) delete mode 100644 tests/run-make/libtest-thread-limit/Makefile create mode 100644 tests/run-make/libtest-thread-limit/rmake.rs diff --git a/Cargo.lock b/Cargo.lock index a18219b56837e..97146fcfd516d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3129,6 +3129,7 @@ dependencies = [ "bstr", "build_helper", "gimli 0.31.0", + "libc", "object 0.36.3", "regex", "serde_json", diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 1a13d56b0e42f..77df6e7beb591 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -12,3 +12,4 @@ regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" build_helper = { path = "../build_helper" } serde_json = "1.0" +libc = "0.2" diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index fc20fd3b2e86a..d010ed29f1d26 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -36,6 +36,7 @@ pub mod rfs { // Re-exports of third-party library crates. pub use bstr; pub use gimli; +pub use libc; pub use object; pub use regex; pub use serde_json; diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f55abb513b80d..0f7213c536a89 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -6,7 +6,6 @@ run-make/incr-add-rust-src-component/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile run-make/jobserver-error/Makefile run-make/libs-through-symlinks/Makefile -run-make/libtest-thread-limit/Makefile run-make/macos-deployment-target/Makefile run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile diff --git a/tests/run-make/libtest-thread-limit/Makefile b/tests/run-make/libtest-thread-limit/Makefile deleted file mode 100644 index 9496fa30159a6..0000000000000 --- a/tests/run-make/libtest-thread-limit/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -# only-linux - -all: - $(RUSTC) test.rs --test --target $(TARGET) - $(shell ulimit -p 0 && $(call RUN,test)) diff --git a/tests/run-make/libtest-thread-limit/rmake.rs b/tests/run-make/libtest-thread-limit/rmake.rs new file mode 100644 index 0000000000000..f3551ad2d55f6 --- /dev/null +++ b/tests/run-make/libtest-thread-limit/rmake.rs @@ -0,0 +1,62 @@ +// libtest used to panic if it hit the thread limit. This often resulted in spurious test failures +// (thread 'main' panicked at 'called Result::unwrap() on an Err value: Os +// { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }' ... +// error: test failed, to rerun pass '--lib'). +// Since the fix in #81546, the test should continue to run synchronously +// if it runs out of threads. Therefore, this test's final execution step +// should succeed without an error. +// See https://github.com/rust-lang/rust/pull/81546 + +//@ only-linux +// Reason: thread limit modification + +use std::ffi::{self, CStr, CString}; +use std::path::PathBuf; + +use run_make_support::{libc, run, rustc}; + +fn main() { + rustc().input("test.rs").arg("--test").run(); + + // We need to emulate an environment for libtest where threads are exhausted and spawning + // new threads are guaranteed to fail. This was previously achieved by ulimit shell builtin + // that called out to prlimit64 underneath to set resource limits (specifically thread + // number limits). Now that we don't have a shell, we need to implement that ourselves. + // See https://linux.die.net/man/2/setrlimit + + // The fork + exec is required because we cannot first try to limit the number of + // processes/threads to 1 and then try to spawn a new process to run the test. We need to + // setrlimit and run the libtest test program in the same process. + let pid = unsafe { libc::fork() }; + assert!(pid >= 0); + + // If the process ID is 0, this is the child process responsible for running the test + // program. + if pid == 0 { + let test = CString::new("test").unwrap(); + // The argv array should be terminated with a NULL pointer. + let argv = [test.as_ptr(), std::ptr::null()]; + // rlim_cur is soft limit, rlim_max is hard limit. + // By setting the limit very low (max 1), we ensure that libtest is unable to create new + // threads. + let rlimit = libc::rlimit { rlim_cur: 1, rlim_max: 1 }; + // RLIMIT_NPROC: The maximum number of processes (or, more precisely on Linux, + // threads) that can be created for the real user ID of the calling process. Upon + // encountering this limit, fork(2) fails with the error EAGAIN. + // Therefore, set the resource limit to RLIMIT_NPROC. + let ret = unsafe { libc::setrlimit(libc::RLIMIT_NPROC, &rlimit as *const libc::rlimit) }; + assert!(ret == 0); + + // Finally, execute the 2 tests in test.rs. + let ret = unsafe { libc::execv(test.as_ptr(), argv.as_ptr()) }; + assert!(ret == 0); + } else { + // Otherwise, other process IDs indicate that this is the parent process. + + let mut status: libc::c_int = 0; + let ret = unsafe { libc::waitpid(pid, &mut status as *mut libc::c_int, 0) }; + assert!(ret == pid); + assert!(libc::WIFEXITED(status)); + assert!(libc::WEXITSTATUS(status) == 0); + } +} diff --git a/tests/run-make/libtest-thread-limit/test.rs b/tests/run-make/libtest-thread-limit/test.rs index 87e1d51917106..d4eb12426158b 100644 --- a/tests/run-make/libtest-thread-limit/test.rs +++ b/tests/run-make/libtest-thread-limit/test.rs @@ -10,7 +10,12 @@ fn spawn_thread_would_block() { THREAD_ID.set(thread::current().id()).unwrap(); } +// Tests are run in alphabetical order, and the second test is dependent on the +// first to set THREAD_ID. Do not rename the tests in such a way that `test_run_in_same_thread` +// would run before `spawn_thread_would_block`. +// See https://doc.rust-lang.org/rustc/tests/index.html#--shuffle + #[test] -fn run_in_same_thread() { +fn test_run_in_same_thread() { assert_eq!(*THREAD_ID.get().unwrap(), thread::current().id()); } From e37e15dc0bd9e4a21ced7a5c534c4c64dc3dfeda Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Aug 2024 18:05:11 +0200 Subject: [PATCH 11/13] Fix extern crates not being hidden with `doc(hidden)` --- src/librustdoc/passes/strip_hidden.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index faf42b3aab13e..23e298571d5ce 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,7 +2,7 @@ use std::mem; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; @@ -145,8 +145,9 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { let old = mem::replace(&mut self.update_retained, false); let ret = self.set_is_in_hidden_item_and_fold(true, i); self.update_retained = old; - if ret.is_crate() { - // We don't strip the crate, even if it has `#[doc(hidden)]`. + if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) { + // We don't strip the current crate, even if it has `#[doc(hidden)]`. + debug!("strip_hidden: Not strippping local crate"); Some(ret) } else { Some(strip_item(ret)) From 4de29c90478003ce28880e92986ee7f2fc9c2d33 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Aug 2024 18:05:52 +0200 Subject: [PATCH 12/13] Add regression test for #126796 --- tests/rustdoc/doc-hidden-crate.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/rustdoc/doc-hidden-crate.rs diff --git a/tests/rustdoc/doc-hidden-crate.rs b/tests/rustdoc/doc-hidden-crate.rs new file mode 100644 index 0000000000000..dac557107a903 --- /dev/null +++ b/tests/rustdoc/doc-hidden-crate.rs @@ -0,0 +1,27 @@ +// Regression test for . +// `doc(hidden)` should still be able to hide extern crates, only the local crates +// cannot be hidden because we still need to generate its `index.html` file. + +#![crate_name = "foo"] +#![doc(hidden)] + +//@ has 'foo/index.html' +// First we check that the page contains the crate name (`foo`). +//@ has - '//*' 'foo' +// But doesn't contain any of the other items. +//@ !has - '//*' 'other' +//@ !has - '//*' 'marker' +//@ !has - '//*' 'PhantomData' + +#[doc(inline)] +pub use std as other; + +#[doc(inline)] +pub use std::marker; + +#[doc(inline)] +pub use std::marker::PhantomData; + +//@ !has - '//*' 'myself' +#[doc(inline)] +pub use crate as myself; From 8151de2820442d2d19a5cabaefcafc64d7490c6f Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Thu, 22 Aug 2024 11:33:51 -0700 Subject: [PATCH 13/13] rustdoc-search: use tighter json for names and parents File size --------- ```console $ du -hs doc.old/search-index1.82.0.js doc/search-index1.82.0.js 3.2M doc.old/search-index1.82.0.js 2.8M doc/search-index1.82.0.js $ gzip doc/search-index1.82.0.js $ gzip doc.old/search-index1.82.0.js $ du -hs doc.old/search-index1.82.0.js.gz doc/search-index1.82.0.js.gz 464K doc.old/search-index1.82.0.js.gz 456K doc/search-index1.82.0.js.gz $ du -hs compiler-doc.old/search-index.js compiler-doc/search-index.js 8.5M compiler-doc.old/search-index.js 6.5M compiler-doc/search-index.js $ gzip compiler-doc/search-index1.82.0.js $ gzip compiler-doc.old/search-index1.82.0.js $ du -hs compiler-doc.old/search-index.js.gz compiler-doc/search-index.js.gz 1.4M compiler-doc.old/search-index.js.gz 1.4M compiler-doc/search-index.js.gz ``` --- src/librustdoc/html/render/search_index.rs | 36 ++++++++++++++++++---- src/librustdoc/html/static/js/search.js | 17 +++++----- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 8a12bdef69bf4..d7682bd1c1917 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -579,12 +579,14 @@ pub(crate) fn build_index<'tcx>( let mut names = Vec::with_capacity(self.items.len()); let mut types = String::with_capacity(self.items.len()); let mut full_paths = Vec::with_capacity(self.items.len()); - let mut parents = Vec::with_capacity(self.items.len()); + let mut parents = String::with_capacity(self.items.len()); + let mut parents_backref_queue = VecDeque::new(); let mut functions = String::with_capacity(self.items.len()); let mut deprecated = Vec::with_capacity(self.items.len()); - let mut backref_queue = VecDeque::new(); + let mut type_backref_queue = VecDeque::new(); + let mut last_name = None; for (index, item) in self.items.iter().enumerate() { let n = item.ty as u8; let c = char::try_from(n + b'A').expect("item types must fit in ASCII"); @@ -597,17 +599,39 @@ pub(crate) fn build_index<'tcx>( "`{}` is missing idx", item.name ); - // 0 is a sentinel, everything else is one-indexed - parents.push(item.parent_idx.map(|x| x + 1).unwrap_or(0)); + assert!( + parents_backref_queue.len() <= 16, + "the string encoding only supports 16 slots of lookback" + ); + let parent: i32 = item.parent_idx.map(|x| x + 1).unwrap_or(0).try_into().unwrap(); + if let Some(idx) = parents_backref_queue.iter().position(|p: &i32| *p == parent) { + parents.push( + char::try_from('0' as u32 + u32::try_from(idx).unwrap()) + .expect("last possible value is '?'"), + ); + } else if parent == 0 { + write_vlqhex_to_string(parent, &mut parents); + } else { + parents_backref_queue.push_front(parent); + write_vlqhex_to_string(parent, &mut parents); + if parents_backref_queue.len() > 16 { + parents_backref_queue.pop_back(); + } + } - names.push(item.name.as_str()); + if Some(item.name.as_str()) == last_name { + names.push(""); + } else { + names.push(item.name.as_str()); + last_name = Some(item.name.as_str()); + } if !item.path.is_empty() { full_paths.push((index, &item.path)); } match &item.search_type { - Some(ty) => ty.write_to_string(&mut functions, &mut backref_queue), + Some(ty) => ty.write_to_string(&mut functions, &mut type_backref_queue), None => functions.push('`'), } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 3eb27ea087c1d..4e3b532ae08ae 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -3546,7 +3546,7 @@ ${item.displayPath}${name}\ // Used to de-duplicate inlined and re-exported stuff const itemReexports = new Map(crateCorpus.r); // an array of (Number) the parent path index + 1 to `paths`, or 0 if none - const itemParentIdxs = crateCorpus.i; + const itemParentIdxDecoder = new VlqHexDecoder(crateCorpus.i, noop => noop); // a map Number, string for impl disambiguators const implDisambiguator = new Map(crateCorpus.b); // an array of [(Number) item type, @@ -3593,6 +3593,8 @@ ${item.displayPath}${name}\ // faster analysis operations lastPath = ""; len = itemTypes.length; + let lastName = ""; + let lastWord = ""; for (let i = 0; i < len; ++i) { const bitIndex = i + 1; if (descIndex >= descShard.len && @@ -3608,10 +3610,8 @@ ${item.displayPath}${name}\ descIndex = 0; descShardList.push(descShard); } - let word = ""; - if (typeof itemNames[i] === "string") { - word = itemNames[i].toLowerCase(); - } + const name = itemNames[i] === "" ? lastName : itemNames[i]; + const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase(); const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath; const type = itemFunctionDecoder.next(); if (type !== null) { @@ -3633,15 +3633,16 @@ ${item.displayPath}${name}\ } // This object should have exactly the same set of fields as the "crateRow" // object defined above. + const itemParentIdx = itemParentIdxDecoder.next(); const row = { crate, ty: itemTypes.charCodeAt(i) - 65, // 65 = "A" - name: itemNames[i], + name, path, descShard, descIndex, exactPath: itemReexports.has(i) ? itemPaths.get(itemReexports.get(i)) : path, - parent: itemParentIdxs[i] > 0 ? paths[itemParentIdxs[i] - 1] : undefined, + parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined, type, id, word, @@ -3655,6 +3656,8 @@ ${item.displayPath}${name}\ if (!searchIndexEmptyDesc.get(crate).contains(bitIndex)) { descIndex += 1; } + lastName = name; + lastWord = word; } if (aliases) {