diff --git a/Cargo.lock b/Cargo.lock index 873182dde9102..9d5d0f2d403f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6213,9 +6213,9 @@ dependencies = [ [[package]] name = "wasi-preview1-component-adapter-provider" -version = "44.0.2" +version = "46.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2211ca2d69a88055eefb06bad741dde3180c9d4020f7e42fea72caba83f9c10c" +checksum = "1b6c48003fe59c201c97a7786ff55feabe6b6f83b598aa9ff5bcc4f94d940bf3" [[package]] name = "wasip2" @@ -6282,9 +6282,9 @@ dependencies = [ [[package]] name = "wasm-component-ld" -version = "0.5.25" +version = "0.5.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee72c06c556db23aca2d29e1e183d96efdffa7110b24915629a5091de600a894" +checksum = "51a12709376d4ce64f472699500db3b0e5902cc2bef16fb6ca3098bfdac032fa" dependencies = [ "anyhow", "clap", @@ -6293,12 +6293,12 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.252.0", + "wasmparser 0.253.0", "wat", "windows-sys 0.61.2", "winsplit", - "wit-component 0.252.0", - "wit-parser 0.252.0", + "wit-component 0.253.0", + "wit-parser 0.253.0", ] [[package]] @@ -6330,12 +6330,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f" +checksum = "59972d6cd272259de647b7c1f1912e45e289c75ffd4be04e10695507cd7e1b59" dependencies = [ "leb128fmt", - "wasmparser 0.252.0", + "wasmparser 0.253.0", ] [[package]] @@ -6352,14 +6352,14 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b7e08e02a3cd55bf778009d4cd6faae50da011f293644daf78a531a32d6d142" +checksum = "b3f45816ef616806f48498bcd831377de578c4fa51db0c83ab8ceb78cc13523b" dependencies = [ "anyhow", "indexmap", - "wasm-encoder 0.252.0", - "wasmparser 0.252.0", + "wasm-encoder 0.253.0", + "wasmparser 0.253.0", ] [[package]] @@ -6396,9 +6396,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c" +checksum = "19db11f87d2486580e1e8b6f494c54df7e0566b87d0b599db843c24019667339" dependencies = [ "bitflags", "hashbrown 0.17.0", @@ -6409,22 +6409,22 @@ dependencies = [ [[package]] name = "wast" -version = "252.0.0" +version = "253.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942a3449d6a593fccc111a6241c8df52bda168af30e40bf9580d4394d7374c65" +checksum = "d3264542f8965c5d84fb1085d924bfba9a6314bb228eff13a2de14d7627664d0" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.2", - "wasm-encoder 0.252.0", + "wasm-encoder 0.253.0", ] [[package]] name = "wat" -version = "1.252.0" +version = "1.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c72a4ba7088f7bac94cf516e49882bdf97068904a563768cf249efc839ec42cb" +checksum = "4bfc5ce906144200c972ec617470aa35bd847472e170b26dde3e80541c674055" dependencies = [ "wast", ] @@ -6872,9 +6872,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76db0662b590f45d33d0e363fa13539a5a1eecd35d5a12fe208c335461c1053d" +checksum = "dbbd2500ac3488489ee8c6e59b79d7e47e6da5bfb019efd35d5dca57b78af624" dependencies = [ "anyhow", "bitflags", @@ -6883,10 +6883,10 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.252.0", - "wasm-metadata 0.252.0", - "wasmparser 0.252.0", - "wit-parser 0.252.0", + "wasm-encoder 0.253.0", + "wasm-metadata 0.253.0", + "wasmparser 0.253.0", + "wit-parser 0.253.0", ] [[package]] @@ -6909,9 +6909,9 @@ dependencies = [ [[package]] name = "wit-parser" -version = "0.252.0" +version = "0.253.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4266bea110371c620ccf3201c5023676046bc4556e5c7cfb5d500bda5ebc162d" +checksum = "4d997b8e5920fcbeec742b58e583325d6419a6aca617ae8075c406a61c65ba8a" dependencies = [ "anyhow", "hashbrown 0.17.0", @@ -6923,7 +6923,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-ident", - "wasmparser 0.252.0", + "wasmparser 0.253.0", ] [[package]] diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 41e87caf40c7d..4fda4735b613c 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -89,7 +89,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { unreachable!("`homogeneous_aggregate` should not be called for scalable vectors") } - BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { sized: true } => { // Helper for computing `homogeneous_aggregate`, allowing a custom // starting offset (used below for handling variants). let from_fields_at = diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 003e811dc7855..ad48e14430952 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -476,7 +476,7 @@ impl LayoutCalculator { Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true }, Ok(Some((repr, _))) => match repr { // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt - BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _) + BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } if repr.scalar_platform_align(dl).unwrap() != align => { BackendRepr::Memory { sized: true } @@ -489,7 +489,7 @@ impl LayoutCalculator { } // the alignment tests passed and we can use this BackendRepr::Scalar(..) - | BackendRepr::ScalarPair(..) + | BackendRepr::ScalarPair { .. } | BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } | BackendRepr::Memory { .. } => repr, @@ -558,7 +558,7 @@ impl LayoutCalculator { }; match &mut st.backend_repr { BackendRepr::Scalar(scalar) => hide_niches(scalar), - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair { a, b, b_offset: _ } => { hide_niches(a); hide_niches(b); } @@ -701,13 +701,21 @@ impl LayoutCalculator { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. BackendRepr::Scalar(_) => BackendRepr::Scalar(niche_scalar), - BackendRepr::ScalarPair(first, second) => { + BackendRepr::ScalarPair { a: first, b: second, b_offset } => { // Only the niche is guaranteed to be initialised, // so use union layouts for the other primitive. if niche_offset == Size::ZERO { - BackendRepr::ScalarPair(niche_scalar, second.to_union()) + BackendRepr::ScalarPair { + a: niche_scalar, + b: second.to_union(), + b_offset, + } } else { - BackendRepr::ScalarPair(first.to_union(), niche_scalar) + BackendRepr::ScalarPair { + a: first.to_union(), + b: niche_scalar, + b_offset, + } } } _ => BackendRepr::Memory { sized: true }, @@ -1037,7 +1045,7 @@ impl LayoutCalculator { // If we pick a "clever" (by-value) ABI, we might have to adjust the ABI of the // variants to ensure they are consistent. This is because a downcast is // semantically a NOP, and thus should not affect layout. - if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { + if matches!(abi, BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }) { for variant in &mut layout_variants { // We only do this for variants with fields; the others are not accessed anyway. // Also do not overwrite any already existing "clever" ABIs. @@ -1354,7 +1362,7 @@ impl LayoutCalculator { } // But scalar pairs are Rust-specific and get // treated as aggregates by C ABIs anyway. - BackendRepr::ScalarPair(..) => { + BackendRepr::ScalarPair { .. } => { abi = field.backend_repr; } _ => {} diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index 5fd504def384a..1fffb84ec21cb 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -110,7 +110,7 @@ impl LayoutData { offsets: [Size::ZERO, b_offset].into(), in_memory_order: [FieldIdx::new(0), FieldIdx::new(1)].into(), }, - backend_repr: BackendRepr::ScalarPair(a, b), + backend_repr: BackendRepr::ScalarPair { a, b, b_offset }, largest_niche, uninhabited: false, align: AbiAlign::new(align), diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index c2069432e6f8e..b8cd152e30288 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1796,14 +1796,18 @@ impl IntoDiagArg for NumScalableVectors { pub enum BackendRepr { Scalar(Scalar), /// The data contained in this type can be entirely represented by two scalars. - /// The two scalars are listed in *memory* order, so the first is at offset zero - /// and the second at a non-zero offset. + /// The two scalars are listed in *memory* order, so `a` is at offset zero + /// and `b` is at non-zero offset `b_offset`. /// These need not be `FieldIdx(0)` and `FieldIdx(1)`. /// - /// As of June 2026 the offset to the second scalar is the size of the first - /// scalar rounded up to the platform alignment of the second scalar. + /// As of June 2026 the `b_offset` is always the size of the `a` + /// scalar rounded up to the platform alignment of the `b` scalar. /// That may soon change, however; see MCP#1007. - ScalarPair(Scalar, Scalar), + ScalarPair { + a: Scalar, + b: Scalar, + b_offset: Size, + }, SimdScalableVector { element: Scalar, count: u64, @@ -1826,7 +1830,7 @@ impl BackendRepr { pub fn is_unsized(&self) -> bool { match *self { BackendRepr::Scalar(_) - | BackendRepr::ScalarPair(..) + | BackendRepr::ScalarPair { .. } // FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the // `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is // fully implemented, scalable vectors will remain `Sized`, they just won't be @@ -1875,7 +1879,7 @@ impl BackendRepr { pub fn scalar_platform_align(&self, cx: &C) -> Option { match *self { BackendRepr::Scalar(s) => Some(s.default_align(cx).abi), - BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => { Some(s1.default_align(cx).max(s2.default_align(cx)).abi) } // The align of a Vector can vary in surprising ways @@ -1893,8 +1897,7 @@ impl BackendRepr { // No padding in scalars. BackendRepr::Scalar(s) => Some(s.size(cx)), // May have some padding between the pair. - BackendRepr::ScalarPair(s1, s2) => { - let field2_offset = s1.size(cx).align_to(s2.default_align(cx).abi); + BackendRepr::ScalarPair { a: _, b: s2, b_offset: field2_offset } => { let size = (field2_offset + s2.size(cx)).align_to( self.scalar_platform_align(cx) // We absolutely must have an answer here or everything is FUBAR. @@ -1913,8 +1916,8 @@ impl BackendRepr { pub fn to_union(&self) -> Self { match *self { BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()), - BackendRepr::ScalarPair(s1, s2) => { - BackendRepr::ScalarPair(s1.to_union(), s2.to_union()) + BackendRepr::ScalarPair { a: s1, b: s2, b_offset } => { + BackendRepr::ScalarPair { a: s1.to_union(), b: s2.to_union(), b_offset } } BackendRepr::SimdVector { element, count } => { BackendRepr::SimdVector { element: element.to_union(), count } @@ -1939,8 +1942,13 @@ impl BackendRepr { BackendRepr::SimdVector { element: element_l, count: count_l }, BackendRepr::SimdVector { element: element_r, count: count_r }, ) => element_l.primitive() == element_r.primitive() && count_l == count_r, - (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => { - l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() + ( + BackendRepr::ScalarPair { a: l1, b: l2, b_offset: l_offset }, + BackendRepr::ScalarPair { a: r1, b: r2, b_offset: r_offset }, + ) => { + l1.primitive() == r1.primitive() + && l2.primitive() == r2.primitive() + && l_offset == r_offset } // Everything else must be strictly identical. _ => self == other, @@ -2180,7 +2188,7 @@ impl LayoutData { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => false, - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => true, } } @@ -2294,7 +2302,7 @@ impl LayoutData { pub fn is_zst(&self) -> bool { match self.backend_repr { BackendRepr::Scalar(_) - | BackendRepr::ScalarPair(..) + | BackendRepr::ScalarPair { .. } | BackendRepr::SimdScalableVector { .. } | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 012951098fa15..ec17e72900dfb 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -220,7 +220,7 @@ fn make_local_place<'tcx>( ); } let place = if is_ssa { - if let BackendRepr::ScalarPair(_, _) = layout.backend_repr { + if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = layout.backend_repr { CPlace::new_var_pair(fx, local, layout) } else { CPlace::new_var(fx, local, layout) diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 612f89e6a4217..75d7e4d9fd500 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -112,7 +112,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr { - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair { a, b, b_offset: _ } => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); smallvec![ @@ -167,7 +167,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { _ => unreachable!("{:?}", self.layout.backend_repr), }, PassMode::Pair(attrs_a, attrs_b) => match self.layout.backend_repr { - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair { a, b, b_offset: _ } => { let a = scalar_to_clif_type(tcx, a); let b = scalar_to_clif_type(tcx, b); ( diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index b37fb213d945a..bf6a98866cd12 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -695,7 +695,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: } UnOp::PtrMetadata => match layout.backend_repr { BackendRepr::Scalar(_) => CValue::zst(dest_layout), - BackendRepr::ScalarPair(_, _) => { + BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => { CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout) } _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"), diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index e6b8c537d8451..d4bb8bd019331 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -572,7 +572,9 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr { + let meta = if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = + ptr.layout().backend_repr + { Some(ptr.load_scalar_pair(fx).1) } else { None @@ -586,7 +588,9 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = fx.layout_of(generic_args.type_at(0)); // Note: Can't use is_unsized here as truly unsized types need to take the fixed size // branch - let meta = if let BackendRepr::ScalarPair(_, _) = ptr.layout().backend_repr { + let meta = if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = + ptr.layout().backend_repr + { Some(ptr.load_scalar_pair(fx).1) } else { None diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 995a70f24240b..d7248acfafef1 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -55,8 +55,7 @@ fn codegen_field<'tcx>( } } -fn scalar_pair_calculate_b_offset(tcx: TyCtxt<'_>, a_scalar: Scalar, b_scalar: Scalar) -> Offset32 { - let b_offset = a_scalar.size(&tcx).align_to(b_scalar.default_align(&tcx).abi); +fn scalar_pair_convert_b_offset(b_offset: Size) -> Offset32 { Offset32::new(b_offset.bytes().try_into().unwrap()) } @@ -159,11 +158,11 @@ impl<'tcx> CValue<'tcx> { let layout = self.1; match self.0 { CValueInner::ByRef(ptr, None) => { - let (a_scalar, b_scalar) = match layout.backend_repr { - BackendRepr::ScalarPair(a, b) => (a, b), + let (a_scalar, b_scalar, b_offset) = match layout.backend_repr { + BackendRepr::ScalarPair { a, b, b_offset } => (a, b, b_offset), _ => unreachable!("load_scalar_pair({:?})", self), }; - let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); + let b_offset = scalar_pair_convert_b_offset(b_offset); let clif_ty1 = scalar_to_clif_type(fx.tcx, a_scalar); let clif_ty2 = scalar_to_clif_type(fx.tcx, b_scalar); let mut flags = MemFlags::new(); @@ -189,7 +188,7 @@ impl<'tcx> CValue<'tcx> { match self.0 { CValueInner::ByVal(_) => unreachable!(), CValueInner::ByValPair(val1, val2) => match layout.backend_repr { - BackendRepr::ScalarPair(_, _) => { + BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => { let val = match field.as_u32() { 0 => val1, 1 => val2, @@ -580,7 +579,7 @@ impl<'tcx> CPlace<'tcx> { } CPlaceInner::VarPair(_local, var1, var2) => { let (data1, data2) = match from.1.backend_repr { - BackendRepr::ScalarPair(_, _) => { + BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => { CValue(from.0, dst_layout).load_scalar_pair(fx) } _ => { @@ -607,9 +606,8 @@ impl<'tcx> CPlace<'tcx> { to_ptr.store(fx, val, flags); } CValueInner::ByValPair(val1, val2) => match from.layout().backend_repr { - BackendRepr::ScalarPair(a_scalar, b_scalar) => { - let b_offset = - scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); + BackendRepr::ScalarPair { a: _, b: _, b_offset } => { + let b_offset = scalar_pair_convert_b_offset(b_offset); to_ptr.store(fx, val1, flags); to_ptr.offset(fx, b_offset).store(fx, val2, flags); } @@ -627,9 +625,8 @@ impl<'tcx> CPlace<'tcx> { to_ptr.store(fx, val, flags); return; } - BackendRepr::ScalarPair(a_scalar, b_scalar) => { - let b_offset = - scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar); + BackendRepr::ScalarPair { a: _, b: _, b_offset } => { + let b_offset = scalar_pair_convert_b_offset(b_offset); let (val1, val2) = from.load_scalar_pair(fx); to_ptr.store(fx, val1, flags); to_ptr.offset(fx, b_offset).store(fx, val2, flags); diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index b5d241d8f39f2..3310e4e3a2228 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -56,13 +56,14 @@ pub(crate) fn get_ptr_and_method_ref<'tcx>( } } - let (ptr, vtable) = if let BackendRepr::ScalarPair(_, _) = arg.layout().backend_repr { - let (ptr, vtable) = arg.load_scalar_pair(fx); - (Pointer::new(ptr), vtable) - } else { - let (ptr, vtable) = arg.try_to_ptr().unwrap(); - (ptr, vtable.unwrap()) - }; + let (ptr, vtable) = + if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = arg.layout().backend_repr { + let (ptr, vtable) = arg.load_scalar_pair(fx); + (Pointer::new(ptr), vtable) + } else { + let (ptr, vtable) = arg.try_to_ptr().unwrap(); + (ptr, vtable.unwrap()) + }; let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes(); let func_ref = fx.bcx.ins().load( diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index f9358872299b7..0bef86b1ae8c1 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1064,9 +1064,9 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { load }, ) - } else if let abi::BackendRepr::ScalarPair(ref a, ref b) = place.layout.backend_repr { - let b_offset = a.size(self).align_to(b.default_align(self).abi); - + } else if let abi::BackendRepr::ScalarPair { ref a, ref b, b_offset } = + place.layout.backend_repr + { let mut load = |i, scalar: &abi::Scalar, align| { let ptr = if i == 0 { place.val.llval diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 78a4c7e88c895..a5b8068e0f018 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -485,7 +485,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { - Scalar(_) | ScalarPair(_, _) => true, + Scalar(_) | ScalarPair { a: _, b: _, b_offset: _ } => true, SimdVector { .. } | SimdScalableVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 9807a84c0788d..227b513c0ff30 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -75,7 +75,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( }; return cx.context.new_vector_type(element, count); } - BackendRepr::ScalarPair(..) => { + BackendRepr::ScalarPair { .. } => { return cx.type_struct( &[ layout.scalar_pair_element_gcc_type(cx, 0), @@ -182,13 +182,13 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, // FIXME(rustc_scalable_vector): Not yet implemented in rustc_codegen_gcc. BackendRepr::SimdScalableVector { .. } => todo!(), - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => false, } } fn is_gcc_scalar_pair(&self) -> bool { match self.backend_repr { - BackendRepr::ScalarPair(..) => true, + BackendRepr::ScalarPair { .. } => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } @@ -308,8 +308,8 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - let (a, b) = match self.backend_repr { - BackendRepr::ScalarPair(ref a, ref b) => (a, b), + let (a, b, b_offset) = match self.backend_repr { + BackendRepr::ScalarPair { ref a, ref b, b_offset } => (a, b, b_offset), _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self), }; let scalar = [a, b][index]; @@ -325,8 +325,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { return cx.type_i1(); } - let offset = - if index == 0 { Size::ZERO } else { a.size(cx).align_to(b.default_align(cx).abi) }; + let offset = if index == 0 { Size::ZERO } else { b_offset }; self.scalar_gcc_type_at(cx, scalar, offset) } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index bdaf72cb17ce6..65bb32ee666f2 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -551,7 +551,9 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Pair(a, b) => { let i = apply(a); let ii = apply(b); - if let BackendRepr::ScalarPair(scalar_a, scalar_b) = arg.layout.backend_repr { + if let BackendRepr::ScalarPair { a: scalar_a, b: scalar_b, b_offset: _ } = + arg.layout.backend_repr + { apply_range_attr(llvm::AttributePlace::Argument(i), scalar_a); let primitive_b = scalar_b.primitive(); let scalar_b = if let rustc_abi::Primitive::Int(int, false) = primitive_b diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 23cf01a84f7fd..e753fff61aa41 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -793,9 +793,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } }); OperandValue::Immediate(llval) - } else if let abi::BackendRepr::ScalarPair(a, b) = place.layout.backend_repr { - let b_offset = a.size(self).align_to(b.default_align(self).abi); - + } else if let abi::BackendRepr::ScalarPair { a, b, b_offset } = place.layout.backend_repr { let mut load = |i, scalar: abi::Scalar, layout, align, offset| { let llptr = if i == 0 { place.val.llval diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 10e152a7c8c63..b0ac5c096efdf 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -118,7 +118,9 @@ pub(crate) fn adjust_activity_to_abi<'tcx>( // If the argument is lowered as a `ScalarPair`, we need to duplicate its activity. // Otherwise, the number of activities won't match the number of LLVM arguments and // this will lead to errors when verifying the Enzyme call. - if let rustc_abi::BackendRepr::ScalarPair(_, _) = layout.backend_repr() { + if let rustc_abi::BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = + layout.backend_repr() + { new_activities.push(da[i].clone()); new_positions.push(i + 1 - del_activities); } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index bd7a4cfe38d48..54456ddea620b 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -574,7 +574,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let tp_ty = fn_args.type_at(0); let layout = self.layout_of(tp_ty).layout; let use_integer_compare = match layout.backend_repr() { - Scalar(_) | ScalarPair(_, _) => true, + Scalar(_) | ScalarPair { a: _, b: _, b_offset: _ } => true, SimdVector { .. } => false, SimdScalableVector { .. } => { let err = tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 6d0490e4a1f79..d1c2e1d567e40 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -73,7 +73,7 @@ fn uncached_llvm_type<'a, 'tcx>( _ => bug!("`#[rustc_scalable_vector]` tuple struct with too many fields"), }; } - BackendRepr::Memory { .. } | BackendRepr::ScalarPair(..) => {} + BackendRepr::Memory { .. } | BackendRepr::ScalarPair { .. } => {} } let name = match layout.ty.kind() { @@ -228,13 +228,13 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => true, - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => false, } } fn is_llvm_scalar_pair(&self) -> bool { match self.backend_repr { - BackendRepr::ScalarPair(..) => true, + BackendRepr::ScalarPair { .. } => true, BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } @@ -313,7 +313,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { return cx.type_i1(); } } - BackendRepr::ScalarPair(..) => { + BackendRepr::ScalarPair { .. } => { // An immediate pair always contains just the two elements, without any padding // filler, as it should never be stored to memory. return cx.type_struct( @@ -346,7 +346,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // This must produce the same result for `repr(transparent)` wrappers as for the inner type! // In other words, this should generally not look at the type at all, but only at the // layout. - let BackendRepr::ScalarPair(a, b) = self.backend_repr else { + let BackendRepr::ScalarPair { a, b, b_offset: _ } = self.backend_repr else { bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self); }; let scalar = [a, b][index]; diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index b8d1cd3504517..d2583f94cf80c 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -564,7 +564,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( BackendRepr::Scalar(scalar) => { registers_for_primitive(scalar.primitive()); } - BackendRepr::ScalarPair(scalar1, scalar2) => { + BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset: _ } => { registers_for_primitive(scalar1.primitive()); registers_for_primitive(scalar2.primitive()); } @@ -641,7 +641,7 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( } Primitive::Float(_) => bx.inbounds_ptradd(reg_save_area_v, fp_offset_v), }, - BackendRepr::ScalarPair(scalar1, scalar2) => { + BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset: offset } => { let ty_lo = bx.cx().scalar_pair_element_backend_type(layout, 0, false); let ty_hi = bx.cx().scalar_pair_element_backend_type(layout, 1, false); @@ -665,9 +665,8 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo); let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi); - let offset = scalar1.size(bx.cx).align_to(align_hi).bytes(); let field0 = tmp; - let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset as u32)); + let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset.bytes() as u32)); bx.store(reg_lo, field0, align); bx.store(reg_hi, field1, align); @@ -688,9 +687,8 @@ fn emit_x86_64_sysv64_va_arg<'ll, 'tcx>( let reg_lo = bx.load(ty_lo, reg_lo_addr, align_lo); let reg_hi = bx.load(ty_hi, reg_hi_addr, align_hi); - let offset = scalar1.size(bx.cx).align_to(align_hi).bytes(); let field0 = tmp; - let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset as u32)); + let field1 = bx.inbounds_ptradd(tmp, bx.const_u32(offset.bytes() as u32)); bx.store(reg_lo, field0, align_lo); bx.store(reg_hi, field1, align_hi); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8c20db5791774..e24e7bad2b945 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1286,9 +1286,24 @@ impl<'a> Linker for EmLinker<'a> { self.cc_arg("-s"); + // Emscripten exposes the program entry point under the JS name `_main` + // regardless of the underlying wasm symbol (which is `__main_argc_argv` + // per the wasm C ABI in the tool-conventions BasicCABI spec), bridging + // the two internally. So the entry symbol must be requested as `_main` + // here rather than as a `_`-prefixed form of its wasm name. + let entry_name = self.sess.target.entry_name.as_ref(); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( - &symbols.iter().map(|sym| "_".to_owned() + &sym.name).collect::>(), + &symbols + .iter() + .map(|sym| { + if sym.name == entry_name { + "_main".to_owned() + } else { + "_".to_owned() + &sym.name + } + }) + .collect::>(), ) .unwrap(); debug!("{encoded}"); diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 71315acc4e5db..c586b8080ef30 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -611,7 +611,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // be marked as a `LocalVariable` for MSVC debuggers to visualize // their data correctly. (See #81894 & #88625) let var_ty_layout = self.cx.layout_of(var_ty); - if let BackendRepr::ScalarPair(_, _) = var_ty_layout.backend_repr { + if let BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } = + var_ty_layout.backend_repr + { VariableKind::LocalVariable } else { VariableKind::ArgumentVariable(arg_index) diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 0b00b22b1a992..9ce8e6e48bbd1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -441,7 +441,7 @@ fn wasm_type<'tcx>(signature: &mut String, arg_abi: &ArgAbi<'_, Ty<'tcx>>, ptr_t signature.push_str(direct_type); } PassMode::Pair(_, _) => match arg_abi.layout.backend_repr { - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair { a, b, b_offset: _ } => { signature.push_str(wasm_primitive(a.primitive(), ptr_type)); signature.push_str(", "); signature.push_str(wasm_primitive(b.primitive(), ptr_type)); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 0246da3f27829..f2594b712d8cd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -168,7 +168,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { alloc_id, meta } => { - let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else { + let BackendRepr::ScalarPair { a: a_scalar, b: _, b_offset: _ } = + layout.backend_repr + else { bug!("from_const: invalid ScalarPair layout: {:#?}", layout); }; let a = Scalar::from_pointer(Pointer::new(alloc_id.into(), Size::ZERO), &bx.tcx()); @@ -222,12 +224,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); OperandRef { val: OperandValue::Immediate(val), layout, move_annotation: None } } - BackendRepr::ScalarPair( - a @ abi::Scalar::Initialized { .. }, - b @ abi::Scalar::Initialized { .. }, - ) => { + BackendRepr::ScalarPair { + a: a @ abi::Scalar::Initialized { .. }, + b: b @ abi::Scalar::Initialized { .. }, + b_offset, + } => { let (a_size, b_size) = (a.size(bx), b.size(bx)); - let b_offset = (offset + a_size).align_to(b.default_align(bx).abi); assert!(b_offset.bytes() > 0); let a_val = read_scalar( offset, @@ -345,7 +347,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { llval: V, layout: TyAndLayout<'tcx>, ) -> Self { - let val = if let BackendRepr::ScalarPair(..) = layout.backend_repr { + let val = if let BackendRepr::ScalarPair { .. } = layout.backend_repr { debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", llval, layout); // Deconstruct the immediate aggregate. @@ -383,12 +385,15 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } else { let (in_scalar, imm) = match (self.val, self.layout.backend_repr) { // Extract a scalar component from a pair. - (OperandValue::Pair(a_llval, b_llval), BackendRepr::ScalarPair(a, b)) => { + ( + OperandValue::Pair(a_llval, b_llval), + BackendRepr::ScalarPair { a, b, b_offset }, + ) => { if offset.bytes() == 0 { assert_eq!(field.size, a.size(bx.cx())); (Some(a), a_llval) } else { - assert_eq!(offset, a.size(bx.cx()).align_to(b.default_align(bx.cx()).abi)); + assert_eq!(offset, b_offset); assert_eq!(field.size, b.size(bx.cx())); (Some(b), b_llval) } @@ -419,7 +424,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { imm } } - BackendRepr::ScalarPair(_, _) + BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } | BackendRepr::Memory { .. } | BackendRepr::SimdScalableVector { .. } => bug!(), }) @@ -705,7 +710,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { let val = match layout.backend_repr { BackendRepr::Memory { .. } if layout.is_zst() => OperandValueBuilder::ZeroSized, BackendRepr::Scalar(s) => OperandValueBuilder::Immediate(Either::Right(s)), - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair { a, b, b_offset: _ } => { OperandValueBuilder::Pair(Either::Right(a), Either::Right(b)) } BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { @@ -733,7 +738,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { (OperandValue::Immediate(v), BackendRepr::SimdVector { .. }) => { OperandValueBuilder::Vector(Either::Left(v)) } - (OperandValue::Pair(a, b), BackendRepr::ScalarPair(_, _)) => { + (OperandValue::Pair(a, b), BackendRepr::ScalarPair { a: _, b: _, b_offset: _ }) => { OperandValueBuilder::Pair(Either::Left(a), Either::Left(b)) } (_, BackendRepr::Memory { .. }) => { @@ -810,17 +815,18 @@ impl<'a, 'tcx, V: CodegenObject> OperandRefBuilder<'tcx, V> { bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}") } }, - (OperandValue::Pair(a, b), BackendRepr::ScalarPair(from_sa, from_sb)) => { - match &mut self.val { - OperandValueBuilder::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => { - update(fst, a, from_sa); - update(snd, b, from_sb); - } - _ => bug!( - "Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}" - ), + ( + OperandValue::Pair(a, b), + BackendRepr::ScalarPair { a: from_sa, b: from_sb, b_offset: _ }, + ) => match &mut self.val { + OperandValueBuilder::Pair(fst @ Either::Right(_), snd @ Either::Right(_)) => { + update(fst, a, from_sa); + update(snd, b, from_sb); } - } + _ => { + bug!("Tried to insert {field_operand:?} into {variant:?}.{field:?} of {self:?}") + } + }, (OperandValue::Ref(place), BackendRepr::Memory { .. }) => match &mut self.val { OperandValueBuilder::Vector(val @ Either::Right(())) => { let ibty = bx.cx().immediate_backend_type(self.layout); @@ -1008,10 +1014,10 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { bx.store_with_flags(val, dest.val.llval, dest.val.align, flags); } OperandValue::Pair(a, b) => { - let BackendRepr::ScalarPair(a_scalar, b_scalar) = dest.layout.backend_repr else { + let BackendRepr::ScalarPair { a: _, b: _, b_offset } = dest.layout.backend_repr + else { bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout); }; - let b_offset = a_scalar.size(bx).align_to(b_scalar.default_align(bx).abi); let val = bx.from_immediate(a); let align = dest.val.align; diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 49f03fe1376e2..f417dfba746f1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // semantics regarding when assignment operators allow overlap of LHS and RHS. if matches!( cg_operand.layout.backend_repr, - BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..), + BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }, ) { debug_assert!(!matches!(cg_operand.val, OperandValue::Ref(..))); } @@ -323,9 +323,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } ( OperandValue::Pair(imm_a, imm_b), - abi::BackendRepr::ScalarPair(in_a, in_b), - abi::BackendRepr::ScalarPair(out_a, out_b), - ) if in_a.size(cx) == out_a.size(cx) && in_b.size(cx) == out_b.size(cx) => { + abi::BackendRepr::ScalarPair { a: in_a, b: in_b, b_offset: in_offset }, + abi::BackendRepr::ScalarPair { a: out_a, b: out_b, b_offset: out_offset }, + ) if in_a.size(cx) == out_a.size(cx) + && in_b.size(cx) == out_b.size(cx) + && in_offset == out_offset => + { OperandValue::Pair( transmute_scalar(bx, imm_a, in_a, out_a), transmute_scalar(bx, imm_b, in_b, out_b), diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 1b6c948657e0d..7295df0ab2210 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -136,7 +136,7 @@ fn const_to_valtree_inner<'tcx>( let val = ecx.read_immediate(place).report_err()?; // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. - if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair { .. }) { Err(ValTreeCreationError::NonSupportedType(ty)) } else { let val = val.to_scalar(); diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 1f67b896fc8ec..0c1e171c0edc9 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -84,7 +84,7 @@ impl Immediate { pub fn to_scalar(self) -> Scalar { match self { Immediate::Scalar(val) => val, - Immediate::ScalarPair(..) => bug!("Got a scalar pair where a scalar was expected"), + Immediate::ScalarPair { .. } => bug!("Got a scalar pair where a scalar was expected"), Immediate::Uninit => bug!("Got uninit where a scalar was expected"), } } @@ -129,7 +129,10 @@ impl Immediate { ); } } - (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => { + ( + Immediate::ScalarPair(a_val, b_val), + BackendRepr::ScalarPair { a, b, b_offset: _ }, + ) => { assert_eq!( a_val.size(), a.size(cx), @@ -263,7 +266,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { #[inline] pub fn from_scalar_pair(a: Scalar, b: Scalar, layout: TyAndLayout<'tcx>) -> Self { debug_assert!( - matches!(layout.backend_repr, BackendRepr::ScalarPair(..)), + matches!(layout.backend_repr, BackendRepr::ScalarPair { .. }), "`ImmTy::from_scalar_pair` on non-scalar-pair layout" ); let imm = Immediate::ScalarPair(a, b); @@ -276,7 +279,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { debug_assert!( match (imm, layout.backend_repr) { (Immediate::Scalar(..), BackendRepr::Scalar(..)) => true, - (Immediate::ScalarPair(..), BackendRepr::ScalarPair(..)) => true, + (Immediate::ScalarPair { .. }, BackendRepr::ScalarPair { .. }) => true, (Immediate::Uninit, _) if layout.is_sized() => true, _ => false, }, @@ -415,14 +418,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { **self } // extract fields from types with `ScalarPair` ABI - (Immediate::ScalarPair(a_val, b_val), BackendRepr::ScalarPair(a, b)) => { - Immediate::from(if offset.bytes() == 0 { - a_val - } else { - assert_eq!(offset, a.size(cx).align_to(b.default_align(cx).abi)); - b_val - }) - } + ( + Immediate::ScalarPair(a_val, b_val), + BackendRepr::ScalarPair { a: _, b: _, b_offset }, + ) => Immediate::from(if offset.bytes() == 0 { + a_val + } else { + assert_eq!(offset, b_offset); + b_val + }), // everything else is a bug _ => bug!( "invalid field access on immediate {} at offset {}, original layout {:#?}", @@ -606,15 +610,15 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; Some(ImmTy::from_scalar(scalar, mplace.layout)) } - BackendRepr::ScalarPair( - abi::Scalar::Initialized { value: a, .. }, - abi::Scalar::Initialized { value: b, .. }, - ) => { + BackendRepr::ScalarPair { + a: abi::Scalar::Initialized { value: a, .. }, + b: abi::Scalar::Initialized { value: b, .. }, + b_offset, + } => { // We checked `ptr_align` above, so all fields will have the alignment they need. // We would anyway check against `ptr_align.restrict_for_offset(b_offset)`, // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let (a_size, b_size) = (a.size(self), b.size(self)); - let b_offset = a_size.align_to(b.default_align(self).abi); assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields let a_val = alloc.read_scalar( alloc_range(Size::ZERO, a_size), @@ -668,10 +672,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !matches!( op.layout().backend_repr, BackendRepr::Scalar(abi::Scalar::Initialized { .. }) - | BackendRepr::ScalarPair( - abi::Scalar::Initialized { .. }, - abi::Scalar::Initialized { .. } - ) + | BackendRepr::ScalarPair { + a: abi::Scalar::Initialized { .. }, + b: abi::Scalar::Initialized { .. }, + b_offset: _, + } ) { span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty); } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index d6d73b2d8da81..0c786c5831676 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -713,7 +713,6 @@ where // to handle padding properly, which is only correct if we never look at this data with the // wrong type. - let tcx = *self.tcx; let will_later_validate = M::enforce_validity(self, layout); let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { // zero-sized access @@ -725,7 +724,7 @@ where alloc.write_scalar(alloc_range(Size::ZERO, scalar.size()), scalar)?; } Immediate::ScalarPair(a_val, b_val) => { - let BackendRepr::ScalarPair(_a, b) = layout.backend_repr else { + let BackendRepr::ScalarPair { a: _, b: _, b_offset } = layout.backend_repr else { span_bug!( self.cur_span(), "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", @@ -733,7 +732,7 @@ where ) }; let a_size = a_val.size(); - let b_offset = a_size.align_to(b.default_align(&tcx).abi); + let b_size = b_val.size(); assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, @@ -744,12 +743,12 @@ where // destination now to ensure that no stray pointer fragments are being // preserved (see ). // We can skip this if there is no padding (e.g. for wide pointers). - if !will_later_validate && a_size + b_val.size() != layout.size { + if !will_later_validate && a_size + b_size != layout.size { alloc.write_uninit_full(); } alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; - alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?; + alloc.write_scalar(alloc_range(b_offset, b_size), b_val)?; } Immediate::Uninit => alloc.write_uninit_full(), } @@ -902,17 +901,19 @@ where // padding in the target independent of layout choices. let src_has_padding = match src.layout().backend_repr { BackendRepr::Scalar(_) => false, - BackendRepr::ScalarPair(left, right) + BackendRepr::ScalarPair { a: left, b: right, b_offset: _ } if matches!(src.layout().ty.kind(), ty::Ref(..) | ty::RawPtr(..)) => { // Wide pointers never have padding, so we can avoid calling `size()`. debug_assert_eq!(left.size(self) + right.size(self), src.layout().size); false } - BackendRepr::ScalarPair(left, right) => { + BackendRepr::ScalarPair { a: left, b: right, b_offset: _ } => { let left_size = left.size(self); let right_size = right.size(self); // We have padding if the sizes don't add up to the total. + // (Why don't we need to check the offset? The scalars don't overlap so no padding + // implies `b_offset == left_size`, which would be superfluous to check explicitly.) left_size + right_size != src.layout().size } // Everything else can only exist in memory anyway, so it doesn't matter. diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 262ef6ba74ed0..2d412e1124e5a 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1397,7 +1397,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.path, Uninit { expected } ), - Immediate::Scalar(..) | Immediate::ScalarPair(..) => + Immediate::Scalar(..) | Immediate::ScalarPair { .. } => bug!("arrays/slices can never have Scalar/ScalarPair layout"), } }; @@ -1486,7 +1486,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(scalar, scalar_layout)?; } } - BackendRepr::ScalarPair(a_layout, b_layout) => { + BackendRepr::ScalarPair { a: a_layout, b: b_layout, b_offset: _ } => { // We can only proceed if *both* scalars need to be initialized. // FIXME: find a way to also check ScalarPair when one side can be uninit but // the other must be init. @@ -1545,7 +1545,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, .expect("the above checks should have fully handled this situation"); } } - BackendRepr::ScalarPair(a_layout, b_layout) => { + BackendRepr::ScalarPair { a: a_layout, b: b_layout, b_offset: _ } => { // We can only proceed if *both* scalars need to be initialized. // FIXME: find a way to also check ScalarPair when one side can be uninit but // the other must be init. diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 00835a3cc990a..64688f56fe763 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -121,7 +121,7 @@ fn check_validity_requirement_lax<'tcx>( let valid = !this.is_uninhabited() // definitely UB if uninhabited && match this.backend_repr { BackendRepr::Scalar(s) => scalar_allows_raw_init(s), - BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => { scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2) } BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s), diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 8bded7662f423..641c50b620ff5 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -696,11 +696,15 @@ impl TtParser { } fn ambiguity_error<'matcher, T: Tracker<'matcher>>( - &self, + &mut self, parser: &Parser<'_>, matcher: &'matcher [MatcherLoc], track: &mut T, ) -> NamedParseResult { + // Use a reasonable and deterministic ordering for data in the error message. + self.bb_mps.sort_unstable_by_key(|mp| mp.idx); + self.next_mps.sort_unstable_by_key(|mp| mp.idx); + let bb_locs = self.bb_mps.iter().map(|mp| &matcher[mp.idx]); let next_locs = self.next_mps.iter().map(|mp| &matcher[mp.idx]); track.ambiguity(parser, bb_locs, next_locs); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 383023aa24457..ea0f8f22ab187 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1325,7 +1325,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { // FIXME(generic_const_exprs): Revisit this before stabilization. // See also `tests/ui/const-generics/generic_const_exprs/type-alias-bounds.rs`. let ty = cx.tcx.type_of(item.owner_id).instantiate_identity().skip_norm_wip(); - if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) + if ty.has_type_flags(ty::TypeFlags::HAS_CONST_ALIAS) && cx.tcx.features().generic_const_exprs() { return; @@ -2438,7 +2438,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // Check if this ADT has a constrained layout (like `NonNull` and friends). if let Ok(layout) = cx.tcx.layout_of(cx.typing_env().as_query_input(ty)) { - if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair { a: scalar, .. } = &layout.backend_repr { let range = scalar.valid_range(cx); diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 43ed22927da56..f0692817fb60b 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -44,7 +44,7 @@ impl<'tcx> TyCtxt<'tcx> { self.tcx } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + if ty.has_type_flags(ty::TypeFlags::HAS_CONST_ALIAS) { ty.super_fold_with(self) } else { ty diff --git a/compiler/rustc_middle/src/ty/offload_meta.rs b/compiler/rustc_middle/src/ty/offload_meta.rs index 9d0fcc50ef224..a58e517e05f61 100644 --- a/compiler/rustc_middle/src/ty/offload_meta.rs +++ b/compiler/rustc_middle/src/ty/offload_meta.rs @@ -76,7 +76,7 @@ impl OffloadMetadata { Ty<'tcx>: TyAbiInterface<'tcx, C>, { match arg_abi.layout.backend_repr { - BackendRepr::ScalarPair(_, _) => (0..2) + BackendRepr::ScalarPair { a: _, b: _, b_offset: _ } => (0..2) .map(|i| { let ty = arg_abi.layout.field(cx, i).ty; (OffloadMetadata::from_ty(tcx, ty), ty) diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index c7d18bd1cc92f..7e128ad72454e 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -647,7 +647,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. Some(val) => { - if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair { .. }) { let (val, overflow) = val.to_scalar_pair(); (FlatSet::Elem(val), FlatSet::Elem(overflow)) } else { @@ -814,7 +814,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { return Some(Const::Val(ConstValue::Scalar(value), ty)); } - if matches!(layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) { + if matches!(layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }) { let alloc_id = ecx .intern_with_temp_alloc(layout, |ecx, dest| { try_write_constant(ecx, dest, place, ty, state, map) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2db4502ecc6b6..f00dd3fde5aac 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -608,7 +608,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { let fields = fields.iter().map(|&f| self.eval_to_const(f)).collect::>>()?; let variant = if ty.ty.is_enum() { Some(variant) } else { None }; - let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) = ty.backend_repr + let (BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. }) = ty.backend_repr else { return None; }; @@ -639,7 +639,7 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { ImmTy::from_immediate(Immediate::Uninit, ty).into() } else if matches!( ty.backend_repr, - BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) + BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. } ) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; let field_dest = self.ecx.project_field(&dest, active_field).discard_err()?; @@ -738,11 +738,15 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { s1.size(&self.ecx) == s2.size(&self.ecx) && !matches!(s1.primitive(), Primitive::Pointer(..)) } - (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { + ( + BackendRepr::ScalarPair { a: a1, b: b1, b_offset: b1_offset }, + BackendRepr::ScalarPair { a: a2, b: b2, b_offset: b2_offset }, + ) => { a1.size(&self.ecx) == a2.size(&self.ecx) && b1.size(&self.ecx) == b2.size(&self.ecx) - // The alignment of the second component determines its offset, so that also needs to match. - && b1.default_align(&self.ecx) == b2.default_align(&self.ecx) + // The first component is always at offset zero, but the offset to the second + // component needs to match as well for us to be able to transmute. + && b1_offset == b2_offset // None of the inputs may be a pointer. && !matches!(a1.primitive(), Primitive::Pointer(..)) && !matches!(b1.primitive(), Primitive::Pointer(..)) @@ -1804,7 +1808,9 @@ impl<'body, 'a, 'tcx> VnState<'body, 'a, 'tcx> { true } } - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair { a, b, b_offset: _ } => { + // The offset is irrelevant to niches since it can only cause padding, + // which can never have a niche since it's uninitialized. !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) } BackendRepr::SimdVector { .. } @@ -1902,7 +1908,10 @@ fn op_to_prop_const<'tcx>( // But we *do* want to synthesize any size constant if it is entirely uninit because that // benefits codegen, which has special handling for them. if !op.is_immediate_uninit() - && !matches!(op.layout.backend_repr, BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..)) + && !matches!( + op.layout.backend_repr, + BackendRepr::Scalar(..) | BackendRepr::ScalarPair { .. } + ) { return None; } diff --git a/compiler/rustc_mir_transform/src/impossible_predicates.rs b/compiler/rustc_mir_transform/src/impossible_predicates.rs index cc216c39b8599..cf3e22212f95a 100644 --- a/compiler/rustc_mir_transform/src/impossible_predicates.rs +++ b/compiler/rustc_mir_transform/src/impossible_predicates.rs @@ -45,7 +45,7 @@ pub(crate) fn has_impossible_predicates(tcx: TyCtxt<'_>, def_id: DefId) -> bool // Only consider global clauses to simplify. TypeFlags::HAS_FREE_LOCAL_NAMES // Clauses that refer to alias constants as they cause cycles. - | TypeFlags::HAS_CT_PROJECTION, + | TypeFlags::HAS_CONST_ALIAS, ) }); let predicates: Vec<_> = traits::elaborate(tcx, predicates).collect(); diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index cd8dc963eb33c..e762821724231 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -563,7 +563,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?; let val = self.use_ecx(|this| this.ecx.binary_op(bin_op, &left, &right))?; - if matches!(val.layout.backend_repr, BackendRepr::ScalarPair(..)) { + if matches!(val.layout.backend_repr, BackendRepr::ScalarPair { .. }) { // FIXME `Value` should properly support pairs in `Immediate`... but currently // it does not. let (val, overflow) = val.to_pair(&self.ecx); @@ -629,7 +629,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // so bail out if the target is not one. match (value.layout.backend_repr, to.backend_repr) { (BackendRepr::Scalar(..), BackendRepr::Scalar(..)) => {} - (BackendRepr::ScalarPair(..), BackendRepr::ScalarPair(..)) => {} + (BackendRepr::ScalarPair { .. }, BackendRepr::ScalarPair { .. }) => {} _ => return None, } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 98b2ed1642582..201601d91adfa 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3424,6 +3424,7 @@ impl<'a> Parser<'a> { let (pat, colon) = this.parse_fn_param_pat_colon()?; if !colon { let mut err = this.unexpected().unwrap_err(); + let pat_span = pat.span; return if let Some(ident) = this.parameter_without_type( &mut err, pat, @@ -3432,7 +3433,9 @@ impl<'a> Parser<'a> { fn_parse_mode, ) { let guar = err.emit(); - Ok((dummy_arg(ident, guar), Trailing::No, UsePreAttrPos::No)) + let mut arg = dummy_arg(ident, guar); + arg.span = pat_span; + Ok((arg, Trailing::No, UsePreAttrPos::No)) } else { Err(err) }; diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index cde885def8a41..02674e4107c77 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -241,7 +241,11 @@ pub struct NumScalableVectors(pub(crate) u8); #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum ValueAbi { Scalar(Scalar), - ScalarPair(Scalar, Scalar), + ScalarPair { + a: Scalar, + b: Scalar, + b_offset: Size, + }, Vector { element: Scalar, count: u64, @@ -262,7 +266,7 @@ impl ValueAbi { pub fn is_unsized(&self) -> bool { match *self { ValueAbi::Scalar(_) - | ValueAbi::ScalarPair(..) + | ValueAbi::ScalarPair { .. } | ValueAbi::Vector { .. } // FIXME(rustc_scalable_vector): Scalable vectors are `Sized` while the // `sized_hierarchy` feature is not yet fully implemented. After `sized_hierarchy` is diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 7e0b04f8a7f61..bbc7435a6c596 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -271,8 +271,12 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { ) -> Self::T { match *self { rustc_abi::BackendRepr::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables, cx)), - rustc_abi::BackendRepr::ScalarPair(first, second) => { - ValueAbi::ScalarPair(first.stable(tables, cx), second.stable(tables, cx)) + rustc_abi::BackendRepr::ScalarPair { a: first, b: second, b_offset: second_offset } => { + ValueAbi::ScalarPair { + a: first.stable(tables, cx), + b: second.stable(tables, cx), + b_offset: second_offset.stable(tables, cx), + } } rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables, cx), count } diff --git a/compiler/rustc_target/src/callconv/aarch64.rs b/compiler/rustc_target/src/callconv/aarch64.rs index ce69427cbdd59..ec2c30756ddc0 100644 --- a/compiler/rustc_target/src/callconv/aarch64.rs +++ b/compiler/rustc_target/src/callconv/aarch64.rs @@ -56,7 +56,7 @@ fn softfloat_float_abi(target: &Target, arg: &mut ArgAbi<'_, Ty>) { && let Primitive::Float(f) = s.primitive() { arg.cast_to(Reg { kind: RegKind::Integer, size: f.size() }); - } else if let BackendRepr::ScalarPair(s1, s2) = arg.layout.backend_repr + } else if let BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } = arg.layout.backend_repr && (matches!(s1.primitive(), Primitive::Float(_)) || matches!(s2.primitive(), Primitive::Float(_))) { diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 6d3826abf27a8..3e9ff2b672a07 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -89,7 +89,7 @@ where return Err(CannotUseFpConv); } BackendRepr::SimdScalableVector { .. } => panic!("scalable vectors are unsupported"), - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 4bc88cc4f9705..54f4ff77627b9 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -390,17 +390,15 @@ impl<'a, Ty: fmt::Display> fmt::Debug for ArgAbi<'a, Ty> { impl<'a, Ty> ArgAbi<'a, Ty> { /// This defines the "default ABI" for that type, that is then later adjusted in `fn_abi_adjust_for_abi`. pub fn new( - cx: &impl HasDataLayout, layout: TyAndLayout<'a, Ty>, scalar_attrs: impl Fn(Scalar, Size) -> ArgAttributes, ) -> Self { let mode = match layout.backend_repr { _ if layout.is_zst() => PassMode::Ignore, BackendRepr::Scalar(scalar) => PassMode::Direct(scalar_attrs(scalar, Size::ZERO)), - BackendRepr::ScalarPair(a, b) => PassMode::Pair( - scalar_attrs(a, Size::ZERO), - scalar_attrs(b, a.size(cx).align_to(b.default_align(cx).abi)), - ), + BackendRepr::ScalarPair { a, b, b_offset } => { + PassMode::Pair(scalar_attrs(a, Size::ZERO), scalar_attrs(b, b_offset)) + } BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), BackendRepr::SimdScalableVector { .. } => PassMode::Direct(ArgAttributes::new()), @@ -877,7 +875,7 @@ where { match layout.backend_repr { BackendRepr::Scalar(scalar) => !scalar.is_uninit_valid(), - BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => { !s1.is_uninit_valid() && !s2.is_uninit_valid() // Ensure there is no padding. diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index bc81ec95c86e3..e79ce0557ce80 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -94,7 +94,7 @@ where BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => { return Err(CannotUseFpConv); } - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs index b5e5c3e2a88b3..6b19f8ebd76ce 100644 --- a/compiler/rustc_target/src/callconv/sparc64.rs +++ b/compiler/rustc_target/src/callconv/sparc64.rs @@ -67,7 +67,7 @@ fn classify<'a, Ty, C>( }, BackendRepr::SimdVector { .. } => {} BackendRepr::SimdScalableVector { .. } => {} - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 81ff1a2a45900..a80088e41cd31 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -92,7 +92,7 @@ where Ty: TyAbiInterface<'a, C> + Copy, { match layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) => false, + BackendRepr::Scalar(_) | BackendRepr::ScalarPair { .. } => false, BackendRepr::SimdVector { .. } => true, BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { @@ -211,7 +211,7 @@ where if !fn_abi.ret.is_ignore() { let has_float = match fn_abi.ret.layout.backend_repr { BackendRepr::Scalar(s) => matches!(s.primitive(), Primitive::Float(_)), - BackendRepr::ScalarPair(s1, s2) => { + BackendRepr::ScalarPair { a: s1, b: s2, b_offset: _ } => { matches!(s1.primitive(), Primitive::Float(_)) || matches!(s2.primitive(), Primitive::Float(_)) } diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index 3055d18ffa014..5ab2834807d67 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -61,7 +61,7 @@ where BackendRepr::SimdScalableVector { .. } => panic!("scalable vectors are unsupported"), - BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { let field_off = off + layout.fields.offset(i); classify(cx, layout.field(cx, i), cls, field_off)?; diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index cece9d032b53a..4aaf34e56ce4b 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -12,7 +12,7 @@ where let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| { match a.layout.backend_repr { BackendRepr::Memory { sized: false } => {} - BackendRepr::ScalarPair(..) | BackendRepr::Memory { sized: true } => { + BackendRepr::ScalarPair { .. } | BackendRepr::Memory { sized: true } => { match a.layout.size.bits() { 8 => a.cast_to(Reg::i8()), 16 => a.cast_to(Reg::i16()), diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index 2104286ec8684..bda2681605814 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -29,6 +29,11 @@ pub(crate) fn target() -> Target { crt_static_default: true, crt_static_allows_dylibs: true, main_needs_argc_argv: true, + // Use the wasm C-ABI entry name from the tool-conventions BasicCABI + // spec rather than a raw `main`, as referenced by emscripten's crt/libc. + // Required for entry paths like `-sPROXY_TO_PTHREAD`, whose + // `crt1_proxy_main` links against `__main_argc_argv`. + entry_name: "__main_argc_argv".into(), panic_strategy: PanicStrategy::Unwind, no_default_libraries: false, families: cvs!["unix", "wasm"], diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index e8371a3c0f257..ac6100747970e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -376,7 +376,7 @@ impl<'a, 'tcx> QueryNormalizer<'a, 'tcx> { // of type/const and we need to continue folding it to reveal the TAIT behind it // or further normalize nested alias consts. if res != term.to_term(tcx, ty::IsRigid::No) - && (res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) + && (res.has_type_flags(ty::TypeFlags::HAS_CONST_ALIAS) || matches!( term.kind, ty::AliasTermKind::FreeTy { .. } | ty::AliasTermKind::FreeConst { .. } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 51db1b8efde2f..8873fb13efe03 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -486,7 +486,7 @@ fn fn_abi_sanity_check<'tcx>( BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } | BackendRepr::SimdScalableVector { .. } => {} - BackendRepr::ScalarPair(..) => { + BackendRepr::ScalarPair { .. } => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } BackendRepr::Memory { sized } => { @@ -513,7 +513,7 @@ fn fn_abi_sanity_check<'tcx>( // Similar to `Direct`, we need to make sure that backends use `layout.backend_repr` // and ignore the rest of the layout. assert!( - matches!(arg.layout.backend_repr, BackendRepr::ScalarPair(..)), + matches!(arg.layout.backend_repr, BackendRepr::ScalarPair { .. }), "PassMode::Pair for type {}", arg.layout.ty ); @@ -612,7 +612,7 @@ fn fn_abi_new_uncached<'tcx>( layout }; - Ok(ArgAbi::new(cx, layout, |scalar, offset| { + Ok(ArgAbi::new(layout, |scalar, offset| { arg_attrs_for_rust_scalar(*cx, scalar, layout, offset, is_return, determined_fn_def_id) })) }; @@ -741,7 +741,7 @@ fn make_thin_self_ptr<'tcx>( Ty::new_mut_ptr(tcx, layout.ty) } else { match layout.backend_repr { - BackendRepr::ScalarPair(..) | BackendRepr::Scalar(..) => (), + BackendRepr::ScalarPair { .. } | BackendRepr::Scalar(..) => (), _ => bug!("receiver type has unsupported layout: {:?}", layout), } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index be0042f697e5d..0defe2e0ac38f 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -291,7 +291,8 @@ fn layout_of_uncached<'tcx>( } } ty::PatternKind::NotNull => { - if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = + if let BackendRepr::Scalar(scalar) + | BackendRepr::ScalarPair { a: scalar, b: _, b_offset: _ } = &mut layout.backend_repr { scalar.valid_range_mut().start = 1; diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index decf1ffb5570d..70e980490f36b 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -158,15 +158,21 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou } } } - BackendRepr::ScalarPair(scalar1, scalar2) => { + BackendRepr::ScalarPair { a: scalar1, b: scalar2, b_offset } => { // Check that the underlying pair of fields matches. let inner = skip_newtypes(cx, layout); assert!( - matches!(inner.layout.backend_repr(), BackendRepr::ScalarPair(..)), + matches!(inner.layout.backend_repr(), BackendRepr::ScalarPair { .. }), "`ScalarPair` type {} is newtype around non-`ScalarPair` type {}", layout.ty, inner.ty ); + // `a` is at memory offset zero, so to keep them from overlapping the offset + // to `b` must be at least as much as the size of `a`. + assert!( + b_offset >= scalar1.size(cx), + "`ScalarPair` scalars are overlapping in {layout:?}", + ); if matches!(inner.layout.variants(), Variants::Multiple { .. }) { // FIXME: ScalarPair for enums is enormously complicated and it is very hard // to check anything about them. @@ -234,6 +240,10 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou offset2, field2_offset, "`ScalarPair` second field at bad offset in {inner:#?}", ); + assert_eq!( + b_offset, field2_offset, + "`ScalarPair` with inconsistent b_offset in {inner:#?}", + ); assert_eq!( field2.size, size2, "`ScalarPair` second field with bad size in {inner:#?}", @@ -325,8 +335,11 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou }; let abi_coherent = match (layout.backend_repr, variant.backend_repr) { (BackendRepr::Scalar(s1), BackendRepr::Scalar(s2)) => scalar_coherent(s1, s2), - (BackendRepr::ScalarPair(a1, b1), BackendRepr::ScalarPair(a2, b2)) => { - scalar_coherent(a1, a2) && scalar_coherent(b1, b2) + ( + BackendRepr::ScalarPair { a: a1, b: b1, b_offset: b1_offset }, + BackendRepr::ScalarPair { a: a2, b: b2, b_offset: b2_offset }, + ) => { + scalar_coherent(a1, a2) && scalar_coherent(b1, b2) && b1_offset == b2_offset } (BackendRepr::Memory { .. }, _) => true, _ => false, diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 03f90215ad1aa..214a83a9b491b 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -80,7 +80,7 @@ bitflags::bitflags! { /// Does this have `Inherent`? const HAS_TY_INHERENT = 1 << 13; /// Does this have `ConstKind::Alias`? - const HAS_CT_PROJECTION = 1 << 14; + const HAS_CONST_ALIAS = 1 << 14; /// Does this have `Alias` or `ConstKind::Alias`? /// @@ -89,7 +89,7 @@ bitflags::bitflags! { | TypeFlags::HAS_TY_FREE_ALIAS.bits() | TypeFlags::HAS_TY_OPAQUE.bits() | TypeFlags::HAS_TY_INHERENT.bits() - | TypeFlags::HAS_CT_PROJECTION.bits(); + | TypeFlags::HAS_CONST_ALIAS.bits(); /// Is a type or const error reachable? const HAS_NON_REGION_ERROR = 1 << 15; @@ -476,7 +476,7 @@ impl FlagComputation { ty::ConstKind::Alias(is_rigid, alias_const) => { self.add_is_rigid(is_rigid); self.add_args(alias_const.args.as_slice()); - self.add_flags(TypeFlags::HAS_CT_PROJECTION); + self.add_flags(TypeFlags::HAS_CONST_ALIAS); } ty::ConstKind::Infer(infer) => match infer { ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH), diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 065cc128101ae..44211354f520e 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1430,6 +1430,7 @@ impl VecDeque { /// buf.truncate(1); /// assert_eq!(buf, [5]); /// ``` + #[doc(alias = "retain_front")] #[stable(feature = "deque_extras", since = "1.16.0")] pub fn truncate(&mut self, len: usize) { /// Runs the destructor for all items in the slice when it gets dropped (normally or @@ -1484,7 +1485,6 @@ impl VecDeque { /// # Examples /// /// ``` - /// # #![feature(vec_deque_truncate_front)] /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -1493,11 +1493,12 @@ impl VecDeque { /// buf.push_front(15); /// assert_eq!(buf, [15, 10, 5]); /// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..])); - /// buf.truncate_front(1); + /// buf.retain_back(1); /// assert_eq!(buf.as_slices(), (&[5][..], &[][..])); /// ``` - #[unstable(feature = "vec_deque_truncate_front", issue = "140667")] - pub fn truncate_front(&mut self, len: usize) { + #[doc(alias = "truncate_front")] + #[stable(feature = "vec_deque_truncate_front", since = "CURRENT_RUSTC_VERSION")] + pub fn retain_back(&mut self, len: usize) { /// Runs the destructor for all items in the slice when it gets dropped (normally or /// during unwinding). struct Dropper<'a, T>(&'a mut [T]); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index c3b86a635bd0f..7ca6c7b951ffc 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2629,23 +2629,49 @@ impl Vec { self.dedup_by(|a, b| key(a) == key(b)) } - /// Removes all but the first of consecutive elements in the vector satisfying a given equality - /// relation. + /// Removes all but the first of consecutive elements in the vector that are + /// "equal" according to the given predicate function. /// - /// The `same_bucket` function is passed references to two elements from the vector and - /// must determine if the elements compare equal. The elements are passed in opposite order - /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is removed. + /// The predicate `same_bucket(x, p)` is passed references to two elements. + /// If it returns `true`, the element `x` is removed from the vector. /// - /// If the vector is sorted, this removes all duplicates. + /// The element `p` occurs *before* `x` in the vector (`[.., p, .., x, ..]`), + /// so `same_bucket(x, p)` is receiving them in reversed order (unlike [`windows`]). + /// + /// If the vector is sorted, this removes all duplicates. For more complicated predicates + /// however, the order (ascending vs. descending) can matter. + /// + /// [`windows`]: slice::windows /// /// # Examples /// /// ``` /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"]; + /// vec.dedup_by(|x, p| x.eq_ignore_ascii_case(p)); + /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + /// ``` /// - /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// Both references passed to `same_bucket` are mutable. + /// This allows merging elements by mutating `p` and returning `true`: /// - /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]); + /// ``` + /// let mut ranges = vec![1..2, 2..4, 2..5, 8..9]; + /// + /// // Sort ranges by start, and if equal, by end (lexicographically) + /// // Sorting in reverse instead (`x.start.cmp(&p.start)...`) would later fail + /// ranges.sort_unstable_by(|p, x| p.start.cmp(&x.start).then(p.end.cmp(&x.end))); + /// + /// // Merge touching (`1..2` and `2..4`) and then overlapping (`1..4` and `2..5`) ranges + /// ranges.dedup_by(|x, p| { + /// if p.end >= x.start { + /// p.end = p.end.max(x.end); + /// true + /// } else { + /// false + /// } + /// }); + /// + /// assert_eq!(ranges, [1..5, 8..9]); /// ``` #[stable(feature = "dedup_by", since = "1.16.0")] pub fn dedup_by(&mut self, mut same_bucket: F) diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml index 3b522bf80a217..791b8ecbafce3 100644 --- a/library/alloctests/Cargo.toml +++ b/library/alloctests/Cargo.toml @@ -22,6 +22,10 @@ rand_xorshift = "0.4.0" name = "alloctests" path = "tests/lib.rs" +[[test]] +name = "c_str_alloc_error" +path = "tests/c_str_alloc_error.rs" + [[test]] name = "vec_deque_alloc_error" path = "tests/vec_deque_alloc_error.rs" diff --git a/library/alloctests/tests/c_str_alloc_error.rs b/library/alloctests/tests/c_str_alloc_error.rs new file mode 100644 index 0000000000000..669a783645baa --- /dev/null +++ b/library/alloctests/tests/c_str_alloc_error.rs @@ -0,0 +1,72 @@ +//! Regression test for the panic-safety fix in rust-lang/rust#155707. +//! +//! rust-lang/rust#70201 gave `::clone_into` a path that moved the +//! target `CString`'s buffer out before growing a `Vec`; if that growth's allocation +//! failed and unwound, the target was left without its nul terminator. This only +//! reproduces under Miri: in a normal build the `#[global_allocator]` below can't +//! intercept the reallocation inside `CString::clone_into` (it lives in libstd, which +//! library tests link with `-C prefer-dynamic`), so as a regular test it just checks +//! the happy path. + +// Disabled under Miri on Windows: a `#[global_allocator]` wrapping `System` trips +// Stacked Borrows there, and it affects libtest's own allocations, not just this test +// (so `#[ignore]` would not be enough). See . +#![cfg(not(all(miri, windows)))] +#![feature(alloc_error_hook)] + +use std::alloc::{GlobalAlloc, Layout, System, set_alloc_error_hook}; +use std::ffi::CString; +use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::sync::atomic::{AtomicBool, Ordering}; + +// Once armed, the first allocation of 8 bytes or more fails and disarms, so the +// reallocation inside `clone_into`'s grow path fails while the runtime's own +// smaller allocations keep succeeding. +struct OneShotFailingAlloc; + +static ARMED: AtomicBool = AtomicBool::new(false); + +unsafe impl GlobalAlloc for OneShotFailingAlloc { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + if layout.size() >= 8 && ARMED.swap(false, Ordering::SeqCst) { + return core::ptr::null_mut(); + } + unsafe { System.alloc(layout) } + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + unsafe { System.dealloc(ptr, layout) } + } + + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + if new_size >= 8 && ARMED.swap(false, Ordering::SeqCst) { + return core::ptr::null_mut(); + } + unsafe { System.realloc(ptr, layout, new_size) } + } +} + +#[global_allocator] +static ALLOC: OneShotFailingAlloc = OneShotFailingAlloc; + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn clone_into_alloc_failure_leaves_target_valid() { + set_alloc_error_hook(|_| panic!("alloc error")); + + let src = CString::new("a fairly long value").unwrap(); + let mut target = CString::new("x").unwrap(); + + ARMED.store(true, Ordering::SeqCst); + // Under Miri the failing allocator is honored, so this reallocation unwinds; in a + // normal build the allocator can't intercept it and `clone_into` just succeeds. + let res = catch_unwind(AssertUnwindSafe(|| src.as_c_str().clone_into(&mut target))); + ARMED.store(false, Ordering::SeqCst); + + if cfg!(miri) { + assert!(res.is_err(), "clone_into should have unwound on the alloc failure"); + } + // Either way `target` must still end in its nul terminator. Before the fix the Miri + // unwind left it empty (also caught as a bad write in `CString`'s destructor). + assert_eq!(target.as_bytes_with_nul().last(), Some(&0)); +} diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index f89b974cd290c..2ede9730d12dc 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -36,7 +36,6 @@ #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(string_replace_in_place)] -#![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![feature(vec_peek_mut)] diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 91843dfd00585..2e75b7b07e63f 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -1635,7 +1635,7 @@ fn truncate_leak() { #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn truncate_front_leak() { +fn retain_back_leak() { struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } ); let mut q = VecDeque::new(); @@ -1648,7 +1648,7 @@ fn truncate_front_leak() { q.push_front(D(false)); q.push_front(D(false)); - catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok(); + catch_unwind(AssertUnwindSafe(|| q.retain_back(1))).ok(); assert_eq!(DROPS.get(), 7); } @@ -1817,20 +1817,20 @@ fn test_collect_from_into_iter_keeps_allocation() { } #[test] -fn test_truncate_front() { +fn test_retain_back() { let mut v = VecDeque::with_capacity(13); v.extend(0..7); assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.truncate_front(10); + v.retain_back(10); assert_eq!(v.len(), 7); assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.truncate_front(7); + v.retain_back(7); assert_eq!(v.len(), 7); assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); - v.truncate_front(3); + v.retain_back(3); assert_eq!(v.as_slices(), ([4, 5, 6].as_slice(), [].as_slice())); assert_eq!(v.len(), 3); - v.truncate_front(0); + v.retain_back(0); assert_eq!(v.as_slices(), ([].as_slice(), [].as_slice())); assert_eq!(v.len(), 0); @@ -1841,13 +1841,13 @@ fn test_truncate_front() { v.push_front(8); v.push_front(7); assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(12); + v.retain_back(12); assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(10); + v.retain_back(10); assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(8); + v.retain_back(8); assert_eq!(v.as_slices(), ([9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); - v.truncate_front(5); + v.retain_back(5); assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice())); } @@ -1855,7 +1855,7 @@ fn test_truncate_front() { fn test_extend_from_within() { let mut v = VecDeque::with_capacity(8); v.extend(0..6); - v.truncate_front(4); + v.retain_back(4); assert_eq!(v, [2, 3, 4, 5]); v.extend_from_within(1..4); assert_eq!(v, [2, 3, 4, 5, 3, 4, 5]); @@ -1915,7 +1915,7 @@ fn test_extend_from_within_clone() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); v.extend_from_within(2..); @@ -1947,7 +1947,7 @@ fn test_extend_from_within_clone_panic() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); // panic after wrapping @@ -1963,7 +1963,7 @@ fn test_extend_from_within_clone_panic() { // nothing should have been dropped assert_eq!(drop_count.get(), 0); - v.truncate_front(2); + v.retain_back(2); assert_eq!(drop_count.get(), 4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1]); @@ -1985,7 +1985,7 @@ fn test_extend_from_within_clone_panic() { fn test_prepend_from_within() { let mut v = VecDeque::with_capacity(8); v.extend(0..6); - v.truncate_front(4); + v.retain_back(4); v.prepend_from_within(..=0); assert_eq!(v.as_slices(), ([2, 2, 3, 4, 5].as_slice(), [].as_slice())); v.prepend_from_within(2..); @@ -2007,7 +2007,7 @@ fn test_prepend_from_within_clone() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); v.prepend_from_within(..2); @@ -2034,7 +2034,7 @@ fn test_prepend_from_within_clone_panic() { panic: false, })); // remove the dummy elements - v.truncate_front(4); + v.retain_back(4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [0, 1, 2, 3]); // panic after wrapping @@ -2050,7 +2050,7 @@ fn test_prepend_from_within_clone_panic() { // nothing should have been dropped assert_eq!(drop_count.get(), 0); - v.truncate_front(2); + v.retain_back(2); assert_eq!(drop_count.get(), 4); assert_eq!(v.iter().map(|tr| tr.id).collect::>(), [2, 3]); @@ -2071,7 +2071,7 @@ fn test_prepend_from_within_clone_panic() { #[test] fn test_extend_and_prepend_from_within() { let mut v = ('0'..='9').map(String::from).collect::>(); - v.truncate_front(5); + v.retain_back(5); v.extend_from_within(4..); v.prepend_from_within(..2); assert_eq!(v.iter().map(|s| &**s).collect::(), "56567899"); @@ -2095,7 +2095,7 @@ fn test_extend_front() { let mut v = VecDeque::with_capacity(8); let cap = v.capacity(); v.extend(0..4); - v.truncate_front(2); + v.retain_back(2); v.extend_front(4..8); assert_eq!(v.as_slices(), ([7, 6].as_slice(), [5, 4, 2, 3].as_slice())); assert_eq!(v.capacity(), cap); diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3371b2cecbd79..328e9b47966c9 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -248,14 +248,26 @@ use crate::ops::ControlFlow; #[rustc_diagnostic_item = "PartialEq"] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] pub const trait PartialEq: PointeeSized { - /// Tests for `self` and `other` values to be equal, and is used by `==`. + /// Equality operator `==`. + /// + /// Implementation of the "is equal to" operator `==`: + /// tests whether its arguments are equal. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialeq_eq"] fn eq(&self, other: &Rhs) -> bool; - /// Tests for `!=`. The default implementation is almost always sufficient, - /// and should not be overridden without very good reason. + /// Inequality operator `!=`. + /// + /// Implementation of the "is not equal to" or "is different from" operator `!=`: + /// tests whether its arguments are different. + /// + /// # Default implementation + /// The default implementation of the inequality operator simply calls + /// the implementation of the equality operator and negates the result. + /// + /// This default shouldn't be overridden without good reason, + /// such as when forwarding to another PartialEq implementation. #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] @@ -1869,19 +1881,31 @@ mod impls { use crate::ops::ControlFlow::{self, Break, Continue}; use crate::panic::const_assert; - macro_rules! partial_eq_impl { + /// Implements `PartialEq` for primitive types. + /// + /// Primitive types have a compiler-defined primitive implementation of `==` and `!=`. + /// This implements the `PartialEq` trait in terms of those primitive implementations. + /// + /// NOTE: Calling this on a non-primitive type (such as `()`) + /// leads to an infinitely-looping self-recursive implementation. + macro_rules! impl_partial_eq_for_primitive { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const impl PartialEq for $t { #[inline] fn eq(&self, other: &Self) -> bool { *self == *other } + // Override the default to use the primitive implementation for `!=`. #[inline] fn ne(&self, other: &Self) -> bool { *self != *other } } )*) } + impl_partial_eq_for_primitive! { + bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 + } + #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] const impl PartialEq for () { @@ -1895,10 +1919,6 @@ mod impls { } } - partial_eq_impl! { - bool char usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f16 f32 f64 f128 - } - macro_rules! eq_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 8a374f015a958..a2d367931ea9b 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2392,7 +2392,7 @@ macro_rules! int_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `<<` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shl`] which has nicer behaviour. @@ -2429,7 +2429,7 @@ macro_rules! int_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `>>` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shr`] which has nicer behaviour. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index cfb5eb54fb6bc..b33b2b5db1a32 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2827,7 +2827,7 @@ macro_rules! uint_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `<<` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shl`] which has nicer behaviour. @@ -2871,7 +2871,7 @@ macro_rules! uint_impl { /// /// Beware that, unlike most other `wrapping_*` methods on integers, this /// does *not* give the same result as doing the shift in infinite precision - /// then truncating as needed. The behaviour matches what shift instructions + /// then truncating as needed. Instead, the behaviour of this method matches what shift instructions /// do on many processors, and is what the `>>` operator does when overflow /// checks are disabled, but numerically it's weird. Consider, instead, /// using [`Self::unbounded_shr`] which has nicer behaviour. diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 163e8bf714b1d..9e7a8d4472d81 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2082,10 +2082,7 @@ impl Option { /// assert_eq!(o2.into_flat_iter().collect::>(), Vec::<&usize>::new()); /// ``` #[unstable(feature = "option_into_flat_iter", issue = "148441")] - pub fn into_flat_iter(self) -> OptionFlatten - where - T: IntoIterator, - { + pub fn into_flat_iter(self) -> OptionFlatten { OptionFlatten { iter: self.map(IntoIterator::into_iter) } } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4b02e73a4dcc3..25889994be977 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3692,18 +3692,22 @@ impl [T] { self.partition_dedup_by(|a, b| a == b) } - /// Moves all but the first of consecutive elements to the end of the slice satisfying - /// a given equality relation. + /// Moves all but the first of consecutive elements to the end of the slice that are + /// "equal" according to the given predicate function. /// /// Returns two slices. The first contains no consecutive repeated elements. /// The second contains all the duplicates in no specified order. /// - /// The `same_bucket` function is passed references to two elements from the slice and - /// must determine if the elements compare equal. The elements are passed in opposite order - /// from their order in the slice, so if `same_bucket(a, b)` returns `true`, `a` is moved - /// at the end of the slice. + /// The predicate `same_bucket(x, p)` is passed references to two elements from + /// the slice and must determine if the elements compare equal. The element `p` occurs + /// *before* `x` in the slice (`[.., p, .., x, ..]`), so `same_bucket(x, p)` + /// is receiving them in reversed order. /// - /// If the slice is sorted, the first returned slice contains no duplicates. + /// If the slice is sorted, the first returned slice contains no duplicates. For more + /// complicated predicates however, the order (ascending vs. descending) can matter. + /// + /// Both references passed to `same_bucket` are mutable. + /// This allows merged elements in the first slice by mutating `p` and returning `true`. /// /// # Examples /// @@ -3712,7 +3716,7 @@ impl [T] { /// /// let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"]; /// - /// let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b)); + /// let (dedup, duplicates) = slice.partition_dedup_by(|x, p| x.eq_ignore_ascii_case(p)); /// /// assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]); /// assert_eq!(duplicates, ["bar", "Foo", "BAZ"]); @@ -3793,7 +3797,7 @@ impl [T] { // are less than `len`, thus are inside `self`. `prev_ptr_write` points to // one element before `ptr_write`, but `next_write` starts at 1, so // `prev_ptr_write` is never less than 0 and is inside the slice. - // This fulfils the requirements for dereferencing `ptr_read`, `prev_ptr_write` + // This fulfills the requirements for dereferencing `ptr_read`, `prev_ptr_write` // and `ptr_write`, and for using `ptr.add(next_read)`, `ptr.add(next_write - 1)` // and `prev_ptr_write.offset(1)`. // diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index c226a0dc2403f..4ed5c43616a29 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -12,7 +12,7 @@ use crate::fs; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; #[cfg(not(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx", target_os = "hermit", target_os = "trusty", @@ -104,7 +104,7 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. #[cfg(not(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "emscripten")), target_os = "hermit", target_os = "trusty", target_os = "motor" @@ -131,7 +131,11 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty"))] + #[cfg(any( + all(target_arch = "wasm32", not(target_os = "emscripten")), + target_os = "hermit", + target_os = "trusty" + ))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> io::Result { Err(io::Error::UNSUPPORTED_PLATFORM) diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs index 0385e5513ea08..19fdf8ba2fb03 100644 --- a/library/std/src/os/unix/io/mod.rs +++ b/library/std/src/os/unix/io/mod.rs @@ -214,7 +214,7 @@ fn replace_stdio_fd(this: BorrowedFd<'_>, other: OwnedFd) -> io::Result<()> { cvt(unsafe { libc::__wasilibc_fd_renumber(other.as_raw_fd(), this.as_raw_fd()) }).map(|_| ()) } not(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "emscripten")), target_os = "hermit", target_os = "trusty", target_os = "motor" diff --git a/library/std/src/sys/io/error/mod.rs b/library/std/src/sys/io/error/mod.rs index cc8cda9aec045..1b6bfea27d3b0 100644 --- a/library/std/src/sys/io/error/mod.rs +++ b/library/std/src/sys/io/error/mod.rs @@ -15,22 +15,14 @@ cfg_select! { mod solid; pub use solid::*; } - target_os = "teeos" => { - mod teeos; - pub use teeos::*; - } target_os = "uefi" => { mod uefi; pub use uefi::*; } - target_family = "unix" => { + any(target_family = "unix", target_os = "wasi", target_os = "teeos") => { mod unix; pub use unix::*; } - target_os = "wasi" => { - mod wasi; - pub use wasi::*; - } target_os = "windows" => { mod windows; pub use windows::*; diff --git a/library/std/src/sys/io/error/teeos.rs b/library/std/src/sys/io/error/teeos.rs deleted file mode 100644 index 18826ffc3894f..0000000000000 --- a/library/std/src/sys/io/error/teeos.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::io; - -pub fn errno() -> i32 { - unsafe { (*libc::__errno_location()) as i32 } -} - -#[inline] -pub fn is_interrupted(errno: i32) -> bool { - errno == libc::EINTR -} - -// Note: code below is 1:1 copied from unix/mod.rs -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { - use io::ErrorKind::*; - match errno as libc::c_int { - libc::E2BIG => ArgumentListTooLong, - libc::EADDRINUSE => AddrInUse, - libc::EADDRNOTAVAIL => AddrNotAvailable, - libc::EBUSY => ResourceBusy, - libc::ECONNABORTED => ConnectionAborted, - libc::ECONNREFUSED => ConnectionRefused, - libc::ECONNRESET => ConnectionReset, - libc::EDEADLK => Deadlock, - libc::EDQUOT => QuotaExceeded, - libc::EEXIST => AlreadyExists, - libc::EFBIG => FileTooLarge, - libc::EHOSTUNREACH => HostUnreachable, - libc::EINTR => Interrupted, - libc::EINVAL => InvalidInput, - libc::EISDIR => IsADirectory, - libc::ELOOP => FilesystemLoop, - libc::ENOENT => NotFound, - libc::ENOMEM => OutOfMemory, - libc::ENOSPC => StorageFull, - libc::ENOSYS => Unsupported, - libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => InvalidFilename, - libc::ENETDOWN => NetworkDown, - libc::ENETUNREACH => NetworkUnreachable, - libc::ENOTCONN => NotConnected, - libc::ENOTDIR => NotADirectory, - libc::ENOTEMPTY => DirectoryNotEmpty, - libc::EPIPE => BrokenPipe, - libc::EROFS => ReadOnlyFilesystem, - libc::ESPIPE => NotSeekable, - libc::ESTALE => StaleNetworkFileHandle, - libc::ETIMEDOUT => TimedOut, - libc::ETXTBSY => ExecutableFileBusy, - libc::EXDEV => CrossesDevices, - - libc::EACCES | libc::EPERM => PermissionDenied, - - // These two constants can have the same value on some systems, - // but different values on others, so we can't use a match - // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => WouldBlock, - - _ => Uncategorized, - } -} - -pub fn error_string(_errno: i32) -> String { - "error string unimplemented".to_string() -} diff --git a/library/std/src/sys/io/error/unix.rs b/library/std/src/sys/io/error/unix.rs index 85e3c09782ae2..2feeefa2530c8 100644 --- a/library/std/src/sys/io/error/unix.rs +++ b/library/std/src/sys/io/error/unix.rs @@ -1,8 +1,15 @@ -use crate::ffi::{CStr, c_char, c_int}; +use crate::ffi::c_int; +#[cfg(not(target_os = "teeos"))] +use crate::ffi::{CStr, c_char}; use crate::io; unsafe extern "C" { - #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] + #[cfg(not(any( + target_os = "dragonfly", + target_os = "vxworks", + target_os = "rtems", + target_os = "wasi" + )))] #[cfg_attr( any( target_os = "linux", @@ -10,6 +17,7 @@ unsafe extern "C" { target_os = "fuchsia", target_os = "l4re", target_os = "hurd", + target_os = "teeos", ), link_name = "__errno_location" )] @@ -37,7 +45,12 @@ unsafe extern "C" { } /// Returns the platform-specific value of errno -#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks", target_os = "rtems")))] +#[cfg(not(any( + target_os = "dragonfly", + target_os = "vxworks", + target_os = "rtems", + target_os = "wasi" +)))] #[inline] pub fn errno() -> i32 { unsafe { (*errno_location()) as i32 } @@ -45,7 +58,12 @@ pub fn errno() -> i32 { /// Sets the platform-specific value of errno // needed for readdir and syscall! -#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks"), not(target_os = "rtems")))] +#[cfg(not(any( + target_os = "dragonfly", + target_os = "vxworks", + target_os = "rtems", + target_os = "wasi", +)))] #[allow(dead_code)] // but not all target cfgs actually end up using it #[inline] pub fn set_errno(e: i32) { @@ -94,6 +112,25 @@ pub fn set_errno(e: i32) { } } +#[cfg(target_os = "wasi")] +unsafe extern "C" { + #[thread_local] + #[link_name = "errno"] + static mut libc_errno: libc::c_int; +} + +#[cfg(target_os = "wasi")] +pub fn errno() -> i32 { + unsafe { libc_errno as i32 } +} + +#[cfg(target_os = "wasi")] +pub fn set_errno(val: i32) { + unsafe { + libc_errno = val; + } +} + #[inline] pub fn is_interrupted(errno: i32) -> bool { errno == libc::EINTR @@ -153,8 +190,9 @@ pub fn decode_error_kind(errno: i32) -> io::ErrorKind { } /// Gets a detailed string description for the given error number. +#[cfg(any(target_family = "unix", target_os = "wasi"))] pub fn error_string(errno: i32) -> String { - const TMPBUF_SZ: usize = 128; + const TMPBUF_SZ: usize = if cfg!(target_os = "wasi") { 1024 } else { 128 }; unsafe extern "C" { #[cfg_attr( @@ -186,3 +224,8 @@ pub fn error_string(errno: i32) -> String { String::from_utf8_lossy(CStr::from_ptr(p).to_bytes()).into() } } + +#[cfg(target_os = "teeos")] +pub fn error_string(_errno: i32) -> String { + "error string unimplemented".to_string() +} diff --git a/library/std/src/sys/io/error/wasi.rs b/library/std/src/sys/io/error/wasi.rs deleted file mode 100644 index 3a0fa37e979bc..0000000000000 --- a/library/std/src/sys/io/error/wasi.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::ffi::CStr; -use crate::io as std_io; - -unsafe extern "C" { - #[thread_local] - #[link_name = "errno"] - static mut libc_errno: libc::c_int; -} - -pub fn errno() -> i32 { - unsafe { libc_errno as i32 } -} - -pub fn set_errno(val: i32) { - unsafe { - libc_errno = val; - } -} - -#[inline] -pub fn is_interrupted(errno: i32) -> bool { - errno == libc::EINTR -} - -pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { - use std_io::ErrorKind::*; - match errno as libc::c_int { - libc::E2BIG => ArgumentListTooLong, - libc::EADDRINUSE => AddrInUse, - libc::EADDRNOTAVAIL => AddrNotAvailable, - libc::EBUSY => ResourceBusy, - libc::ECONNABORTED => ConnectionAborted, - libc::ECONNREFUSED => ConnectionRefused, - libc::ECONNRESET => ConnectionReset, - libc::EDEADLK => Deadlock, - libc::EDQUOT => QuotaExceeded, - libc::EEXIST => AlreadyExists, - libc::EFBIG => FileTooLarge, - libc::EHOSTUNREACH => HostUnreachable, - libc::EINTR => Interrupted, - libc::EINVAL => InvalidInput, - libc::EISDIR => IsADirectory, - libc::ELOOP => FilesystemLoop, - libc::ENOENT => NotFound, - libc::ENOMEM => OutOfMemory, - libc::ENOSPC => StorageFull, - libc::ENOSYS => Unsupported, - libc::EMLINK => TooManyLinks, - libc::ENAMETOOLONG => InvalidFilename, - libc::ENETDOWN => NetworkDown, - libc::ENETUNREACH => NetworkUnreachable, - libc::ENOTCONN => NotConnected, - libc::ENOTDIR => NotADirectory, - libc::EPIPE => BrokenPipe, - libc::EROFS => ReadOnlyFilesystem, - libc::ESPIPE => NotSeekable, - libc::ESTALE => StaleNetworkFileHandle, - libc::ETIMEDOUT => TimedOut, - libc::ETXTBSY => ExecutableFileBusy, - libc::EXDEV => CrossesDevices, - libc::EINPROGRESS => InProgress, - libc::EMFILE | libc::ENFILE => TooManyOpenFiles, - libc::EOPNOTSUPP => Unsupported, - libc::EACCES | libc::EPERM => PermissionDenied, - libc::EWOULDBLOCK => WouldBlock, - - _ => Uncategorized, - } -} - -pub fn error_string(errno: i32) -> String { - let mut buf = [0 as libc::c_char; 1024]; - - let p = buf.as_mut_ptr(); - unsafe { - if libc::strerror_r(errno as libc::c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} diff --git a/library/std/src/sys/personality/gcc.rs b/library/std/src/sys/personality/gcc.rs index 019d5629d6d6e..0e20a4192b1b9 100644 --- a/library/std/src/sys/personality/gcc.rs +++ b/library/std/src/sys/personality/gcc.rs @@ -204,6 +204,35 @@ cfg_select! { } } _ => { + #[rustc_force_inline] + unsafe fn sign_lpad(context: *mut uw::_Unwind_Context, lpad: *const u8) -> *const u8 { + cfg_select! { + all(target_abi = "pauthtest", target_arch = "aarch64") => { + // DWARF register number for SP on AArch64. + const SP_REG: i32 = 31; + + unsafe { + let sp = uw::_Unwind_GetGR(context, SP_REG).addr() as u64; + let mut addr = lpad.addr(); + + // `pacib` corresponds to `ptrauth_key_process_dependent_code` in . + core::arch::asm!( + "pacib {addr}, {sp}", + addr = inout(reg) addr, + sp = in(reg) sp, + options(nostack, preserves_flags) + ); + + lpad.with_addr(addr) + } + } + _ => { + let _ = context; + lpad + } + } + } + /// Default personality routine, which is used directly on most targets /// and indirectly on Windows x86_64 and AArch64 via SEH. unsafe extern "C" fn rust_eh_personality_impl( @@ -239,7 +268,8 @@ cfg_select! { exception_object.cast(), ); uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, core::ptr::null()); - uw::_Unwind_SetIP(context, lpad); + let maybe_signed_lpad = sign_lpad(context, lpad); + uw::_Unwind_SetIP(context, maybe_signed_lpad); uw::_URC_INSTALL_CONTEXT } EHAction::Terminate => uw::_URC_FATAL_PHASE2_ERROR, diff --git a/library/std/tests/pipe_subprocess.rs b/library/std/tests/pipe_subprocess.rs index dad1ea6c57377..9643c3b7bdad8 100644 --- a/library/std/tests/pipe_subprocess.rs +++ b/library/std/tests/pipe_subprocess.rs @@ -13,10 +13,16 @@ fn main() { fn parent() { let me = env::current_exe().unwrap(); + // If a custom `runner` is set up for the current target, we'll be + // executing `./runner ./test`, not just `./test`. For such a case, + // use the same arguments for child to avoid executing `runner` + // without an actual executable. + let args = env::args(); let (rx, tx) = pipe().unwrap(); assert!( process::Command::new(me) + .args(args) .env("I_AM_THE_CHILD", "1") .stdout(tx) .status() diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs index 93f73ccad3ea4..80e712a2388a1 100644 --- a/library/std/tests/process_spawning.rs +++ b/library/std/tests/process_spawning.rs @@ -26,8 +26,16 @@ fn issue_15149() { env::join_paths(paths).unwrap() }; - let child_output = - process::Command::new("mytest").env("PATH", &path).arg("child").output().unwrap(); + // If a custom `runner` is set up for the current target, we'll be executing `./runner ./test`, + // not just `./test`. For such a case, use the same arguments for child to avoid executing + // `runner` without an actual executable. + let args = env::args(); + let child_output = process::Command::new("mytest") + .args(args) + .env("PATH", &path) + .arg("child") + .output() + .unwrap(); assert!( child_output.status.success(), diff --git a/library/stdarch/.github/workflows/main.yml b/library/stdarch/.github/workflows/main.yml index 6333b32ab8ad4..9e102a15e8ff7 100644 --- a/library/stdarch/.github/workflows/main.yml +++ b/library/stdarch/.github/workflows/main.yml @@ -285,12 +285,13 @@ jobs: include: - target: aarch64_be-unknown-linux-gnu build_std: true - - target: x86_64-unknown-linux-gnu - cc: icx - profile: dev - - target: x86_64-unknown-linux-gnu - cc: icx - profile: release + # getting the icx compiler hits network failures. + # - target: x86_64-unknown-linux-gnu + # cc: icx + # profile: dev + # - target: x86_64-unknown-linux-gnu + # cc: icx + # profile: release exclude: - target: armv7-unknown-linux-gnueabihf cc: gcc @@ -318,7 +319,7 @@ jobs: # Check that the generated files agree with the checked-in versions. check-stdarch-gen: needs: [style] - name: Check stdarch-gen-{arm, loongarch, hexagon, hexagon-scalar} output + name: Check stdarch-gen-{arm, loongarch, hexagon} output runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 @@ -342,11 +343,7 @@ jobs: run: | cargo run -p stdarch-gen-hexagon --release git diff --exit-code - - name: Check hexagon scalar - run: | - cargo run -p stdarch-gen-hexagon-scalar --release - git diff --exit-code - + # Run some tests with Miri. Most stdarch functions use platform-specific intrinsics # that Miri does not support. Also Miri is reltively slow. # diff --git a/library/stdarch/Cargo.lock b/library/stdarch/Cargo.lock index c8cfc21a5a1a1..cf6ce0d38e40c 100644 --- a/library/stdarch/Cargo.lock +++ b/library/stdarch/Cargo.lock @@ -849,13 +849,6 @@ dependencies = [ "stdarch-gen-common", ] -[[package]] -name = "stdarch-gen-hexagon-scalar" -version = "0.1.0" -dependencies = [ - "regex", -] - [[package]] name = "stdarch-gen-loongarch" version = "0.1.0" @@ -869,7 +862,6 @@ version = "0.1.0" dependencies = [ "assert-instr-macro", "cc", - "cfg-if", "rustc-demangle", "simd-test-macro", "wasmprinter", diff --git a/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile index 1b61dd0c1b87a..0ae4172f9dd37 100644 --- a/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/aarch64-unknown-linux-gnu/Dockerfile @@ -11,7 +11,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ wget -RUN wget https://mirrors.edge.kernel.org/pub/tools/llvm/files/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz +RUN wget https://ci-mirrors.rust-lang.org/llvm/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz RUN mkdir llvm RUN tar -xvf llvm.tar.xz --strip-components=1 -C llvm @@ -19,5 +19,5 @@ ENV CLANG_PATH="/llvm/bin/clang" ENV GCC_PATH=aarch64-linux-gnu-gcc ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -cpu max -L /usr/aarch64-linux-gnu" \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-aarch64 -cpu max,sve512=on -L /usr/aarch64-linux-gnu" \ OBJDUMP=aarch64-linux-gnu-objdump diff --git a/library/stdarch/ci/docker/aarch64_be-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/aarch64_be-unknown-linux-gnu/Dockerfile index 70acc2d22a418..0b7a59cc08d83 100644 --- a/library/stdarch/ci/docker/aarch64_be-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/aarch64_be-unknown-linux-gnu/Dockerfile @@ -19,7 +19,7 @@ RUN curl -L "https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/bin RUN tar -xvf "${TOOLCHAIN}.tar.xz" RUN mkdir /toolchains && mv "./${TOOLCHAIN}" /toolchains -RUN wget https://mirrors.edge.kernel.org/pub/tools/llvm/files/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz +RUN wget https://ci-mirrors.rust-lang.org/llvm/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz RUN mkdir llvm RUN tar -xvf llvm.tar.xz --strip-components=1 -C llvm diff --git a/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile b/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile index 3c8a1b5add27f..f4240be7bb47b 100644 --- a/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile +++ b/library/stdarch/ci/docker/armv7-unknown-linux-gnueabihf/Dockerfile @@ -10,7 +10,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ file \ wget -RUN wget https://mirrors.edge.kernel.org/pub/tools/llvm/files/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz +RUN wget https://ci-mirrors.rust-lang.org/llvm/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz RUN mkdir llvm RUN tar -xvf llvm.tar.xz --strip-components=1 -C llvm diff --git a/library/stdarch/ci/docker/x86_64-unknown-linux-gnu/Dockerfile b/library/stdarch/ci/docker/x86_64-unknown-linux-gnu/Dockerfile index efbb2b0853371..1ac46dc407395 100644 --- a/library/stdarch/ci/docker/x86_64-unknown-linux-gnu/Dockerfile +++ b/library/stdarch/ci/docker/x86_64-unknown-linux-gnu/Dockerfile @@ -13,7 +13,7 @@ RUN wget http://ci-mirrors.rust-lang.org/sde-external-10.8.0-2026-03-15-lin.tar. RUN mkdir intel-sde RUN tar -xJf sde.tar.xz --strip-components=1 -C intel-sde -RUN wget https://mirrors.edge.kernel.org/pub/tools/llvm/files/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz +RUN wget https://ci-mirrors.rust-lang.org/llvm/llvm-22.1.4-x86_64.tar.gz -O llvm.tar.xz RUN mkdir llvm RUN tar -xvf llvm.tar.xz --strip-components=1 -C llvm diff --git a/library/stdarch/ci/intrinsic-test.sh b/library/stdarch/ci/intrinsic-test.sh index 8de7a4cfa5221..3966aa88d8f41 100755 --- a/library/stdarch/ci/intrinsic-test.sh +++ b/library/stdarch/ci/intrinsic-test.sh @@ -45,21 +45,25 @@ case ${TARGET} in aarch64_be*) export CFLAGS="-I${AARCH64_BE_TOOLCHAIN}/aarch64_be-none-linux-gnu/libc/usr/include --sysroot={AARCH64_BE_TOOLCHAIN}/aarch64_be-none-linux-gnu/libc -Wno-nonportable-vector-initialization" ARCH=aarch64_be + RUNTIME_RUSTFLAGS= ;; aarch64*) export CFLAGS="-I/usr/aarch64-linux-gnu/include/" ARCH=aarch64 + RUNTIME_RUSTFLAGS=-Ctarget-feature=+sve,+sve2 ;; armv7*) export CFLAGS="-I/usr/arm-linux-gnueabihf/include/" ARCH=arm + RUNTIME_RUSTFLAGS= ;; x86_64*) export CFLAGS="-I/usr/include/x86_64-linux-gnu/" ARCH=x86 + RUNTIME_RUSTFLAGS= ;; *) ;; @@ -86,5 +90,5 @@ case "${TARGET}" in ;; esac -cargo test --manifest-path=rust_programs/Cargo.toml --target "${TARGET}" --profile "${PROFILE}" \ - --tests "$@" +RUSTFLAGS="${RUNTIME_RUSTFLAGS}" cargo test --manifest-path=rust_programs/Cargo.toml \ + --target "${TARGET}" --profile "${PROFILE}" --tests --no-fail-fast "$@" diff --git a/library/stdarch/crates/core_arch/src/aarch64/sve/generated.rs b/library/stdarch/crates/core_arch/src/aarch64/sve/generated.rs index ac3070918a025..4e5547b1d083e 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/sve/generated.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/sve/generated.rs @@ -42211,19 +42211,6 @@ pub fn svtmad_f64(op1: svfloat64_t, op2: svfloat64_t) -> svfloa unsafe { _svtmad_f64(op1, op2, IMM3) } } #[doc = "Interleave even elements from two inputs"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1_b8)"] -#[inline] -#[target_feature(enable = "sve")] -#[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] -#[cfg_attr(test, assert_instr(trn1))] -pub fn svtrn1_b8(op1: svbool_t, op2: svbool_t) -> svbool_t { - unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.nxv16i1")] - fn _svtrn1_b8(op1: svbool_t, op2: svbool_t) -> svbool_t; - } - unsafe { _svtrn1_b8(op1, op2) } -} -#[doc = "Interleave even elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1_b16)"] #[inline] #[target_feature(enable = "sve")] @@ -42231,10 +42218,10 @@ pub fn svtrn1_b8(op1: svbool_t, op2: svbool_t) -> svbool_t { #[cfg_attr(test, assert_instr(trn1))] pub fn svtrn1_b16(op1: svbool_t, op2: svbool_t) -> svbool_t { unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.nxv8i1")] - fn _svtrn1_b16(op1: svbool8_t, op2: svbool8_t) -> svbool8_t; + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.b16")] + fn _svtrn1_b16(op1: svbool_t, op2: svbool_t) -> svbool_t; } - unsafe { _svtrn1_b16(op1.sve_into(), op2.sve_into()).sve_into() } + unsafe { _svtrn1_b16(op1.sve_into(), op2.sve_into()) } } #[doc = "Interleave even elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1_b32)"] @@ -42244,10 +42231,10 @@ pub fn svtrn1_b16(op1: svbool_t, op2: svbool_t) -> svbool_t { #[cfg_attr(test, assert_instr(trn1))] pub fn svtrn1_b32(op1: svbool_t, op2: svbool_t) -> svbool_t { unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.nxv4i1")] - fn _svtrn1_b32(op1: svbool4_t, op2: svbool4_t) -> svbool4_t; + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.b32")] + fn _svtrn1_b32(op1: svbool_t, op2: svbool_t) -> svbool_t; } - unsafe { _svtrn1_b32(op1.sve_into(), op2.sve_into()).sve_into() } + unsafe { _svtrn1_b32(op1.sve_into(), op2.sve_into()) } } #[doc = "Interleave even elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1_b64)"] @@ -42257,10 +42244,10 @@ pub fn svtrn1_b32(op1: svbool_t, op2: svbool_t) -> svbool_t { #[cfg_attr(test, assert_instr(trn1))] pub fn svtrn1_b64(op1: svbool_t, op2: svbool_t) -> svbool_t { unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.nxv2i1")] - fn _svtrn1_b64(op1: svbool2_t, op2: svbool2_t) -> svbool2_t; + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.b64")] + fn _svtrn1_b64(op1: svbool_t, op2: svbool_t) -> svbool_t; } - unsafe { _svtrn1_b64(op1.sve_into(), op2.sve_into()).sve_into() } + unsafe { _svtrn1_b64(op1.sve_into(), op2.sve_into()) } } #[doc = "Interleave even elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1[_f32])"] @@ -42376,6 +42363,19 @@ pub fn svtrn1_u32(op1: svuint32_t, op2: svuint32_t) -> svuint32_t { pub fn svtrn1_u64(op1: svuint64_t, op2: svuint64_t) -> svuint64_t { unsafe { svtrn1_s64(op1.as_signed(), op2.as_signed()).as_unsigned() } } +#[doc = "Interleave even elements from two inputs"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1[_b8])"] +#[inline] +#[target_feature(enable = "sve")] +#[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] +#[cfg_attr(test, assert_instr(trn1))] +pub fn svtrn1_b8(op1: svbool_t, op2: svbool_t) -> svbool_t { + unsafe extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn1.nxv16i1")] + fn _svtrn1_b8(op1: svbool_t, op2: svbool_t) -> svbool_t; + } + unsafe { _svtrn1_b8(op1, op2) } +} #[doc = "Interleave even quadwords from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn1q[_f32])"] #[inline] @@ -42491,19 +42491,6 @@ pub fn svtrn1q_u64(op1: svuint64_t, op2: svuint64_t) -> svuint64_t { unsafe { svtrn1q_s64(op1.as_signed(), op2.as_signed()).as_unsigned() } } #[doc = "Interleave odd elements from two inputs"] -#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2_b8)"] -#[inline] -#[target_feature(enable = "sve")] -#[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] -#[cfg_attr(test, assert_instr(trn2))] -pub fn svtrn2_b8(op1: svbool_t, op2: svbool_t) -> svbool_t { - unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.nxv16i1")] - fn _svtrn2_b8(op1: svbool_t, op2: svbool_t) -> svbool_t; - } - unsafe { _svtrn2_b8(op1, op2) } -} -#[doc = "Interleave odd elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2_b16)"] #[inline] #[target_feature(enable = "sve")] @@ -42511,10 +42498,10 @@ pub fn svtrn2_b8(op1: svbool_t, op2: svbool_t) -> svbool_t { #[cfg_attr(test, assert_instr(trn2))] pub fn svtrn2_b16(op1: svbool_t, op2: svbool_t) -> svbool_t { unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.nxv8i1")] - fn _svtrn2_b16(op1: svbool8_t, op2: svbool8_t) -> svbool8_t; + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.b16")] + fn _svtrn2_b16(op1: svbool_t, op2: svbool_t) -> svbool_t; } - unsafe { _svtrn2_b16(op1.sve_into(), op2.sve_into()).sve_into() } + unsafe { _svtrn2_b16(op1.sve_into(), op2.sve_into()) } } #[doc = "Interleave odd elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2_b32)"] @@ -42524,10 +42511,10 @@ pub fn svtrn2_b16(op1: svbool_t, op2: svbool_t) -> svbool_t { #[cfg_attr(test, assert_instr(trn2))] pub fn svtrn2_b32(op1: svbool_t, op2: svbool_t) -> svbool_t { unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.nxv4i1")] - fn _svtrn2_b32(op1: svbool4_t, op2: svbool4_t) -> svbool4_t; + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.b32")] + fn _svtrn2_b32(op1: svbool_t, op2: svbool_t) -> svbool_t; } - unsafe { _svtrn2_b32(op1.sve_into(), op2.sve_into()).sve_into() } + unsafe { _svtrn2_b32(op1.sve_into(), op2.sve_into()) } } #[doc = "Interleave odd elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2_b64)"] @@ -42537,10 +42524,10 @@ pub fn svtrn2_b32(op1: svbool_t, op2: svbool_t) -> svbool_t { #[cfg_attr(test, assert_instr(trn2))] pub fn svtrn2_b64(op1: svbool_t, op2: svbool_t) -> svbool_t { unsafe extern "unadjusted" { - #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.nxv2i1")] - fn _svtrn2_b64(op1: svbool2_t, op2: svbool2_t) -> svbool2_t; + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.b64")] + fn _svtrn2_b64(op1: svbool_t, op2: svbool_t) -> svbool_t; } - unsafe { _svtrn2_b64(op1.sve_into(), op2.sve_into()).sve_into() } + unsafe { _svtrn2_b64(op1.sve_into(), op2.sve_into()) } } #[doc = "Interleave odd elements from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2[_f32])"] @@ -42656,6 +42643,19 @@ pub fn svtrn2_u32(op1: svuint32_t, op2: svuint32_t) -> svuint32_t { pub fn svtrn2_u64(op1: svuint64_t, op2: svuint64_t) -> svuint64_t { unsafe { svtrn2_s64(op1.as_signed(), op2.as_signed()).as_unsigned() } } +#[doc = "Interleave odd elements from two inputs"] +#[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2[_b8])"] +#[inline] +#[target_feature(enable = "sve")] +#[unstable(feature = "stdarch_aarch64_sve", issue = "145052")] +#[cfg_attr(test, assert_instr(trn2))] +pub fn svtrn2_b8(op1: svbool_t, op2: svbool_t) -> svbool_t { + unsafe extern "unadjusted" { + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.sve.trn2.nxv16i1")] + fn _svtrn2_b8(op1: svbool_t, op2: svbool_t) -> svbool_t; + } + unsafe { _svtrn2_b8(op1, op2) } +} #[doc = "Interleave odd quadwords from two inputs"] #[doc = "[Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/svtrn2q[_f32])"] #[inline] diff --git a/library/stdarch/crates/core_arch/src/hexagon/scalar.rs b/library/stdarch/crates/core_arch/src/hexagon/scalar.rs index 477414de74b85..a42c5c5e10f30 100644 --- a/library/stdarch/crates/core_arch/src/hexagon/scalar.rs +++ b/library/stdarch/crates/core_arch/src/hexagon/scalar.rs @@ -1,3 +1,4 @@ +// This code is automatically generated. DO NOT MODIFY. //! Hexagon scalar intrinsics //! //! This module provides intrinsics for scalar (non-HVX) Hexagon DSP operations, diff --git a/library/stdarch/crates/core_arch/src/loongarch64/lasx/generated.rs b/library/stdarch/crates/core_arch/src/loongarch64/lasx/generated.rs index 6a6a3ae924d85..311479750601a 100644 --- a/library/stdarch/crates/core_arch/src/loongarch64/lasx/generated.rs +++ b/library/stdarch/crates/core_arch/src/loongarch64/lasx/generated.rs @@ -199,10 +199,6 @@ unsafe extern "unadjusted" { fn __lasx_xvfclass_s(a: __v8f32) -> __v8i32; #[link_name = "llvm.loongarch.lasx.xvfclass.d"] fn __lasx_xvfclass_d(a: __v4f64) -> __v4i64; - #[link_name = "llvm.loongarch.lasx.xvfrecip.s"] - fn __lasx_xvfrecip_s(a: __v8f32) -> __v8f32; - #[link_name = "llvm.loongarch.lasx.xvfrecip.d"] - fn __lasx_xvfrecip_d(a: __v4f64) -> __v4f64; #[link_name = "llvm.loongarch.lasx.xvfrecipe.s"] fn __lasx_xvfrecipe_s(a: __v8f32) -> __v8f32; #[link_name = "llvm.loongarch.lasx.xvfrecipe.d"] @@ -215,10 +211,6 @@ unsafe extern "unadjusted" { fn __lasx_xvfrint_s(a: __v8f32) -> __v8f32; #[link_name = "llvm.loongarch.lasx.xvfrint.d"] fn __lasx_xvfrint_d(a: __v4f64) -> __v4f64; - #[link_name = "llvm.loongarch.lasx.xvfrsqrt.s"] - fn __lasx_xvfrsqrt_s(a: __v8f32) -> __v8f32; - #[link_name = "llvm.loongarch.lasx.xvfrsqrt.d"] - fn __lasx_xvfrsqrt_d(a: __v4f64) -> __v4f64; #[link_name = "llvm.loongarch.lasx.xvflogb.s"] fn __lasx_xvflogb_s(a: __v8f32) -> __v8f32; #[link_name = "llvm.loongarch.lasx.xvflogb.d"] @@ -265,22 +257,6 @@ unsafe extern "unadjusted" { fn __lasx_xvreplve_d(a: __v4i64, b: i32) -> __v4i64; #[link_name = "llvm.loongarch.lasx.xvpermi.w"] fn __lasx_xvpermi_w(a: __v8i32, b: __v8i32, c: u32) -> __v8i32; - #[link_name = "llvm.loongarch.lasx.xvmuh.b"] - fn __lasx_xvmuh_b(a: __v32i8, b: __v32i8) -> __v32i8; - #[link_name = "llvm.loongarch.lasx.xvmuh.h"] - fn __lasx_xvmuh_h(a: __v16i16, b: __v16i16) -> __v16i16; - #[link_name = "llvm.loongarch.lasx.xvmuh.w"] - fn __lasx_xvmuh_w(a: __v8i32, b: __v8i32) -> __v8i32; - #[link_name = "llvm.loongarch.lasx.xvmuh.d"] - fn __lasx_xvmuh_d(a: __v4i64, b: __v4i64) -> __v4i64; - #[link_name = "llvm.loongarch.lasx.xvmuh.bu"] - fn __lasx_xvmuh_bu(a: __v32u8, b: __v32u8) -> __v32u8; - #[link_name = "llvm.loongarch.lasx.xvmuh.hu"] - fn __lasx_xvmuh_hu(a: __v16u16, b: __v16u16) -> __v16u16; - #[link_name = "llvm.loongarch.lasx.xvmuh.wu"] - fn __lasx_xvmuh_wu(a: __v8u32, b: __v8u32) -> __v8u32; - #[link_name = "llvm.loongarch.lasx.xvmuh.du"] - fn __lasx_xvmuh_du(a: __v4u64, b: __v4u64) -> __v4u64; #[link_name = "llvm.loongarch.lasx.xvsllwil.h.b"] fn __lasx_xvsllwil_h_b(a: __v32i8, b: u32) -> __v16i16; #[link_name = "llvm.loongarch.lasx.xvsllwil.w.h"] @@ -443,22 +419,6 @@ unsafe extern "unadjusted" { fn __lasx_xvfrintrne_s(a: __v8f32) -> __v8f32; #[link_name = "llvm.loongarch.lasx.xvfrintrne.d"] fn __lasx_xvfrintrne_d(a: __v4f64) -> __v4f64; - #[link_name = "llvm.loongarch.lasx.xvfrintrz.s"] - fn __lasx_xvfrintrz_s(a: __v8f32) -> __v8f32; - #[link_name = "llvm.loongarch.lasx.xvfrintrz.d"] - fn __lasx_xvfrintrz_d(a: __v4f64) -> __v4f64; - #[link_name = "llvm.loongarch.lasx.xvfrintrp.s"] - fn __lasx_xvfrintrp_s(a: __v8f32) -> __v8f32; - #[link_name = "llvm.loongarch.lasx.xvfrintrp.d"] - fn __lasx_xvfrintrp_d(a: __v4f64) -> __v4f64; - #[link_name = "llvm.loongarch.lasx.xvfrintrm.s"] - fn __lasx_xvfrintrm_s(a: __v8f32) -> __v8f32; - #[link_name = "llvm.loongarch.lasx.xvfrintrm.d"] - fn __lasx_xvfrintrm_d(a: __v4f64) -> __v4f64; - #[link_name = "llvm.loongarch.lasx.xvld"] - fn __lasx_xvld(a: *const i8, b: i32) -> __v32i8; - #[link_name = "llvm.loongarch.lasx.xvst"] - fn __lasx_xvst(a: __v32i8, b: *mut i8, c: i32); #[link_name = "llvm.loongarch.lasx.xvstelm.b"] fn __lasx_xvstelm_b(a: __v32i8, b: *mut i8, c: i32, d: u32); #[link_name = "llvm.loongarch.lasx.xvstelm.h"] @@ -489,10 +449,6 @@ unsafe extern "unadjusted" { fn __lasx_xvssrln_w_d(a: __v4i64, b: __v4i64) -> __v8i32; #[link_name = "llvm.loongarch.lasx.xvldi"] fn __lasx_xvldi(a: i32) -> __v4i64; - #[link_name = "llvm.loongarch.lasx.xvldx"] - fn __lasx_xvldx(a: *const i8, b: i64) -> __v32i8; - #[link_name = "llvm.loongarch.lasx.xvstx"] - fn __lasx_xvstx(a: __v32i8, b: *mut i8, c: i64); #[link_name = "llvm.loongarch.lasx.xvextl.qu.du"] fn __lasx_xvextl_qu_du(a: __v4u64) -> __v4u64; #[link_name = "llvm.loongarch.lasx.vext2xv.h.b"] @@ -709,14 +665,6 @@ unsafe extern "unadjusted" { fn __lasx_xvmaddwod_w_hu_h(a: __v8i32, b: __v16u16, c: __v16i16) -> __v8i32; #[link_name = "llvm.loongarch.lasx.xvmaddwod.h.bu.b"] fn __lasx_xvmaddwod_h_bu_b(a: __v16i16, b: __v32u8, c: __v32i8) -> __v16i16; - #[link_name = "llvm.loongarch.lasx.xvrotr.b"] - fn __lasx_xvrotr_b(a: __v32i8, b: __v32i8) -> __v32i8; - #[link_name = "llvm.loongarch.lasx.xvrotr.h"] - fn __lasx_xvrotr_h(a: __v16i16, b: __v16i16) -> __v16i16; - #[link_name = "llvm.loongarch.lasx.xvrotr.w"] - fn __lasx_xvrotr_w(a: __v8i32, b: __v8i32) -> __v8i32; - #[link_name = "llvm.loongarch.lasx.xvrotr.d"] - fn __lasx_xvrotr_d(a: __v4i64, b: __v4i64) -> __v4i64; #[link_name = "llvm.loongarch.lasx.xvadd.q"] fn __lasx_xvadd_q(a: __v4i64, b: __v4i64) -> __v4i64; #[link_name = "llvm.loongarch.lasx.xvsub.q"] @@ -749,14 +697,6 @@ unsafe extern "unadjusted" { fn __lasx_xvexth_du_wu(a: __v8u32) -> __v4u64; #[link_name = "llvm.loongarch.lasx.xvexth.qu.du"] fn __lasx_xvexth_qu_du(a: __v4u64) -> __v4u64; - #[link_name = "llvm.loongarch.lasx.xvrotri.b"] - fn __lasx_xvrotri_b(a: __v32i8, b: u32) -> __v32i8; - #[link_name = "llvm.loongarch.lasx.xvrotri.h"] - fn __lasx_xvrotri_h(a: __v16i16, b: u32) -> __v16i16; - #[link_name = "llvm.loongarch.lasx.xvrotri.w"] - fn __lasx_xvrotri_w(a: __v8i32, b: u32) -> __v8i32; - #[link_name = "llvm.loongarch.lasx.xvrotri.d"] - fn __lasx_xvrotri_d(a: __v4i64, b: u32) -> __v4i64; #[link_name = "llvm.loongarch.lasx.xvextl.q.d"] fn __lasx_xvextl_q_d(a: __v4i64) -> __v4i64; #[link_name = "llvm.loongarch.lasx.xvsrlni.b.h"] @@ -1737,20 +1677,6 @@ pub fn lasx_xvfclass_d(a: m256d) -> m256i { unsafe { transmute(__lasx_xvfclass_d(transmute(a))) } } -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrecip_s(a: m256) -> m256 { - unsafe { transmute(__lasx_xvfrecip_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrecip_d(a: m256d) -> m256d { - unsafe { transmute(__lasx_xvfrecip_d(transmute(a))) } -} - #[inline] #[target_feature(enable = "lasx,frecipe")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -1793,20 +1719,6 @@ pub fn lasx_xvfrint_d(a: m256d) -> m256d { unsafe { transmute(__lasx_xvfrint_d(transmute(a))) } } -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrsqrt_s(a: m256) -> m256 { - unsafe { transmute(__lasx_xvfrsqrt_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrsqrt_d(a: m256d) -> m256d { - unsafe { transmute(__lasx_xvfrsqrt_d(transmute(a))) } -} - #[inline] #[target_feature(enable = "lasx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -1970,62 +1882,6 @@ pub fn lasx_xvpermi_w(a: m256i, b: m256i) -> m256i { unsafe { transmute(__lasx_xvpermi_w(transmute(a), transmute(b), IMM8)) } } -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_b(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_b(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_h(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_h(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_w(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_w(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_d(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_d(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_bu(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_bu(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_hu(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_hu(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_wu(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_wu(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvmuh_du(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvmuh_du(transmute(a), transmute(b))) } -} - #[inline] #[target_feature(enable = "lasx")] #[rustc_legacy_const_generics(1)] @@ -2623,66 +2479,6 @@ pub fn lasx_xvfrintrne_d(a: m256d) -> m256d { unsafe { transmute(__lasx_xvfrintrne_d(transmute(a))) } } -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrintrz_s(a: m256) -> m256 { - unsafe { transmute(__lasx_xvfrintrz_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrintrz_d(a: m256d) -> m256d { - unsafe { transmute(__lasx_xvfrintrz_d(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrintrp_s(a: m256) -> m256 { - unsafe { transmute(__lasx_xvfrintrp_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrintrp_d(a: m256d) -> m256d { - unsafe { transmute(__lasx_xvfrintrp_d(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrintrm_s(a: m256) -> m256 { - unsafe { transmute(__lasx_xvfrintrm_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvfrintrm_d(a: m256d) -> m256d { - unsafe { transmute(__lasx_xvfrintrm_d(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lasx_xvld(mem_addr: *const i8) -> m256i { - static_assert_simm_bits!(IMM_S12, 12); - transmute(__lasx_xvld(mem_addr, IMM_S12)) -} - -#[inline] -#[target_feature(enable = "lasx")] -#[rustc_legacy_const_generics(2)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lasx_xvst(a: m256i, mem_addr: *mut i8) { - static_assert_simm_bits!(IMM_S12, 12); - __lasx_xvst(transmute(a), mem_addr, IMM_S12) -} - #[inline] #[target_feature(enable = "lasx")] #[rustc_legacy_const_generics(2, 3)] @@ -2810,20 +2606,6 @@ pub fn lasx_xvldi() -> m256i { unsafe { transmute(__lasx_xvldi(IMM_S13)) } } -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lasx_xvldx(mem_addr: *const i8, b: i64) -> m256i { - transmute(__lasx_xvldx(mem_addr, transmute(b))) -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lasx_xvstx(a: m256i, mem_addr: *mut i8, b: i64) { - __lasx_xvstx(transmute(a), mem_addr, transmute(b)) -} - #[inline] #[target_feature(enable = "lasx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -3592,34 +3374,6 @@ pub fn lasx_xvmaddwod_h_bu_b(a: m256i, b: m256i, c: m256i) -> m256i { unsafe { transmute(__lasx_xvmaddwod_h_bu_b(transmute(a), transmute(b), transmute(c))) } } -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotr_b(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvrotr_b(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotr_h(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvrotr_h(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotr_w(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvrotr_w(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotr_d(a: m256i, b: m256i) -> m256i { - unsafe { transmute(__lasx_xvrotr_d(transmute(a), transmute(b))) } -} - #[inline] #[target_feature(enable = "lasx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -3732,42 +3486,6 @@ pub fn lasx_xvexth_qu_du(a: m256i) -> m256i { unsafe { transmute(__lasx_xvexth_qu_du(transmute(a))) } } -#[inline] -#[target_feature(enable = "lasx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotri_b(a: m256i) -> m256i { - static_assert_uimm_bits!(IMM3, 3); - unsafe { transmute(__lasx_xvrotri_b(transmute(a), IMM3)) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotri_h(a: m256i) -> m256i { - static_assert_uimm_bits!(IMM4, 4); - unsafe { transmute(__lasx_xvrotri_h(transmute(a), IMM4)) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotri_w(a: m256i) -> m256i { - static_assert_uimm_bits!(IMM5, 5); - unsafe { transmute(__lasx_xvrotri_w(transmute(a), IMM5)) } -} - -#[inline] -#[target_feature(enable = "lasx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lasx_xvrotri_d(a: m256i) -> m256i { - static_assert_uimm_bits!(IMM6, 6); - unsafe { transmute(__lasx_xvrotri_d(transmute(a), IMM6)) } -} - #[inline] #[target_feature(enable = "lasx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] diff --git a/library/stdarch/crates/core_arch/src/loongarch64/lasx/portable.rs b/library/stdarch/crates/core_arch/src/loongarch64/lasx/portable.rs index 4dfe80795f68c..110a98cfb06b4 100644 --- a/library/stdarch/crates/core_arch/src/loongarch64/lasx/portable.rs +++ b/library/stdarch/crates/core_arch/src/loongarch64/lasx/portable.rs @@ -328,6 +328,16 @@ impl_vv!("lasx", lasx_xvneg_w, is::simd_neg, m256i, i32x8); impl_vv!("lasx", lasx_xvneg_d, is::simd_neg, m256i, i64x4); impl_vv!("lasx", lasx_xvfsqrt_s, is::simd_fsqrt, m256, f32x8); impl_vv!("lasx", lasx_xvfsqrt_d, is::simd_fsqrt, m256d, f64x4); +impl_vv!("lasx", lasx_xvfrsqrt_s, ls::simd_frsqrt_s, m256, f32x8); +impl_vv!("lasx", lasx_xvfrsqrt_d, ls::simd_frsqrt_d, m256d, f64x4); +impl_vv!("lasx", lasx_xvfrecip_s, ls::simd_frecip_s, m256, f32x8); +impl_vv!("lasx", lasx_xvfrecip_d, ls::simd_frecip_d, m256d, f64x4); +impl_vv!("lasx", lasx_xvfrintrp_s, is::simd_ceil, m256, f32x8); +impl_vv!("lasx", lasx_xvfrintrp_d, is::simd_ceil, m256d, f64x4); +impl_vv!("lasx", lasx_xvfrintrm_s, is::simd_floor, m256, f32x8); +impl_vv!("lasx", lasx_xvfrintrm_d, is::simd_floor, m256d, f64x4); +impl_vv!("lasx", lasx_xvfrintrz_s, is::simd_trunc, m256, f32x8); +impl_vv!("lasx", lasx_xvfrintrz_d, is::simd_trunc, m256d, f64x4); impl_vv!("lasx", lasx_xvreplve0_b, simd_replve0_b, m256i, i8x32); impl_vv!("lasx", lasx_xvreplve0_h, simd_replve0_h, m256i, i16x16); impl_vv!("lasx", lasx_xvreplve0_w, simd_replve0_w, m256i, i32x8); @@ -339,6 +349,10 @@ impl_gv!("lasx", lasx_xvreplgr2vr_h, ls::simd_splat, m256i, i16x16, i32); impl_gv!("lasx", lasx_xvreplgr2vr_w, ls::simd_splat, m256i, i32x8, i32); impl_gv!("lasx", lasx_xvreplgr2vr_d, ls::simd_splat, m256i, i64x4, i64); +impl_ggv!("lasx", lasx_xvldx, simd_ldx, m256i, i8x32, *const i8, i64, unsafe); + +impl_gsv!("lasx", lasx_xvld, simd_ld, m256i, i8x32, *const i8, 12, const, unsafe); + impl_sv!("lasx", lasx_xvrepli_b, ls::simd_splat, m256i, i8x32, 10); impl_sv!("lasx", lasx_xvrepli_h, ls::simd_splat, m256i, i16x16, 10); impl_sv!("lasx", lasx_xvrepli_w, ls::simd_splat, m256i, i32x8, 10); @@ -434,6 +448,10 @@ impl_vvv!("lasx", lasx_xvsrl_b, ls::simd_shr, m256i, u8x32); impl_vvv!("lasx", lasx_xvsrl_h, ls::simd_shr, m256i, u16x16); impl_vvv!("lasx", lasx_xvsrl_w, ls::simd_shr, m256i, u32x8); impl_vvv!("lasx", lasx_xvsrl_d, ls::simd_shr, m256i, u64x4); +impl_vvv!("lasx", lasx_xvrotr_b, ls::simd_rotr, m256i, u8x32); +impl_vvv!("lasx", lasx_xvrotr_h, ls::simd_rotr, m256i, u16x16); +impl_vvv!("lasx", lasx_xvrotr_w, ls::simd_rotr, m256i, u32x8); +impl_vvv!("lasx", lasx_xvrotr_d, ls::simd_rotr, m256i, u64x4); impl_vvv!("lasx", lasx_xvbitclr_b, ls::simd_bitclr, m256i, u8x32); impl_vvv!("lasx", lasx_xvbitclr_h, ls::simd_bitclr, m256i, u16x16); impl_vvv!("lasx", lasx_xvbitclr_w, ls::simd_bitclr, m256i, u32x8); @@ -474,6 +492,14 @@ impl_vvv!("lasx", lasx_xvabsd_bu, ls::simd_absd, m256i, u8x32); impl_vvv!("lasx", lasx_xvabsd_hu, ls::simd_absd, m256i, u16x16); impl_vvv!("lasx", lasx_xvabsd_wu, ls::simd_absd, m256i, u32x8); impl_vvv!("lasx", lasx_xvabsd_du, ls::simd_absd, m256i, u64x4); +impl_vvv!("lasx", lasx_xvmuh_b, simd_muh, m256i, i8x32, i16x32); +impl_vvv!("lasx", lasx_xvmuh_h, simd_muh, m256i, i16x16, i32x16); +impl_vvv!("lasx", lasx_xvmuh_w, simd_muh, m256i, i32x8, i64x8); +impl_vvv!("lasx", lasx_xvmuh_d, simd_muh, m256i, i64x4, i128x4); +impl_vvv!("lasx", lasx_xvmuh_bu, simd_muh, m256i, u8x32, u16x32); +impl_vvv!("lasx", lasx_xvmuh_hu, simd_muh, m256i, u16x16, u32x16); +impl_vvv!("lasx", lasx_xvmuh_wu, simd_muh, m256i, u32x8, u64x8); +impl_vvv!("lasx", lasx_xvmuh_du, simd_muh, m256i, u64x4, u128x4); impl_vvv!("lasx", lasx_xvpickev_b, simd_pickev_b, m256i, i8x32); impl_vvv!("lasx", lasx_xvpickev_h, simd_pickev_h, m256i, i16x16); impl_vvv!("lasx", lasx_xvpickev_w, simd_pickev_w, m256i, i32x8); @@ -499,6 +525,10 @@ impl_vvv!("lasx", lasx_xvpackod_h, simd_packod_h, m256i, i16x16); impl_vvv!("lasx", lasx_xvpackod_w, simd_packod_w, m256i, i32x8); impl_vvv!("lasx", lasx_xvpackod_d, simd_packod_d, m256i, i64x4); +impl_vgg!("lasx", lasx_xvstx, simd_stx, m256i, i8x32, *mut i8, i64, unsafe); + +impl_vgs!("lasx", lasx_xvst, simd_st, m256i, i8x32, *mut i8, 12, const, unsafe); + impl_vuv!("lasx", lasx_xvslli_b, is::simd_shl, m256i, i8x32); impl_vuv!("lasx", lasx_xvslli_h, is::simd_shl, m256i, i16x16); impl_vuv!("lasx", lasx_xvslli_w, is::simd_shl, m256i, i32x8); @@ -511,6 +541,10 @@ impl_vuv!("lasx", lasx_xvsrli_b, is::simd_shr, m256i, u8x32); impl_vuv!("lasx", lasx_xvsrli_h, is::simd_shr, m256i, u16x16); impl_vuv!("lasx", lasx_xvsrli_w, is::simd_shr, m256i, u32x8); impl_vuv!("lasx", lasx_xvsrli_d, is::simd_shr, m256i, u64x4); +impl_vuv!("lasx", lasx_xvrotri_b, ls::simd_rotr, m256i, u8x32); +impl_vuv!("lasx", lasx_xvrotri_h, ls::simd_rotr, m256i, u16x16); +impl_vuv!("lasx", lasx_xvrotri_w, ls::simd_rotr, m256i, u32x8); +impl_vuv!("lasx", lasx_xvrotri_d, ls::simd_rotr, m256i, u64x4); impl_vuv!("lasx", lasx_xvaddi_bu, is::simd_add, m256i, u8x32, 5); impl_vuv!("lasx", lasx_xvaddi_hu, is::simd_add, m256i, u16x16, 5); impl_vuv!("lasx", lasx_xvaddi_wu, is::simd_add, m256i, u32x8, 5); diff --git a/library/stdarch/crates/core_arch/src/loongarch64/lsx/generated.rs b/library/stdarch/crates/core_arch/src/loongarch64/lsx/generated.rs index 555866040e420..6483c6296a344 100644 --- a/library/stdarch/crates/core_arch/src/loongarch64/lsx/generated.rs +++ b/library/stdarch/crates/core_arch/src/loongarch64/lsx/generated.rs @@ -205,10 +205,6 @@ unsafe extern "unadjusted" { fn __lsx_vfclass_s(a: __v4f32) -> __v4i32; #[link_name = "llvm.loongarch.lsx.vfclass.d"] fn __lsx_vfclass_d(a: __v2f64) -> __v2i64; - #[link_name = "llvm.loongarch.lsx.vfrecip.s"] - fn __lsx_vfrecip_s(a: __v4f32) -> __v4f32; - #[link_name = "llvm.loongarch.lsx.vfrecip.d"] - fn __lsx_vfrecip_d(a: __v2f64) -> __v2f64; #[link_name = "llvm.loongarch.lsx.vfrecipe.s"] fn __lsx_vfrecipe_s(a: __v4f32) -> __v4f32; #[link_name = "llvm.loongarch.lsx.vfrecipe.d"] @@ -221,10 +217,6 @@ unsafe extern "unadjusted" { fn __lsx_vfrint_s(a: __v4f32) -> __v4f32; #[link_name = "llvm.loongarch.lsx.vfrint.d"] fn __lsx_vfrint_d(a: __v2f64) -> __v2f64; - #[link_name = "llvm.loongarch.lsx.vfrsqrt.s"] - fn __lsx_vfrsqrt_s(a: __v4f32) -> __v4f32; - #[link_name = "llvm.loongarch.lsx.vfrsqrt.d"] - fn __lsx_vfrsqrt_d(a: __v2f64) -> __v2f64; #[link_name = "llvm.loongarch.lsx.vflogb.s"] fn __lsx_vflogb_s(a: __v4f32) -> __v4f32; #[link_name = "llvm.loongarch.lsx.vflogb.d"] @@ -261,22 +253,6 @@ unsafe extern "unadjusted" { fn __lsx_vffint_s_wu(a: __v4u32) -> __v4f32; #[link_name = "llvm.loongarch.lsx.vffint.d.lu"] fn __lsx_vffint_d_lu(a: __v2u64) -> __v2f64; - #[link_name = "llvm.loongarch.lsx.vmuh.b"] - fn __lsx_vmuh_b(a: __v16i8, b: __v16i8) -> __v16i8; - #[link_name = "llvm.loongarch.lsx.vmuh.h"] - fn __lsx_vmuh_h(a: __v8i16, b: __v8i16) -> __v8i16; - #[link_name = "llvm.loongarch.lsx.vmuh.w"] - fn __lsx_vmuh_w(a: __v4i32, b: __v4i32) -> __v4i32; - #[link_name = "llvm.loongarch.lsx.vmuh.d"] - fn __lsx_vmuh_d(a: __v2i64, b: __v2i64) -> __v2i64; - #[link_name = "llvm.loongarch.lsx.vmuh.bu"] - fn __lsx_vmuh_bu(a: __v16u8, b: __v16u8) -> __v16u8; - #[link_name = "llvm.loongarch.lsx.vmuh.hu"] - fn __lsx_vmuh_hu(a: __v8u16, b: __v8u16) -> __v8u16; - #[link_name = "llvm.loongarch.lsx.vmuh.wu"] - fn __lsx_vmuh_wu(a: __v4u32, b: __v4u32) -> __v4u32; - #[link_name = "llvm.loongarch.lsx.vmuh.du"] - fn __lsx_vmuh_du(a: __v2u64, b: __v2u64) -> __v2u64; #[link_name = "llvm.loongarch.lsx.vsllwil.h.b"] fn __lsx_vsllwil_h_b(a: __v16i8, b: u32) -> __v8i16; #[link_name = "llvm.loongarch.lsx.vsllwil.w.h"] @@ -437,18 +413,6 @@ unsafe extern "unadjusted" { fn __lsx_vfrintrne_s(a: __v4f32) -> __v4f32; #[link_name = "llvm.loongarch.lsx.vfrintrne.d"] fn __lsx_vfrintrne_d(a: __v2f64) -> __v2f64; - #[link_name = "llvm.loongarch.lsx.vfrintrz.s"] - fn __lsx_vfrintrz_s(a: __v4f32) -> __v4f32; - #[link_name = "llvm.loongarch.lsx.vfrintrz.d"] - fn __lsx_vfrintrz_d(a: __v2f64) -> __v2f64; - #[link_name = "llvm.loongarch.lsx.vfrintrp.s"] - fn __lsx_vfrintrp_s(a: __v4f32) -> __v4f32; - #[link_name = "llvm.loongarch.lsx.vfrintrp.d"] - fn __lsx_vfrintrp_d(a: __v2f64) -> __v2f64; - #[link_name = "llvm.loongarch.lsx.vfrintrm.s"] - fn __lsx_vfrintrm_s(a: __v4f32) -> __v4f32; - #[link_name = "llvm.loongarch.lsx.vfrintrm.d"] - fn __lsx_vfrintrm_d(a: __v2f64) -> __v2f64; #[link_name = "llvm.loongarch.lsx.vstelm.b"] fn __lsx_vstelm_b(a: __v16i8, b: *mut i8, c: i32, d: u32); #[link_name = "llvm.loongarch.lsx.vstelm.h"] @@ -641,14 +605,6 @@ unsafe extern "unadjusted" { fn __lsx_vmaddwev_q_du_d(a: __v2i64, b: __v2u64, c: __v2i64) -> __v2i64; #[link_name = "llvm.loongarch.lsx.vmaddwod.q.du.d"] fn __lsx_vmaddwod_q_du_d(a: __v2i64, b: __v2u64, c: __v2i64) -> __v2i64; - #[link_name = "llvm.loongarch.lsx.vrotr.b"] - fn __lsx_vrotr_b(a: __v16i8, b: __v16i8) -> __v16i8; - #[link_name = "llvm.loongarch.lsx.vrotr.h"] - fn __lsx_vrotr_h(a: __v8i16, b: __v8i16) -> __v8i16; - #[link_name = "llvm.loongarch.lsx.vrotr.w"] - fn __lsx_vrotr_w(a: __v4i32, b: __v4i32) -> __v4i32; - #[link_name = "llvm.loongarch.lsx.vrotr.d"] - fn __lsx_vrotr_d(a: __v2i64, b: __v2i64) -> __v2i64; #[link_name = "llvm.loongarch.lsx.vadd.q"] fn __lsx_vadd_q(a: __v2i64, b: __v2i64) -> __v2i64; #[link_name = "llvm.loongarch.lsx.vsub.q"] @@ -681,14 +637,6 @@ unsafe extern "unadjusted" { fn __lsx_vexth_du_wu(a: __v4u32) -> __v2u64; #[link_name = "llvm.loongarch.lsx.vexth.qu.du"] fn __lsx_vexth_qu_du(a: __v2u64) -> __v2u64; - #[link_name = "llvm.loongarch.lsx.vrotri.b"] - fn __lsx_vrotri_b(a: __v16i8, b: u32) -> __v16i8; - #[link_name = "llvm.loongarch.lsx.vrotri.h"] - fn __lsx_vrotri_h(a: __v8i16, b: u32) -> __v8i16; - #[link_name = "llvm.loongarch.lsx.vrotri.w"] - fn __lsx_vrotri_w(a: __v4i32, b: u32) -> __v4i32; - #[link_name = "llvm.loongarch.lsx.vrotri.d"] - fn __lsx_vrotri_d(a: __v2i64, b: u32) -> __v2i64; #[link_name = "llvm.loongarch.lsx.vextl.q.d"] fn __lsx_vextl_q_d(a: __v2i64) -> __v2i64; #[link_name = "llvm.loongarch.lsx.vsrlni.b.h"] @@ -789,10 +737,6 @@ unsafe extern "unadjusted" { fn __lsx_vssrarni_du_q(a: __v2u64, b: __v2i64, c: u32) -> __v2u64; #[link_name = "llvm.loongarch.lsx.vpermi.w"] fn __lsx_vpermi_w(a: __v4i32, b: __v4i32, c: u32) -> __v4i32; - #[link_name = "llvm.loongarch.lsx.vld"] - fn __lsx_vld(a: *const i8, b: i32) -> __v16i8; - #[link_name = "llvm.loongarch.lsx.vst"] - fn __lsx_vst(a: __v16i8, b: *mut i8, c: i32); #[link_name = "llvm.loongarch.lsx.vssrlrn.b.h"] fn __lsx_vssrlrn_b_h(a: __v8i16, b: __v8i16) -> __v16i8; #[link_name = "llvm.loongarch.lsx.vssrlrn.h.w"] @@ -809,10 +753,6 @@ unsafe extern "unadjusted" { fn __lsx_vldi(a: i32) -> __v2i64; #[link_name = "llvm.loongarch.lsx.vshuf.b"] fn __lsx_vshuf_b(a: __v16i8, b: __v16i8, c: __v16i8) -> __v16i8; - #[link_name = "llvm.loongarch.lsx.vldx"] - fn __lsx_vldx(a: *const i8, b: i64) -> __v16i8; - #[link_name = "llvm.loongarch.lsx.vstx"] - fn __lsx_vstx(a: __v16i8, b: *mut i8, c: i64); #[link_name = "llvm.loongarch.lsx.vextl.qu.du"] fn __lsx_vextl_qu_du(a: __v2u64) -> __v2u64; #[link_name = "llvm.loongarch.lsx.bnz.b"] @@ -1678,20 +1618,6 @@ pub fn lsx_vfclass_d(a: m128d) -> m128i { unsafe { transmute(__lsx_vfclass_d(transmute(a))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrecip_s(a: m128) -> m128 { - unsafe { transmute(__lsx_vfrecip_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrecip_d(a: m128d) -> m128d { - unsafe { transmute(__lsx_vfrecip_d(transmute(a))) } -} - #[inline] #[target_feature(enable = "lsx,frecipe")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -1734,20 +1660,6 @@ pub fn lsx_vfrint_d(a: m128d) -> m128d { unsafe { transmute(__lsx_vfrint_d(transmute(a))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrsqrt_s(a: m128) -> m128 { - unsafe { transmute(__lsx_vfrsqrt_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrsqrt_d(a: m128d) -> m128d { - unsafe { transmute(__lsx_vfrsqrt_d(transmute(a))) } -} - #[inline] #[target_feature(enable = "lsx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -1874,62 +1786,6 @@ pub fn lsx_vffint_d_lu(a: m128i) -> m128d { unsafe { transmute(__lsx_vffint_d_lu(transmute(a))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_b(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_b(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_h(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_h(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_w(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_w(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_d(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_d(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_bu(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_bu(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_hu(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_hu(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_wu(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_wu(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vmuh_du(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vmuh_du(transmute(a), transmute(b))) } -} - #[inline] #[target_feature(enable = "lsx")] #[rustc_legacy_const_generics(1)] @@ -2518,48 +2374,6 @@ pub fn lsx_vfrintrne_d(a: m128d) -> m128d { unsafe { transmute(__lsx_vfrintrne_d(transmute(a))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrintrz_s(a: m128) -> m128 { - unsafe { transmute(__lsx_vfrintrz_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrintrz_d(a: m128d) -> m128d { - unsafe { transmute(__lsx_vfrintrz_d(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrintrp_s(a: m128) -> m128 { - unsafe { transmute(__lsx_vfrintrp_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrintrp_d(a: m128d) -> m128d { - unsafe { transmute(__lsx_vfrintrp_d(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrintrm_s(a: m128) -> m128 { - unsafe { transmute(__lsx_vfrintrm_s(transmute(a))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vfrintrm_d(a: m128d) -> m128d { - unsafe { transmute(__lsx_vfrintrm_d(transmute(a))) } -} - #[inline] #[target_feature(enable = "lsx")] #[rustc_legacy_const_generics(2, 3)] @@ -3244,34 +3058,6 @@ pub fn lsx_vmaddwod_q_du_d(a: m128i, b: m128i, c: m128i) -> m128i { unsafe { transmute(__lsx_vmaddwod_q_du_d(transmute(a), transmute(b), transmute(c))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotr_b(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vrotr_b(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotr_h(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vrotr_h(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotr_w(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vrotr_w(transmute(a), transmute(b))) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotr_d(a: m128i, b: m128i) -> m128i { - unsafe { transmute(__lsx_vrotr_d(transmute(a), transmute(b))) } -} - #[inline] #[target_feature(enable = "lsx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -3392,42 +3178,6 @@ pub fn lsx_vexth_qu_du(a: m128i) -> m128i { unsafe { transmute(__lsx_vexth_qu_du(transmute(a))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotri_b(a: m128i) -> m128i { - static_assert_uimm_bits!(IMM3, 3); - unsafe { transmute(__lsx_vrotri_b(transmute(a), IMM3)) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotri_h(a: m128i) -> m128i { - static_assert_uimm_bits!(IMM4, 4); - unsafe { transmute(__lsx_vrotri_h(transmute(a), IMM4)) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotri_w(a: m128i) -> m128i { - static_assert_uimm_bits!(IMM5, 5); - unsafe { transmute(__lsx_vrotri_w(transmute(a), IMM5)) } -} - -#[inline] -#[target_feature(enable = "lsx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub fn lsx_vrotri_d(a: m128i) -> m128i { - static_assert_uimm_bits!(IMM6, 6); - unsafe { transmute(__lsx_vrotri_d(transmute(a), IMM6)) } -} - #[inline] #[target_feature(enable = "lsx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -3876,24 +3626,6 @@ pub fn lsx_vpermi_w(a: m128i, b: m128i) -> m128i { unsafe { transmute(__lsx_vpermi_w(transmute(a), transmute(b), IMM8)) } } -#[inline] -#[target_feature(enable = "lsx")] -#[rustc_legacy_const_generics(1)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lsx_vld(mem_addr: *const i8) -> m128i { - static_assert_simm_bits!(IMM_S12, 12); - transmute(__lsx_vld(mem_addr, IMM_S12)) -} - -#[inline] -#[target_feature(enable = "lsx")] -#[rustc_legacy_const_generics(2)] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lsx_vst(a: m128i, mem_addr: *mut i8) { - static_assert_simm_bits!(IMM_S12, 12); - __lsx_vst(transmute(a), mem_addr, IMM_S12) -} - #[inline] #[target_feature(enable = "lsx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] @@ -3952,20 +3684,6 @@ pub fn lsx_vshuf_b(a: m128i, b: m128i, c: m128i) -> m128i { unsafe { transmute(__lsx_vshuf_b(transmute(a), transmute(b), transmute(c))) } } -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lsx_vldx(mem_addr: *const i8, b: i64) -> m128i { - transmute(__lsx_vldx(mem_addr, transmute(b))) -} - -#[inline] -#[target_feature(enable = "lsx")] -#[unstable(feature = "stdarch_loongarch", issue = "117427")] -pub unsafe fn lsx_vstx(a: m128i, mem_addr: *mut i8, b: i64) { - __lsx_vstx(transmute(a), mem_addr, transmute(b)) -} - #[inline] #[target_feature(enable = "lsx")] #[unstable(feature = "stdarch_loongarch", issue = "117427")] diff --git a/library/stdarch/crates/core_arch/src/loongarch64/lsx/portable.rs b/library/stdarch/crates/core_arch/src/loongarch64/lsx/portable.rs index 0b0df11bbfaac..2ceed73283726 100644 --- a/library/stdarch/crates/core_arch/src/loongarch64/lsx/portable.rs +++ b/library/stdarch/crates/core_arch/src/loongarch64/lsx/portable.rs @@ -227,12 +227,26 @@ impl_vv!("lsx", lsx_vneg_w, is::simd_neg, m128i, i32x4); impl_vv!("lsx", lsx_vneg_d, is::simd_neg, m128i, i64x2); impl_vv!("lsx", lsx_vfsqrt_s, is::simd_fsqrt, m128, f32x4); impl_vv!("lsx", lsx_vfsqrt_d, is::simd_fsqrt, m128d, f64x2); +impl_vv!("lsx", lsx_vfrsqrt_s, ls::simd_frsqrt_s, m128, f32x4); +impl_vv!("lsx", lsx_vfrsqrt_d, ls::simd_frsqrt_d, m128d, f64x2); +impl_vv!("lsx", lsx_vfrecip_s, ls::simd_frecip_s, m128, f32x4); +impl_vv!("lsx", lsx_vfrecip_d, ls::simd_frecip_d, m128d, f64x2); +impl_vv!("lsx", lsx_vfrintrp_s, is::simd_ceil, m128, f32x4); +impl_vv!("lsx", lsx_vfrintrp_d, is::simd_ceil, m128d, f64x2); +impl_vv!("lsx", lsx_vfrintrm_s, is::simd_floor, m128, f32x4); +impl_vv!("lsx", lsx_vfrintrm_d, is::simd_floor, m128d, f64x2); +impl_vv!("lsx", lsx_vfrintrz_s, is::simd_trunc, m128, f32x4); +impl_vv!("lsx", lsx_vfrintrz_d, is::simd_trunc, m128d, f64x2); impl_gv!("lsx", lsx_vreplgr2vr_b, ls::simd_splat, m128i, i8x16, i32); impl_gv!("lsx", lsx_vreplgr2vr_h, ls::simd_splat, m128i, i16x8, i32); impl_gv!("lsx", lsx_vreplgr2vr_w, ls::simd_splat, m128i, i32x4, i32); impl_gv!("lsx", lsx_vreplgr2vr_d, ls::simd_splat, m128i, i64x2, i64); +impl_ggv!("lsx", lsx_vldx, simd_ldx, m128i, i8x16, *const i8, i64, unsafe); + +impl_gsv!("lsx", lsx_vld, simd_ld, m128i, i8x16, *const i8, 12, const, unsafe); + impl_sv!("lsx", lsx_vrepli_b, ls::simd_splat, m128i, i8x16, 10); impl_sv!("lsx", lsx_vrepli_h, ls::simd_splat, m128i, i16x8, 10); impl_sv!("lsx", lsx_vrepli_w, ls::simd_splat, m128i, i32x4, 10); @@ -328,6 +342,10 @@ impl_vvv!("lsx", lsx_vsrl_b, ls::simd_shr, m128i, u8x16); impl_vvv!("lsx", lsx_vsrl_h, ls::simd_shr, m128i, u16x8); impl_vvv!("lsx", lsx_vsrl_w, ls::simd_shr, m128i, u32x4); impl_vvv!("lsx", lsx_vsrl_d, ls::simd_shr, m128i, u64x2); +impl_vvv!("lsx", lsx_vrotr_b, ls::simd_rotr, m128i, u8x16); +impl_vvv!("lsx", lsx_vrotr_h, ls::simd_rotr, m128i, u16x8); +impl_vvv!("lsx", lsx_vrotr_w, ls::simd_rotr, m128i, u32x4); +impl_vvv!("lsx", lsx_vrotr_d, ls::simd_rotr, m128i, u64x2); impl_vvv!("lsx", lsx_vbitclr_b, ls::simd_bitclr, m128i, u8x16); impl_vvv!("lsx", lsx_vbitclr_h, ls::simd_bitclr, m128i, u16x8); impl_vvv!("lsx", lsx_vbitclr_w, ls::simd_bitclr, m128i, u32x4); @@ -368,6 +386,14 @@ impl_vvv!("lsx", lsx_vabsd_bu, ls::simd_absd, m128i, u8x16); impl_vvv!("lsx", lsx_vabsd_hu, ls::simd_absd, m128i, u16x8); impl_vvv!("lsx", lsx_vabsd_wu, ls::simd_absd, m128i, u32x4); impl_vvv!("lsx", lsx_vabsd_du, ls::simd_absd, m128i, u64x2); +impl_vvv!("lsx", lsx_vmuh_b, simd_muh, m128i, i8x16, i16x16); +impl_vvv!("lsx", lsx_vmuh_h, simd_muh, m128i, i16x8, i32x8); +impl_vvv!("lsx", lsx_vmuh_w, simd_muh, m128i, i32x4, i64x4); +impl_vvv!("lsx", lsx_vmuh_d, simd_muh, m128i, i64x2, i128x2); +impl_vvv!("lsx", lsx_vmuh_bu, simd_muh, m128i, u8x16, u16x16); +impl_vvv!("lsx", lsx_vmuh_hu, simd_muh, m128i, u16x8, u32x8); +impl_vvv!("lsx", lsx_vmuh_wu, simd_muh, m128i, u32x4, u64x4); +impl_vvv!("lsx", lsx_vmuh_du, simd_muh, m128i, u64x2, u128x2); impl_vvv!("lsx", lsx_vpickev_b, simd_pickev_b, m128i, i8x16); impl_vvv!("lsx", lsx_vpickev_h, simd_pickev_h, m128i, i16x8); impl_vvv!("lsx", lsx_vpickev_w, simd_pickev_w, m128i, i32x4); @@ -393,6 +419,10 @@ impl_vvv!("lsx", lsx_vpackod_h, simd_packod_h, m128i, i16x8); impl_vvv!("lsx", lsx_vpackod_w, simd_packod_w, m128i, i32x4); impl_vvv!("lsx", lsx_vpackod_d, simd_packod_d, m128i, i64x2); +impl_vgg!("lsx", lsx_vstx, simd_stx, m128i, i8x16, *mut i8, i64, unsafe); + +impl_vgs!("lsx", lsx_vst, simd_st, m128i, i8x16, *mut i8, 12, const, unsafe); + impl_vuv!("lsx", lsx_vslli_b, is::simd_shl, m128i, i8x16); impl_vuv!("lsx", lsx_vslli_h, is::simd_shl, m128i, i16x8); impl_vuv!("lsx", lsx_vslli_w, is::simd_shl, m128i, i32x4); @@ -405,6 +435,10 @@ impl_vuv!("lsx", lsx_vsrli_b, is::simd_shr, m128i, u8x16); impl_vuv!("lsx", lsx_vsrli_h, is::simd_shr, m128i, u16x8); impl_vuv!("lsx", lsx_vsrli_w, is::simd_shr, m128i, u32x4); impl_vuv!("lsx", lsx_vsrli_d, is::simd_shr, m128i, u64x2); +impl_vuv!("lsx", lsx_vrotri_b, ls::simd_rotr, m128i, u8x16); +impl_vuv!("lsx", lsx_vrotri_h, ls::simd_rotr, m128i, u16x8); +impl_vuv!("lsx", lsx_vrotri_w, ls::simd_rotr, m128i, u32x4); +impl_vuv!("lsx", lsx_vrotri_d, ls::simd_rotr, m128i, u64x2); impl_vuv!("lsx", lsx_vaddi_bu, is::simd_add, m128i, u8x16, 5); impl_vuv!("lsx", lsx_vaddi_hu, is::simd_add, m128i, u16x8, 5); impl_vuv!("lsx", lsx_vaddi_wu, is::simd_add, m128i, u32x4, 5); diff --git a/library/stdarch/crates/core_arch/src/loongarch64/simd.rs b/library/stdarch/crates/core_arch/src/loongarch64/simd.rs index 32f191509be27..58dd016400432 100644 --- a/library/stdarch/crates/core_arch/src/loongarch64/simd.rs +++ b/library/stdarch/crates/core_arch/src/loongarch64/simd.rs @@ -35,16 +35,26 @@ impl_simd_ext!(u8x16, u8); impl_simd_ext!(u8x32, u8); impl_simd_ext!(i16x8, i16); impl_simd_ext!(i16x16, i16); +impl_simd_ext!(i16x32, i16); impl_simd_ext!(u16x8, u16); impl_simd_ext!(u16x16, u16); +impl_simd_ext!(u16x32, u16); impl_simd_ext!(i32x4, i32); impl_simd_ext!(i32x8, i32); +impl_simd_ext!(i32x16, i32); impl_simd_ext!(u32x4, u32); impl_simd_ext!(u32x8, u32); +impl_simd_ext!(u32x16, u32); impl_simd_ext!(i64x2, i64); impl_simd_ext!(i64x4, i64); +impl_simd_ext!(i64x8, i64); impl_simd_ext!(u64x2, u64); impl_simd_ext!(u64x4, u64); +impl_simd_ext!(u64x8, u64); +impl_simd_ext!(i128x2, i128); +impl_simd_ext!(u128x2, u128); +impl_simd_ext!(i128x4, i128); +impl_simd_ext!(u128x4, u128); #[inline(always)] #[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] @@ -108,6 +118,42 @@ pub(super) const unsafe fn simd_fnmsub(a: T, b: T, c: T) -> T { is::simd_neg(ls::simd_fmsub(a, b, c)) } +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_frecip_s(a: T) -> T { + is::simd_div(is::simd_splat(1.0f32), a) +} + +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_frecip_d(a: T) -> T { + is::simd_div(is::simd_splat(1.0f64), a) +} + +#[inline(always)] +pub(super) unsafe fn simd_frsqrt_s(a: T) -> T { + ls::simd_frecip_s(is::simd_fsqrt(a)) +} + +#[inline(always)] +pub(super) unsafe fn simd_frsqrt_d(a: T) -> T { + ls::simd_frecip_d(is::simd_fsqrt(a)) +} + +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_ld(a: *const i8) -> T { + let a = a.offset(I as isize) as *const T; + core::ptr::read_unaligned(a) +} + +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_ldx(a: *const i8, b: i64) -> T { + let a = a.offset(b as isize) as *const T; + core::ptr::read_unaligned(a) +} + #[inline(always)] #[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] pub(super) const unsafe fn simd_madd(a: T, b: T, c: T) -> T { @@ -120,6 +166,18 @@ pub(super) const unsafe fn simd_msub(a: T, b: T, c: T) -> T { is::simd_sub(a, is::simd_mul(b, c)) } +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_muh(a: T, b: T) -> T { + let a: W = is::simd_cast(a); + let b: W = is::simd_cast(b); + let p = is::simd_mul(a, b); + is::simd_cast(is::simd_shr( + p, + ls::simd_splat((size_of::() * 8 / 2) as i64), + )) +} + #[inline(always)] #[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] pub(super) const unsafe fn simd_nor(a: T, b: T) -> T { @@ -138,6 +196,15 @@ pub(super) const unsafe fn simd_orn(a: T, b: T) -> T { is::simd_or(a, ls::simd_not(b)) } +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_rotr(a: T, b: T) -> T { + let m = (size_of::() * 8 - 1) as i64; + let r = is::simd_and(b, ls::simd_splat(m)); + let l = is::simd_and(is::simd_sub(ls::simd_splat(m + 1), r), ls::simd_splat(m)); + is::simd_or(is::simd_shr(a, r), is::simd_shl(a, l)) +} + #[inline(always)] #[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] pub(super) const unsafe fn simd_shl(a: T, b: T) -> T { @@ -158,6 +225,20 @@ pub(super) const unsafe fn simd_splat(a: i64) -> T { T::splat(a) } +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_st(a: T, b: *mut i8) { + let b = b.offset(I as isize) as *mut T; + core::ptr::write_unaligned(b, a); +} + +#[inline(always)] +#[rustc_const_unstable(feature = "stdarch_const_helpers", issue = "none")] +pub(super) const unsafe fn simd_stx(a: T, b: *mut i8, c: i64) { + let b = b.offset(c as isize) as *mut T; + core::ptr::write_unaligned(b, a); +} + macro_rules! impl_vv { ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ty) => { #[inline] @@ -191,6 +272,36 @@ macro_rules! impl_gv { pub(super) use impl_gv; +macro_rules! impl_ggv { + ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $gty:ty, $xty:ty, unsafe) => { + #[inline] + #[target_feature(enable = $ft)] + #[unstable(feature = "stdarch_loongarch", issue = "117427")] + pub unsafe fn $name(a: $gty, b: $xty) -> $oty { + let r: $ity = $op(a, b); + transmute(r) + } + }; +} + +pub(super) use impl_ggv; + +macro_rules! impl_gsv { + ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr, const, unsafe) => { + #[inline] + #[target_feature(enable = $ft)] + #[rustc_legacy_const_generics(1)] + #[unstable(feature = "stdarch_loongarch", issue = "117427")] + pub unsafe fn $name(a: $gty) -> $oty { + static_assert_simm_bits!(IMM, $ibs); + let r: $ity = $op::(a); + transmute(r) + } + }; +} + +pub(super) use impl_gsv; + macro_rules! impl_sv { ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $ibs:expr) => { #[inline] @@ -223,10 +334,51 @@ macro_rules! impl_vvv { } } }; + ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ty, $wty:ty) => { + #[inline] + #[target_feature(enable = $ft)] + #[unstable(feature = "stdarch_loongarch", issue = "117427")] + pub fn $name(a: $oty, b: $oty) -> $oty { + unsafe { + let a: $ity = transmute(a); + let b: $ity = transmute(b); + let r: $ity = $op::<$ity, $wty>(a, b); + transmute(r) + } + } + }; } pub(super) use impl_vvv; +macro_rules! impl_vgg { + ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident, $gty:ty, $xty:ty, unsafe) => { + #[inline] + #[target_feature(enable = $ft)] + #[unstable(feature = "stdarch_loongarch", issue = "117427")] + pub unsafe fn $name(a: $oty, b: $gty, c: $xty) { + $op(a, b, c); + } + }; +} + +pub(super) use impl_vgg; + +macro_rules! impl_vgs { + ($ft:literal, $name:ident, $op:ident, $oty:ty, $ity:ident, $gty:ty, $ibs:expr, const, unsafe) => { + #[inline] + #[target_feature(enable = $ft)] + #[rustc_legacy_const_generics(2)] + #[unstable(feature = "stdarch_loongarch", issue = "117427")] + pub unsafe fn $name(a: $oty, b: $gty) { + static_assert_simm_bits!(IMM, $ibs); + $op::(a, b); + } + }; +} + +pub(super) use impl_vgs; + macro_rules! impl_vuv { ($ft:literal, $name:ident, $op:path, $oty:ty, $ity:ident) => { #[inline] diff --git a/library/stdarch/crates/core_arch/src/simd.rs b/library/stdarch/crates/core_arch/src/simd.rs index 30c3125f5f8b8..08ee17548a01d 100644 --- a/library/stdarch/crates/core_arch/src/simd.rs +++ b/library/stdarch/crates/core_arch/src/simd.rs @@ -28,11 +28,13 @@ unsafe impl SimdElement for u8 {} unsafe impl SimdElement for u16 {} unsafe impl SimdElement for u32 {} unsafe impl SimdElement for u64 {} +unsafe impl SimdElement for u128 {} unsafe impl SimdElement for i8 {} unsafe impl SimdElement for i16 {} unsafe impl SimdElement for i32 {} unsafe impl SimdElement for i64 {} +unsafe impl SimdElement for i128 {} unsafe impl SimdElement for f16 {} unsafe impl SimdElement for f32 {} @@ -371,11 +373,13 @@ pub(crate) type u8x32 = Simd; pub(crate) type u16x16 = Simd; pub(crate) type u32x8 = Simd; pub(crate) type u64x4 = Simd; +pub(crate) type u128x2 = Simd; pub(crate) type i8x32 = Simd; pub(crate) type i16x16 = Simd; pub(crate) type i32x8 = Simd; pub(crate) type i64x4 = Simd; +pub(crate) type i128x2 = Simd; pub(crate) type f16x16 = Simd; pub(crate) type f32x8 = Simd; @@ -391,11 +395,13 @@ pub(crate) type u8x64 = Simd; pub(crate) type u16x32 = Simd; pub(crate) type u32x16 = Simd; pub(crate) type u64x8 = Simd; +pub(crate) type u128x4 = Simd; pub(crate) type i8x64 = Simd; pub(crate) type i16x32 = Simd; pub(crate) type i32x16 = Simd; pub(crate) type i64x8 = Simd; +pub(crate) type i128x4 = Simd; pub(crate) type f16x32 = Simd; pub(crate) type f32x16 = Simd; diff --git a/library/stdarch/crates/core_arch/src/x86/sse2.rs b/library/stdarch/crates/core_arch/src/x86/sse2.rs index bd7e4df2138d5..5e8fe959c301a 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse2.rs @@ -1445,7 +1445,7 @@ pub unsafe fn _mm_stream_si128(mem_addr: *mut __m128i, a: __m128i) { ); } -/// Stores a 32-bit integer value in the specified memory location. +/// Stores a 32-bit integer value in a 4-byte aligned memory location. /// To minimize caching, the data is flagged as non-temporal (unlikely to be /// used again soon). /// diff --git a/library/stdarch/crates/core_arch/src/x86_64/amx.rs b/library/stdarch/crates/core_arch/src/x86_64/amx.rs index cddae18b7684d..f97acf1d3f746 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/amx.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/amx.rs @@ -632,50 +632,6 @@ pub unsafe fn __tile_stream_loaddrs(dst: *mut __tile1024i, base: *const u8, stri (*dst).tile = tileloaddrst164_internal((*dst).rows, (*dst).colsb, base, stride as u64); } -/// Perform matrix multiplication of two tiles a and b, containing packed single precision (32-bit) -/// floating-point elements, which are converted to TF32 (tensor-float32) format, and accumulate the -/// results into a packed single precision tile. -/// For each possible combination of (row of a, column of b), it performs -/// - convert to TF32 -/// - multiply the corresponding elements of a and b -/// - accumulate the results into the corresponding row and column of dst using round-to-nearest-even -/// rounding mode. -/// Output FP32 denormals are always flushed to zero, input single precision denormals are always -/// handled and *not* treated as zero. -#[inline] -#[rustc_legacy_const_generics(0, 1, 2)] -#[target_feature(enable = "amx-tf32")] -#[cfg_attr( - all(test, not(target_vendor = "apple")), - assert_instr(tmmultf32ps, DST = 0, A = 1, B = 2) -)] -#[unstable(feature = "x86_amx_intrinsics", issue = "126622")] -pub unsafe fn _tile_mmultf32ps() { - static_assert_uimm_bits!(DST, 3); - static_assert_uimm_bits!(A, 3); - static_assert_uimm_bits!(B, 3); - tmmultf32ps(DST as i8, A as i8, B as i8); -} - -/// Perform matrix multiplication of two tiles a and b, containing packed single precision (32-bit) -/// floating-point elements, which are converted to TF32 (tensor-float32) format, and accumulate the -/// results into a packed single precision tile. -/// For each possible combination of (row of a, column of b), it performs -/// - convert to TF32 -/// - multiply the corresponding elements of a and b -/// - accumulate the results into the corresponding row and column of dst using round-to-nearest-even -/// rounding mode. -/// Output FP32 denormals are always flushed to zero, input single precision denormals are always -/// handled and *not* treated as zero. -/// The shape of the tile is specified in the struct of [`__tile1024i`]. The register of the tile is allocated by the compiler. -#[inline] -#[target_feature(enable = "amx-tf32")] -#[cfg_attr(all(test, not(target_vendor = "apple")), assert_instr(tmmultf32ps))] -#[unstable(feature = "x86_amx_intrinsics", issue = "126622")] -pub unsafe fn __tile_mmultf32ps(dst: *mut __tile1024i, a: __tile1024i, b: __tile1024i) { - (*dst).tile = tmmultf32ps_internal(a.rows, b.colsb, a.colsb, (*dst).tile, a.tile, b.tile); -} - /// Moves a row from a tile register to a zmm register, converting the packed 32-bit signed integer /// elements to packed single-precision (32-bit) floating-point elements. #[inline] @@ -1037,11 +993,6 @@ unsafe extern "unadjusted" { #[link_name = "llvm.x86.tileloaddrst164.internal"] fn tileloaddrst164_internal(rows: u16, colsb: u16, base: *const u8, stride: u64) -> Tile; - #[link_name = "llvm.x86.tmmultf32ps"] - fn tmmultf32ps(dst: i8, a: i8, b: i8); - #[link_name = "llvm.x86.tmmultf32ps.internal"] - fn tmmultf32ps_internal(m: u16, n: u16, k: u16, dst: Tile, a: Tile, b: Tile) -> Tile; - #[link_name = "llvm.x86.tcvtrowd2ps"] fn tcvtrowd2ps(tile: i8, row: u32) -> f32x16; #[link_name = "llvm.x86.tcvtrowd2psi"] @@ -2368,53 +2319,4 @@ mod tests { } } } - - #[simd_test(enable = "amx-tf32")] - fn test_tile_mmultf32ps() { - unsafe { - _init_amx(); - let a: [[f32; 16]; 16] = array::from_fn(|i| [i as _; _]); - let b: [[f32; 16]; 16] = [array::from_fn(|j| j as _); _]; - let mut res = [[0.0; 16]; 16]; - - let mut config = __tilecfg::default(); - config.palette = 1; - (0..=2).for_each(|i| { - config.colsb[i] = 64; - config.rows[i] = 16; - }); - _tile_loadconfig(config.as_ptr()); - _tile_zero::<0>(); - _tile_loadd::<1>(a.as_ptr().cast(), 64); - _tile_loadd::<2>(b.as_ptr().cast(), 64); - _tile_mmultf32ps::<0, 1, 2>(); - _tile_stored::<0>(res.as_mut_ptr().cast(), 64); - _tile_release(); - - let expected = array::from_fn(|i| array::from_fn(|j| 16.0 * i as f32 * j as f32)); - assert_eq!(res, expected); - } - } - - #[simd_test(enable = "amx-tf32")] - fn test__tile_mmultf32ps() { - unsafe { - _init_amx(); - let a: [[f32; 16]; 16] = array::from_fn(|i| [i as _; _]); - let b: [[f32; 16]; 16] = [array::from_fn(|j| j as _); _]; - let mut res = [[0.0; 16]; 16]; - - let mut tile_a = __tile1024i::zeroed(16, 64); - let mut tile_b = __tile1024i::zeroed(16, 64); - let mut tile_c = __tile1024i::zeroed(16, 64); - - __tile_loadd(&mut tile_a, a.as_ptr().cast(), 64); - __tile_loadd(&mut tile_b, b.as_ptr().cast(), 64); - __tile_mmultf32ps(&mut tile_c, tile_a, tile_b); - __tile_stored(res.as_mut_ptr().cast(), 64, tile_c); - - let expected = array::from_fn(|i| array::from_fn(|j| 16.0 * i as f32 * j as f32)); - assert_eq!(res, expected); - } - } } diff --git a/library/stdarch/crates/core_arch/src/x86_64/sse2.rs b/library/stdarch/crates/core_arch/src/x86_64/sse2.rs index c4768cedbfa6b..ba1d811fe5b20 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/sse2.rs @@ -59,7 +59,7 @@ pub fn _mm_cvttsd_si64x(a: __m128d) -> i64 { _mm_cvttsd_si64(a) } -/// Stores a 64-bit integer value in the specified memory location. +/// Stores a 64-bit integer value in an 8-byte aligned memory location. /// To minimize caching, the data is flagged as non-temporal (unlikely to be /// used again soon). /// diff --git a/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs b/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs index 26f861ca64b62..013c20f2db594 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/json_parser.rs @@ -58,22 +58,14 @@ struct JsonIntrinsic { _instructions: Option>>, } -pub fn get_neon_intrinsics( - filename: &Path, -) -> Result>, Box> { +pub fn get_intrinsics(filename: &Path) -> Result>, Box> { let file = std::fs::File::open(filename)?; let reader = std::io::BufReader::new(file); let json: Vec = serde_json::from_reader(reader).expect("Couldn't parse JSON"); let parsed = json .into_iter() - .filter_map(|intr| { - if intr.simd_isa == "Neon" { - Some(json_to_intrinsic(intr).expect("Couldn't parse JSON")) - } else { - None - } - }) + .map(|intr| json_to_intrinsic(intr).expect("Couldn't parse JSON")) .collect(); Ok(parsed) } @@ -121,8 +113,14 @@ fn json_to_intrinsic( } }); - let mut arg = - Argument::::new(i, String::from(arg_name), ArmType(arg_ty), constraint); + let is_predicate = arg_name == "pg"; + let mut arg = Argument::::new( + i, + String::from(arg_name), + ArmType(arg_ty), + constraint, + is_predicate, + ); // The JSON doesn't list immediates as const let IntrinsicType { diff --git a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs index a60e0ff1551a3..4054d02502bfa 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/mod.rs @@ -2,12 +2,14 @@ mod intrinsic; mod json_parser; mod types; -use crate::common::SupportedArchitecture; +use crate::common::argument::Argument; use crate::common::cli::{CcArgStyle, ProcessedCli}; use crate::common::intrinsic::Intrinsic; -use crate::common::intrinsic_helpers::{SimdLen, TypeKind}; +use crate::common::intrinsic_helpers::{SimdLen, TypeDefinition, TypeKind}; +use crate::common::values::test_values_array_name; +use crate::common::{PASSES, PREDICATE_LOCAL, SupportedArchitecture}; use intrinsic::ArmType; -use json_parser::get_neon_intrinsics; +use json_parser::get_intrinsics; #[derive(PartialEq)] pub struct Arm(Vec>); @@ -29,12 +31,21 @@ impl SupportedArchitecture for Arm { #include #include #include +#ifdef __ARM_FEATURE_SVE +#include +#endif "#; const RUST_PRELUDE: &str = RUST_PRELUDE; fn c_compiler_flags(&self, cli_options: &ProcessedCli) -> Vec<&str> { // GCC uses an extra `-` in the arch name + let big_endian = cli_options.target.starts_with("aarch64_be"); + let a32 = cli_options.target.starts_with("armv7"); match cli_options.cc_arg_style { + CcArgStyle::Clang if !a32 && !big_endian => vec![ + "-march=armv8.6a+crypto+crc+dotprod+fp16+sve2-aes+sve2-sm4+sve2-sha3+sve2-bitperm+\ + f32mm+f64mm+sve2p1", + ], CcArgStyle::Clang => vec!["-march=armv8.6a+crypto+crc+dotprod+fp16"], // SVE tests aren't run under GCC so there are no target features added for SVE CcArgStyle::Gcc => vec!["-march=armv8.6-a+crypto+crc+dotprod+fp16+sha3+sm4"], @@ -45,7 +56,7 @@ impl SupportedArchitecture for Arm { let big_endian = cli_options.target.starts_with("aarch64_be"); let a32 = cli_options.target.starts_with("armv7"); let mut intrinsics = - get_neon_intrinsics(&cli_options.filename).expect("Error parsing input file"); + get_intrinsics(&cli_options.filename).expect("Error parsing input file"); intrinsics.sort_by(|a, b| a.name.cmp(&b.name)); intrinsics.dedup(); @@ -69,13 +80,13 @@ impl SupportedArchitecture for Arm { let has_sve_arg = i .arguments .iter() - .any(|a| a.ty.simd_len == Some(SimdLen::Scalable)); + .any(|a| a.ty.num_lanes() == SimdLen::Scalable); !(has_f16_arg && has_sve_arg) }) .filter(|i| { let has_f16_ret = i.results.kind() == TypeKind::Float && i.results.bit_len == Some(16); - let has_sve_ret = i.results.simd_len == Some(SimdLen::Scalable); + let has_sve_ret = i.results.num_lanes() == SimdLen::Scalable; !(has_f16_ret && has_sve_ret) }) // Skip `svqcvtn{u,}n*_x2` intrinsics - not yet implemented! @@ -129,6 +140,35 @@ impl SupportedArchitecture for Arm { Self(intrinsics) } + + fn predicate_function(size: u32) -> String { + format!("svptrue_b{size}()") + } + + fn load_call(arg: &Argument, idx: usize) -> String { + let name = arg.generate_name(); + let load = arg.ty.load_function(); + let ptr = format!( + "{vals_name}.as_ptr().add((i+{idx}) % {PASSES}) as _", + vals_name = test_values_array_name(&arg.ty) + ); + + match arg.ty.num_lanes() { + // If the load is of a `svbool_t`, then we load a `svint8_t` and + SimdLen::Scalable if matches!(arg.ty.kind(), TypeKind::Bool) => { + format!( + r#" +let {name} = {load}({PREDICATE_LOCAL}, {ptr}); +let {name} = svcmpne_n_s8({PREDICATE_LOCAL}, {name}, 0); + "# + ) + } + // If this load is of a scalable vector, then prepend an additional argument + // containing the predicate for the load. + SimdLen::Scalable => format!("let {name} = {load}({PREDICATE_LOCAL}, {ptr});"), + SimdLen::Fixed(..) => format!("let {name} = {load}({ptr});"), + } + } } const RUST_PRELUDE: &str = r#" @@ -140,6 +180,7 @@ const RUST_PRELUDE: &str = r#" #![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_ftts))] #![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_feat_lut))] #![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(stdarch_neon_fp8))] +#![cfg_attr(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"), feature(stdarch_aarch64_sve))] #![cfg_attr(any(target_arch = "aarch64", target_arch = "arm64ec"), feature(faminmax))] #![feature(stdarch_neon_f16)] @@ -148,4 +189,116 @@ use core_arch::arch::aarch64::*; #[cfg(target_arch = "arm")] use core_arch::arch::arm::*; + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +const fn svpattern_from_i32(value: i32) -> svpattern { + match value { + 0 => svpattern::SV_POW2, + 1 => svpattern::SV_VL1, + 2 => svpattern::SV_VL2, + 3 => svpattern::SV_VL3, + 4 => svpattern::SV_VL4, + 5 => svpattern::SV_VL5, + 6 => svpattern::SV_VL6, + 7 => svpattern::SV_VL7, + 8 => svpattern::SV_VL8, + 9 => svpattern::SV_VL16, + 10 => svpattern::SV_VL32, + 11 => svpattern::SV_VL64, + 12 => svpattern::SV_VL128, + 13 => svpattern::SV_VL256, + 29 => svpattern::SV_MUL4, + 30 => svpattern::SV_MUL3, + 31 => svpattern::SV_ALL, + _ => unreachable!(), + } +} + +#[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] +const fn svprfop_from_i32(value: i32) -> svprfop { + match value { + 0 => svprfop::SV_PLDL1KEEP, + 1 => svprfop::SV_PLDL1STRM, + 2 => svprfop::SV_PLDL2KEEP, + 3 => svprfop::SV_PLDL2STRM, + 4 => svprfop::SV_PLDL3KEEP, + 5 => svprfop::SV_PLDL3STRM, + 8 => svprfop::SV_PSTL1KEEP, + 9 => svprfop::SV_PSTL1STRM, + 10 => svprfop::SV_PSTL2KEEP, + 11 => svprfop::SV_PSTL2STRM, + 12 => svprfop::SV_PSTL3KEEP, + 13 => svprfop::SV_PSTL3STRM, + _ => unreachable!(), + } +} + +macro_rules! debug_print_integral { + ($($name:ident => ($ty:ty, $svptrue_fn:ident, $svcnt_fn:ident, $svst_fn:ident)),*) => { + $( + #[inline] + #[target_feature(enable = "sve")] + #[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] + pub fn $name(v: $ty) -> String { + unsafe { + let __pred = $svptrue_fn(); + let __num_elems = $svcnt_fn() as usize; + let mut __buf = std::vec::Vec::with_capacity(__num_elems); + $svst_fn(__pred, __buf.as_mut_ptr(), v); + __buf.set_len(__num_elems); + format!( + "[{}]", + __buf.iter().map(|el| el.to_string()).collect::>().join(", ") + ) + } + } + )* + } +} + +debug_print_integral! { + debug_print_f32 => (svfloat32_t, svptrue_b32, svcntw, svst1_f32), + debug_print_f64 => (svfloat64_t, svptrue_b64, svcntd, svst1_f64), + debug_print_s8 => (svint8_t, svptrue_b8, svcntb, svst1_s8), + debug_print_s16 => (svint16_t, svptrue_b16, svcnth, svst1_s16), + debug_print_s32 => (svint32_t, svptrue_b32, svcntw, svst1_s32), + debug_print_s64 => (svint64_t, svptrue_b64, svcntd, svst1_s64), + debug_print_u8 => (svuint8_t, svptrue_b8, svcntb, svst1_u8), + debug_print_u16 => (svuint16_t, svptrue_b16, svcnth, svst1_u16), + debug_print_u32 => (svuint32_t, svptrue_b32, svcntw, svst1_u32), + debug_print_u64 => (svuint64_t, svptrue_b64, svcntd, svst1_u64) +} + +macro_rules! debug_print_bool { + ($($name:ident => ($ty:ty, $svst_fn:ident, $svdup_fn:ident)),*) => { + $( + #[inline] + #[target_feature(enable = "sve")] + #[cfg(all(any(target_arch = "aarch64", target_arch = "arm64ec"), target_endian = "little"))] + pub fn $name(v: $ty) -> String { + unsafe { + let __num_elems = svcntb() as usize; + let mut __buf = std::vec::Vec::with_capacity(__num_elems); + $svst_fn(v, __buf.as_mut_ptr(), $svdup_fn(1)); + __buf.set_len(__num_elems); + format!( + "[{}]", + __buf.iter() + .map(|el| *el == 1) + .map(|el| el.to_string()) + .collect::>() + .join(", ") + ) + } + } + )* + } +} + +debug_print_bool! { + debug_print_b8 => (svbool_t, svst1_u8, svdup_n_u8), + debug_print_b16 => (svbool_t, svst1_u16, svdup_n_u16), + debug_print_b32 => (svbool_t, svst1_u32, svdup_n_u32), + debug_print_b64 => (svbool_t, svst1_u64, svdup_n_u64) +} "#; diff --git a/library/stdarch/crates/intrinsic-test/src/arm/types.rs b/library/stdarch/crates/intrinsic-test/src/arm/types.rs index 7754e9ec2d0dd..7481bb4aeb30d 100644 --- a/library/stdarch/crates/intrinsic-test/src/arm/types.rs +++ b/library/stdarch/crates/intrinsic-test/src/arm/types.rs @@ -1,5 +1,9 @@ use super::intrinsic::ArmType; -use crate::common::intrinsic_helpers::{IntrinsicType, Sign, SimdLen, TypeDefinition, TypeKind}; +use crate::common::PREDICATE_LOCAL; +use crate::common::intrinsic_helpers::{ + IntrinsicType, Sign, SimdLen, TypeDefinition, TypeKind, default_fixed_vector_comparison, +}; +use itertools::Itertools; impl TypeDefinition for ArmType { /// Gets a string containing the typename for this type in C format. @@ -70,32 +74,137 @@ impl TypeDefinition for ArmType { } } + fn rust_scalar_type_for_test_value_array(&self) -> String { + if self.kind() == TypeKind::Bool && self.num_lanes() == SimdLen::Scalable { + let mut ty = self.clone(); + ty.kind = TypeKind::Int(Sign::Signed); + ty.rust_scalar_type() + } else { + self.rust_scalar_type() + } + } + /// Determines the load function for this type. fn load_function(&self) -> String { - if let IntrinsicType { - kind: k, - bit_len: Some(bl), - vec_len, - .. - } = **self - { - let quad = if self.num_lanes() * bl > 64 { "q" } else { "" }; + if let Some(bl) = self.bit_len { + match self.num_lanes() { + SimdLen::Scalable => { + format!( + "svld{len}_{type}{bl}", + len = self.num_vectors(), + type = self.rust_intrinsic_name_prefix(), + ) + } + SimdLen::Fixed(num_lanes) => { + format!( + "vld{len}{quad}_{type}{bl}", + quad = if num_lanes * bl > 64 { "q" } else { "" }, + len = self.num_vectors(), + type = self.rust_intrinsic_name_prefix(), + ) + } + } + } else { + todo!("load_function IntrinsicType: {self:#?}") + } + } + + fn comparison_function(&self) -> String { + if let SimdLen::Fixed(num_lanes) = self.num_lanes() { + return default_fixed_vector_comparison(self, num_lanes); + } + + if self.kind() == TypeKind::Bool { + // There isn't a `svcmpeq` for `svbool_t` and there aren't `svboolxN_t` types, so just + // do an XOR and test it is empty. + return format!( + r#" +let __eq = sveor_b_z({PREDICATE_LOCAL}, __rust_return_value, __c_return_value); +assert!(!svptest_any({PREDICATE_LOCAL}, __eq), "{{}}", id); + "# + ); + } + + // Returns `of` when `num_vectors == 1` otherwise returns the appropriate `svget` invocation + // for `of`. + let get = |num_vectors: u32, idx: u32, from: &'static str| -> String { + if num_vectors == 1 { + return from.to_string(); + } format!( - "vld{len}{quad}_{type}{size}", - type = match k { - TypeKind::Int(Sign::Unsigned) => "u", - TypeKind::Int(Sign::Signed) => "s", - TypeKind::Float => "f", - TypeKind::Poly => "p", - x => todo!("get_load_function TypeKind: {x:#?}"), - }, - size = bl, - quad = quad, - len = vec_len.unwrap_or(1), + "svget{num_vectors}_{ty}{bl}::<{idx}>({from})", + ty = self.rust_intrinsic_name_prefix(), + bl = self.inner_size(), ) - } else { - todo!("load_function IntrinsicType: {self:#?}") + }; + + let n = self.num_vectors(); + (0..n) + .format_with("\n", |i, fmt| { + match self.kind() { + TypeKind::Float | TypeKind::BFloat => { + // Floats need special handling because `NaN != NaN` normally - this + // effectively does `(rust == c) || (isnan(rust) && isnan(c))` + fmt(&format_args!( + r#" +let __rust_eq_return_value = {rust_return_value}; +let __c_eq_return_value = {c_return_value}; +let __eq_sans_nan = svcmpeq_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __c_eq_return_value); +let __rust_nan = svcmpuo_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __rust_eq_return_value); +let __c_nan = svcmpuo_{ty}{bl}({PREDICATE_LOCAL}, __c_eq_return_value, __c_eq_return_value); +let __both_nan = svand_b_z({PREDICATE_LOCAL}, __rust_nan, __c_nan); +let __eq = svorr_b_z({PREDICATE_LOCAL}, __eq_sans_nan, __both_nan); +if !svptest_any(__pred, __eq) {{ + let __rust_pretty = debug_print_{ty}{bl}(__rust_eq_return_value); + let __c_pretty = debug_print_{ty}{bl}(__c_eq_return_value); + panic!("{{}}-{i_plus_one}/{n}\nRust: {{__rust_pretty}}\nC: {{__c_pretty}}", id); +}} +"#, + ty = self.rust_intrinsic_name_prefix(), + bl = self.inner_size(), + rust_return_value = get(n, i, "__rust_return_value"), + c_return_value = get(n, i, "__c_return_value"), + i_plus_one = i + 1, // so that the output is "1/2" and "2/2" + )) + } + _ => { + // Most types can just use `svcmpeq` + fmt(&format_args!( + r#" +let __rust_eq_return_value = {rust_return_value}; +let __c_eq_return_value = {c_return_value}; +let __eq = svcmpeq_{ty}{bl}({PREDICATE_LOCAL}, __rust_eq_return_value, __c_eq_return_value); +if !svptest_any(__pred, __eq) {{ + let __rust_pretty = debug_print_{ty}{bl}(__rust_eq_return_value); + let __c_pretty = debug_print_{ty}{bl}(__c_eq_return_value); + panic!("{{}}-{i_plus_one}/{n}\nRust: {{__rust_pretty}}\nC: {{__c_pretty}}", id); +}} +"#, + ty = self.rust_intrinsic_name_prefix(), + bl = self.inner_size(), + rust_return_value = get(n, i, "__rust_return_value"), + c_return_value = get(n, i, "__c_return_value"), + i_plus_one = i + 1, // so that the output is "1/2" and "2/2" + )) + } + } + }) + .to_string() + } +} + +impl ArmType { + /// Returns the Rust prefix for the name of an intrinsic with this type kind (i.e. `s` for + /// `i16`, or `u` for `u16`). For type kinds without any bit length at the end (e.g. `bool`), + /// returns the whole type name. + pub fn rust_intrinsic_name_prefix(&self) -> &str { + match self.kind() { + TypeKind::Char(Sign::Signed) => "s", + TypeKind::Int(Sign::Signed) => "s", + TypeKind::Poly => "p", + TypeKind::Bool => "s", + _ => self.kind.rust_prefix(), } } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/argument.rs b/library/stdarch/crates/intrinsic-test/src/common/argument.rs index 4d38bce327930..10d9224183377 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/argument.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/argument.rs @@ -4,9 +4,9 @@ use crate::common::SupportedArchitecture; use crate::common::intrinsic_helpers::TypeKind; use crate::common::values::test_values_array_name; -use super::PASSES; use super::constraint::Constraint; use super::intrinsic_helpers::TypeDefinition; +use super::{PASSES, PREDICATE_LOCAL}; /// An argument for the intrinsic. #[derive(Debug, PartialEq, Clone)] @@ -19,18 +19,27 @@ pub struct Argument { pub ty: A::Type, /// Any constraints that are on this argument pub constraint: Option, + /// Is the argument a predicate for a scalable intrinsic? + pub is_predicate: bool, } impl Argument where A: SupportedArchitecture, { - pub fn new(pos: usize, name: String, ty: A::Type, constraint: Option) -> Self { + pub fn new( + pos: usize, + name: String, + ty: A::Type, + constraint: Option, + is_predicate: bool, + ) -> Self { Argument { pos, name, ty, constraint, + is_predicate, } } @@ -38,8 +47,14 @@ where self.ty.c_type() } + /// Generates local variable name for the value passed to this argument pub fn generate_name(&self) -> String { - format!("{}_val", self.name) + // The same predicate is used for scalable intrinsic invocations + if self.is_predicate { + format!("{PREDICATE_LOCAL}") + } else { + format!("{}_val", self.name) + } } pub fn is_simd(&self) -> bool { @@ -176,15 +191,11 @@ where pub fn load_values_rust(&self) -> String { self.iter() .filter(|&arg| !arg.has_constraint()) + .filter(|&arg| !arg.is_predicate) .enumerate() .map(|(idx, arg)| { if arg.is_simd() { - format!( - "let {name} = {load}({vals_name}.as_ptr().add((i+{idx}) % {PASSES}) as _);", - name = arg.generate_name(), - vals_name = test_values_array_name(&arg.ty), - load = arg.ty.load_function(), - ) + A::load_call(arg, idx) } else { format!( "let {name} = {vals_name}[(i+{idx}) % {PASSES}];", diff --git a/library/stdarch/crates/intrinsic-test/src/common/constraint.rs b/library/stdarch/crates/intrinsic-test/src/common/constraint.rs index ab52d866ab20a..c7d37da2adcbb 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/constraint.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/constraint.rs @@ -1,6 +1,7 @@ -use serde::Deserialize; use std::ops::Range; +use serde::Deserialize; + /// Describes the values to test for a const generic parameter #[derive(Debug, PartialEq, Clone, Deserialize)] pub enum Constraint { @@ -23,21 +24,53 @@ pub enum Constraint { SvImmRotationAdd, } -impl Constraint { - /// Returns an iterator over the values of this constraint - pub fn iter(&self) -> Box + '_> { +/// Workaround to enable the `Constraint::into_iter` to return an iterator that implements `Clone`, +/// so that it can be used with `Itertools::multi_cartesian_product`. +/// +/// With the different iterator types, returning `Box + '_>` would the +/// idiomatic approach, but this can't be made to implement `Clone`. Given the limited number +/// of iterator types used and their relative lack of complexity, wrapping them all in an enum isn't +/// too bad. +#[derive(Clone)] +pub enum ConstraintIterator<'a> { + Once(std::iter::Once), + Range(std::ops::Range), + Copied(std::iter::Copied>), + Chain(std::iter::Chain, std::ops::RangeInclusive>), + StepBy(std::iter::StepBy>), +} + +impl<'a> Iterator for ConstraintIterator<'a> { + type Item = i64; + + fn next(&mut self) -> Option { + match self { + ConstraintIterator::Once(once) => once.next(), + ConstraintIterator::Range(range) => range.next(), + ConstraintIterator::Copied(copied) => copied.next(), + ConstraintIterator::Chain(chain) => chain.next(), + ConstraintIterator::StepBy(step_by) => step_by.next(), + } + } +} + +impl<'a> IntoIterator for &'a Constraint { + type Item = i64; + type IntoIter = ConstraintIterator<'a>; + + fn into_iter(self) -> Self::IntoIter { match self { - Constraint::Equal(i) => Box::new(std::iter::once(*i)), - Constraint::Range(range) => Box::new(range.clone()), - Constraint::Set(items) => Box::new(items.iter().copied().chain(Range::default())), + Constraint::Equal(i) => ConstraintIterator::Once(std::iter::once(*i)), + Constraint::Range(range) => ConstraintIterator::Range(range.clone()), + Constraint::Set(items) => ConstraintIterator::Copied(items.iter().copied()), // These values are discriminants of the `svpattern` enum - Constraint::SvPattern => Box::new((0..=13).chain(29..=31)), + Constraint::SvPattern => ConstraintIterator::Chain((0..=13).chain(29..=31)), // These values are discriminants of the `svprfop` enum - Constraint::SvPrefetchOp => Box::new((0..=5).chain(8..=14)), + Constraint::SvPrefetchOp => ConstraintIterator::Chain((0..=5).chain(8..=14)), // Valid rotations for intrinsics operating on complex pairs: 0, 90, 180, 270 - Constraint::SvImmRotation => Box::new((0..=270).step_by(90)), + Constraint::SvImmRotation => ConstraintIterator::StepBy((0..=270).step_by(90)), // Valid rotations for `svcadd` and `svqcadd`: 0, 270 - Constraint::SvImmRotationAdd => Box::new((90..=270).step_by(180)), + Constraint::SvImmRotationAdd => ConstraintIterator::StepBy((90..=270).step_by(180)), } } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs index 21cc5cfa2e597..bbff7a91b6c41 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_c.rs @@ -18,30 +18,36 @@ pub fn write_wrapper_c( w: &mut impl std::io::Write, intrinsics: &[Intrinsic], ) -> std::io::Result<()> { - write!(w, "{}", A::NOTICE)?; + write!( + w, + r#" +{notice} +#include +#include +{prelude} - writeln!(w, "#include ")?; - writeln!(w, "#include ")?; - writeln!(w, "{}", A::C_PRELUDE)?; - - for intrinsic in intrinsics { - intrinsic.iter_specializations(|imm_values| { - writeln!( - w, - " +{intrinsics} +"#, + notice = A::NOTICE, + prelude = A::C_PRELUDE, + intrinsics = intrinsics.iter().format_with("", |intrinsic, fmt| { + fmt(&intrinsic + .specializations() + .format_with("\n", |imm_values, fmt| { + fmt(&format_args!( + " void {name}_wrapper{imm_arglist}({return_ty}* __dst{arglist}) {{ *__dst = {name}({params}); }}", - return_ty = intrinsic.results.c_type(), - name = intrinsic.name, - imm_arglist = imm_values - .iter() - .format_with("", |i, fmt| fmt(&format_args!("_{i}"))), - arglist = intrinsic.arguments.as_non_imm_arglist_c(), - params = intrinsic.arguments.as_call_params_c(&imm_values) - ) - })?; - } - - Ok(()) + return_ty = intrinsic.results.c_type(), + name = intrinsic.name, + imm_arglist = imm_values + .iter() + .format_with("", |i, fmt| fmt(&format_args!("_{i}"))), + arglist = intrinsic.arguments.as_non_imm_arglist_c(), + params = intrinsic.arguments.as_call_params_c(&imm_values) + )) + })) + }), + ) } diff --git a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs index baa11511ec219..44128d43b99a0 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/gen_rust.rs @@ -5,8 +5,9 @@ use itertools::Itertools; use super::intrinsic_helpers::TypeDefinition; use crate::common::cli::{CcArgStyle, ProcessedCli}; use crate::common::intrinsic::Intrinsic; +use crate::common::intrinsic_helpers::TypeKind; use crate::common::values::{test_values_array_name, test_values_array_static}; -use crate::common::{PASSES, SupportedArchitecture}; +use crate::common::{PASSES, PREDICATE_LOCAL, SupportedArchitecture}; /// Rust definitions that are included verbatim in the generated source. In particular, defines /// a wrapper around float types that defines `NaN`s to be equal reflexively to enable @@ -126,7 +127,10 @@ pub fn write_lib_rs( for intrinsic in intrinsics { for arg in &intrinsic.arguments.args { - if !arg.has_constraint() { + // Skip arguments with constraints as these correspond to generic instantiatons, and + // predicates for scalable intrinsics as the same predicate is used for all intrinsics + // under test. + if !arg.has_constraint() && !arg.is_predicate { let name = test_values_array_name(&arg.ty); if seen.insert(name) { @@ -168,38 +172,14 @@ fn generate_rust_test_loop( coerce += ") -> _"; c_coerce += ")"; - if intrinsic - .arguments - .iter() - .filter(|arg| arg.has_constraint()) - .count() - == 0 - { - writeln!( - w, - " let specializations = [(\"\", {intrinsic_name}, {intrinsic_name}_wrapper)];" - )?; - } else { - writeln!(w, " let specializations = [")?; - - intrinsic.iter_specializations(|imm_values| { - writeln!( - w, - " (\"{const_args}\", {intrinsic_name}::<{const_args}> as unsafe {coerce}, {intrinsic_name}_wrapper_{c_const_args} as unsafe extern \"C\" {c_coerce}),", - const_args = imm_values.iter().join(","), - c_const_args = imm_values.iter().join("_"), - ) - })?; - - writeln!(w, " ];")?; - } - write!( w, r#" +let specializations = [{specializations}]; for (id, rust, c) in specializations {{ for i in 0..{PASSES} {{ unsafe {{ + {predicate} {loaded_args} let __rust_return_value = rust({rust_args}); @@ -212,9 +192,50 @@ for (id, rust, c) in specializations {{ }} }} "#, + specializations = intrinsic + .specializations() + .format_with(",", |imm_values, fmt| { + if imm_values.is_empty() { + fmt(&format_args!( + "(\"\", {intrinsic_name}, {intrinsic_name}_wrapper)" + )) + } else { + let constraint_args = intrinsic.arguments.iter().filter(|a| a.has_constraint()); + fmt(&format_args!( + r#" + ( + "{const_args}", + {intrinsic_name}::<{const_args}> as unsafe {coerce}, + {intrinsic_name}_wrapper_{c_const_args} as unsafe extern "C" {c_coerce} + ) + "#, + const_args = imm_values + .iter() + .zip(constraint_args) + .map(|(imm_val, arg)| { + match arg.ty.kind() { + TypeKind::SvPattern | TypeKind::SvPrefetchOp => { + format!("{{ {}_from_i32({imm_val}) }}", arg.ty.kind()) + } + _ => imm_val.to_string(), + } + }) + .join(","), + c_const_args = imm_values.iter().join("_"), + )) + } + }), loaded_args = intrinsic.arguments.load_values_rust(), rust_args = intrinsic.arguments.as_call_param_rust(), c_args = intrinsic.arguments.as_c_call_param_rust(), + predicate = if intrinsic.has_scalable_argument_or_result() { + format!( + "let {PREDICATE_LOCAL} = {pred};", + pred = A::predicate_function(intrinsic.results.inner_size()), + ) + } else { + "".to_string() + }, comparison = intrinsic.results.comparison_function(), ) } @@ -256,25 +277,25 @@ pub fn write_bindings_rust( #[allow(improper_ctypes)] #[link(name = "wrapper_{i}")] unsafe extern "C" {{ + {definitions} +}} "#, - )?; - - for intrinsic in intrinsics { - intrinsic.iter_specializations(|imm_values| { - writeln!( - w, - "fn {name}_wrapper{imm_arglist}(__dst: *mut {return_ty}{arglist});", - return_ty = intrinsic.results.rust_type(), - name = intrinsic.name, - imm_arglist = imm_values - .iter() - .format_with("", |i, fmt| fmt(&format_args!("_{i}"))), - arglist = intrinsic.arguments.as_non_imm_arglist_rust(), - ) - })?; - } - - writeln!(w, "}}") + definitions = intrinsics.iter().format_with("", |intrinsic, fmt| { + fmt(&intrinsic + .specializations() + .format_with("\n", |imm_values, fmt| { + fmt(&format_args!( + "fn {name}_wrapper{imm_arglist}(__dst: *mut {return_ty}{arglist});", + return_ty = intrinsic.results.rust_type(), + name = intrinsic.name, + imm_arglist = imm_values + .iter() + .format_with("", |i, fmt| fmt(&format_args!("_{i}"))), + arglist = intrinsic.arguments.as_non_imm_arglist_rust(), + )) + })) + }) + ) } /// Writes a `build.rs` into `w` for each test crate that compiles the corresponding C source code diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs index 0c5bf43069d00..d5d903d941e4b 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic.rs @@ -1,5 +1,6 @@ use super::argument::ArgumentList; -use crate::common::{SupportedArchitecture, constraint::Constraint}; +use crate::common::{SupportedArchitecture, intrinsic_helpers::SimdLen}; +use itertools::Itertools; /// An intrinsic #[derive(Debug, PartialEq, Clone)] @@ -20,27 +21,6 @@ pub struct Intrinsic { pub extension: String, } -/// Invokes `f` for each combination of the values in the constraint ranges. -/// -/// For example, given `constraints=[Equal(0), Range(1..2), Set([3, 4])]` and `imm_values=[]`, this -/// produces the four calls to `f`: `f([0, 1, 3])`, `f([0, 1, 4])`, `f([0, 2, 3])`, `f([0, 2, 4])`. -fn recurse_specializations<'a, E>( - constraints: &mut (impl Iterator + Clone), - imm_values: &mut Vec, - f: &mut impl FnMut(&[i64]) -> Result<(), E>, -) -> Result<(), E> { - if let Some(current) = constraints.next() { - for i in current.iter() { - imm_values.push(i); - recurse_specializations(&mut constraints.clone(), imm_values, f)?; - imm_values.pop(); - } - Ok(()) - } else { - f(&imm_values) - } -} - impl Intrinsic { /// Invokes `f` for "specialisation" of the intrinsic - a specific instantiation of the /// constant generics of the intrinsic. `f` takes a slice where the `i`th element corresponds @@ -49,17 +29,20 @@ impl Intrinsic { /// For an intrinsic with three arguments with constraints `Equal(0)`, `Range(1..2)`, /// `Set([3, 4])` respectively, this would produce four calls to `f`: `f(0, 1, 3)`, /// `f(0, 1, 4)`, `f(0, 2, 3)`, `f(0, 2, 4)`. - pub fn iter_specializations( - &self, - mut f: impl FnMut(&[i64]) -> Result<(), E>, - ) -> Result<(), E> { - recurse_specializations( - &mut self + pub fn specializations(&self) -> impl Iterator> { + self.arguments + .iter() + .filter_map(|arg| arg.constraint.as_ref()) + .map(|constraint| constraint.into_iter()) + .multi_cartesian_product() + } + + /// Returns `true` if this intrinsic has any argument or result types that are scalable vectors + pub fn has_scalable_argument_or_result(&self) -> bool { + self.results.num_lanes() == SimdLen::Scalable + || self .arguments .iter() - .filter_map(|arg| arg.constraint.as_ref()), - &mut Vec::new(), - &mut f, - ) + .any(|a| a.ty.num_lanes() == SimdLen::Scalable) } } diff --git a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs index b9f30af7dfd51..bc47a90d3fe16 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/intrinsic_helpers.rs @@ -116,6 +116,15 @@ pub enum SimdLen { Fixed(u32), } +impl SimdLen { + pub fn expect_fixed(&self) -> u32 { + match self { + SimdLen::Fixed(lanes) => *lanes, + SimdLen::Scalable => panic!("`expect_fixed` with scalable length"), + } + } +} + impl std::fmt::Display for SimdLen { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -173,14 +182,8 @@ impl IntrinsicType { } /// Returns the number of lanes of the type - pub fn num_lanes(&self) -> u32 { - self.simd_len - .as_ref() - .map(|len| match len { - SimdLen::Scalable => unimplemented!(), - SimdLen::Fixed(len) => *len, - }) - .unwrap_or(1) + pub fn num_lanes(&self) -> SimdLen { + self.simd_len.unwrap_or(SimdLen::Fixed(1)) } /// Returns the number of vectors of the type @@ -208,7 +211,7 @@ pub trait TypeDefinition: Clone + DerefMut { match self.simd_len { Some(SimdLen::Scalable) => unimplemented!("architecture-specific"), Some(SimdLen::Fixed(_)) | None => { - default_fixed_vector_comparison(self, self.num_lanes()) + default_fixed_vector_comparison(self, self.num_lanes().expect_fixed()) } } } @@ -227,6 +230,12 @@ pub trait TypeDefinition: Clone + DerefMut { ty.vec_len = None; ty.rust_type() } + + /// Gets a string containing the name of the scalar type corresponding to this type that should + /// be used as the element type for the test value array. + fn rust_scalar_type_for_test_value_array(&self) -> String { + self.rust_scalar_type() + } } /// Returns the default comparison between results of an intrinsic - casting the vectors to arrays diff --git a/library/stdarch/crates/intrinsic-test/src/common/mod.rs b/library/stdarch/crates/intrinsic-test/src/common/mod.rs index 73daabbd6661a..46b6bc4102bed 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/mod.rs @@ -5,12 +5,14 @@ use rayon::prelude::*; use cli::ProcessedCli; use crate::common::{ + argument::Argument, gen_c::write_wrapper_c, gen_rust::{ run_rustfmt, write_bin_cargo_toml, write_build_rs, write_lib_cargo_toml, write_lib_rs, }, intrinsic::Intrinsic, intrinsic_helpers::TypeDefinition, + values::test_values_array_name, }; pub mod argument; @@ -18,10 +20,16 @@ pub mod cli; pub mod constraint; pub mod intrinsic; pub mod intrinsic_helpers; +pub mod values; mod gen_c; mod gen_rust; -mod values; + +/// Many scalable intrinsics take a predicate argument and for the purposes of intrinsic testing, +/// a predicate that enables all lanes is used for all of these intrinsic calls (i.e. loading inputs, +/// result comparison, and the intrinsic under test). This constant defines the name of the local +/// variable that contains that predicate. +pub const PREDICATE_LOCAL: &'static str = "__pred"; // The number of times each intrinsic will be called - influences the generation of the // test arrays to minimise repeated testing of the same test values. @@ -100,6 +108,19 @@ pub trait SupportedArchitecture: Sized { .collect::>() .unwrap(); } + + /// Return a call to a intrinsic to generate a predicate, if reqd. + fn predicate_function(_: u32) -> String; + + /// Return a call loading `arg`. Can assume that `arg.is_simd()` holds. + fn load_call(arg: &Argument, idx: usize) -> String { + format!( + "let {name} = {load}({vals_name}.as_ptr().add((i+{idx}) % {PASSES}) as _);\n", + name = arg.generate_name(), + vals_name = test_values_array_name(&arg.ty), + load = arg.ty.load_function(), + ) + } } pub fn manual_chunk(intrinsic_count: usize) -> (usize, usize) { diff --git a/library/stdarch/crates/intrinsic-test/src/common/values.rs b/library/stdarch/crates/intrinsic-test/src/common/values.rs index 8c549346ce6ed..d1f333fd19363 100644 --- a/library/stdarch/crates/intrinsic-test/src/common/values.rs +++ b/library/stdarch/crates/intrinsic-test/src/common/values.rs @@ -26,7 +26,7 @@ pub fn test_values_array_static( w, "static {name}: [{ty}; {load_size}] = {values};", name = test_values_array_name(ty), - ty = ty.rust_scalar_type(), + ty = ty.rust_scalar_type_for_test_value_array(), load_size = test_values_array_length(&ty), values = test_values_array(&ty) ) @@ -50,8 +50,16 @@ pub fn test_values_array_name(ty: &T) -> String { /// which is then printed as a hex value in the generated code (and if identified as a negative /// value, with the appropriate minus and corrected hex pattern). Calls to `fN::from_bits` are /// generated for floats. +/// +/// An exception to the above is when `ty` is a boolean, where this function returns +/// `[true, false]` - as there are only ever two values for a boolean. This only works because the +/// generated accesses to the test value array is always modulo the length of the test value array. pub fn test_values_array(ty: &IntrinsicType) -> String { let (bit_len, kind) = match ty { + IntrinsicType { + kind: TypeKind::Bool, + .. + } => (1, TypeKind::Bool), IntrinsicType { kind: TypeKind::Float, bit_len: Some(bit_len), @@ -75,6 +83,9 @@ pub fn test_values_array(ty: &IntrinsicType) -> String { let src = bit_pattern_for_test_values_array(bit_len, i); assert!(src == 0 || src.ilog2() < bit_len); match kind { + TypeKind::Bool if ty.num_lanes() != SimdLen::Scalable => { + fmt(&format_args!("{}", if src == 1 { true } else { false })) + } TypeKind::Float => fmt(&format_args!("f{bit_len}::from_bits({src:#x})")), TypeKind::Vector | TypeKind::Int(Sign::Signed) if (src >> (bit_len - 1)) != 0 => { // `src` is a two's complement representation of a negative value. @@ -134,7 +145,8 @@ pub fn test_values_array_length(ty: &IntrinsicType) -> u32 { pub fn bit_pattern_for_test_values_array(bits: u32, index: u32) -> u64 { let index = index as usize; match bits { - bits @ (1 | 2 | 3 | 4 | 5 | 6 | 7 | 8) => BIT_PATTERNS_8[index % (1 << bits)].into(), + 1 => BIT_PATTERNS_1[index % BIT_PATTERNS_1.len()].into(), + bits @ (2 | 3 | 4 | 5 | 6 | 7 | 8) => BIT_PATTERNS_8[index % (1 << bits)].into(), 16 => BIT_PATTERNS_16[index % BIT_PATTERNS_16.len()].into(), 32 => BIT_PATTERNS_32[index % BIT_PATTERNS_32.len()].into(), 64 => BIT_PATTERNS_64[index % BIT_PATTERNS_64.len()], @@ -142,6 +154,9 @@ pub fn bit_pattern_for_test_values_array(bits: u32, index: u32) -> u64 { } } +// Contains every possible 1-bit value in order +pub const BIT_PATTERNS_1: &[u8] = &[0x0, 0x1]; + // Contains every possible 8-bit value in order pub const BIT_PATTERNS_8: &[u8] = &[ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, diff --git a/library/stdarch/crates/intrinsic-test/src/x86/mod.rs b/library/stdarch/crates/intrinsic-test/src/x86/mod.rs index ce4955032916d..36f4fee43741b 100644 --- a/library/stdarch/crates/intrinsic-test/src/x86/mod.rs +++ b/library/stdarch/crates/intrinsic-test/src/x86/mod.rs @@ -99,6 +99,10 @@ impl SupportedArchitecture for X86 { Self { intrinsics } } + + fn predicate_function(_: u32) -> String { + unimplemented!("no scalable vectors on x86") + } } const RUST_PRELUDE: &str = r#" diff --git a/library/stdarch/crates/intrinsic-test/src/x86/xml_parser.rs b/library/stdarch/crates/intrinsic-test/src/x86/xml_parser.rs index 52f6da786e3d7..2296dffb64a5b 100644 --- a/library/stdarch/crates/intrinsic-test/src/x86/xml_parser.rs +++ b/library/stdarch/crates/intrinsic-test/src/x86/xml_parser.rs @@ -99,8 +99,13 @@ fn xml_to_intrinsic(intr: XMLIntrinsic) -> Result, Box::new(i, param.var_name.clone(), ty.unwrap(), constraint); - Some(arg) + Some(Argument::::new( + i, + param.var_name.clone(), + ty.unwrap(), + constraint, + false, + )) } }); diff --git a/library/stdarch/crates/stdarch-gen-arm/spec/sve/aarch64.spec.yml b/library/stdarch/crates/stdarch-gen-arm/spec/sve/aarch64.spec.yml index 138d5ba31175b..0b2d17d3b195f 100644 --- a/library/stdarch/crates/stdarch-gen-arm/spec/sve/aarch64.spec.yml +++ b/library/stdarch/crates/stdarch-gen-arm/spec/sve/aarch64.spec.yml @@ -1157,7 +1157,7 @@ intrinsics: doc: Interleave even elements from two inputs arguments: ["op1: {sve_type}", "op2: {sve_type}"] return_type: "{sve_type}" - types: [f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] + types: [b8, f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] assert_instr: [trn1] compose: - LLVMLink: { name: "trn1.{sve_type}" } @@ -1167,10 +1167,13 @@ intrinsics: doc: Interleave even elements from two inputs arguments: ["op1: {sve_type}", "op2: {sve_type}"] return_type: "{sve_type}" - types: [b8, b16, b32, b64] + types: [b16, b32, b64] assert_instr: [trn1] compose: - - LLVMLink: { name: "trn1.{sve_type}" } + - LLVMLink: + name: "llvm.aarch64.sve.trn1.b{size}" + arguments: ["op1: svbool_t", "op2: svbool_t"] + return_type: "svbool_t" - name: svtrn1q[_{type}] attr: [*sve-unstable] @@ -1188,7 +1191,7 @@ intrinsics: doc: Interleave odd elements from two inputs arguments: ["op1: {sve_type}", "op2: {sve_type}"] return_type: "{sve_type}" - types: [f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] + types: [b8, f32, f64, i8, i16, i32, i64, u8, u16, u32, u64] assert_instr: [trn2] compose: - LLVMLink: { name: "trn2.{sve_type}" } @@ -1198,10 +1201,13 @@ intrinsics: doc: Interleave odd elements from two inputs arguments: ["op1: {sve_type}", "op2: {sve_type}"] return_type: "{sve_type}" - types: [b8, b16, b32, b64] + types: [b16, b32, b64] assert_instr: [trn2] compose: - - LLVMLink: { name: "trn2.{sve_type}" } + - LLVMLink: + name: "llvm.aarch64.sve.trn2.b{size}" + arguments: ["op1: svbool_t", "op2: svbool_t"] + return_type: "svbool_t" - name: svtrn2q[_{type}] attr: [*sve-unstable] diff --git a/library/stdarch/crates/stdarch-gen-hexagon-scalar/Cargo.toml b/library/stdarch/crates/stdarch-gen-hexagon-scalar/Cargo.toml deleted file mode 100644 index 04bee944f4a91..0000000000000 --- a/library/stdarch/crates/stdarch-gen-hexagon-scalar/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "stdarch-gen-hexagon-scalar" -version = "0.1.0" -authors = ["The Rust Project Developers"] -license = "MIT OR Apache-2.0" -edition = "2021" - -[dependencies] -regex = "1.10" diff --git a/library/stdarch/crates/stdarch-gen-hexagon-scalar/hexagon_protos.h b/library/stdarch/crates/stdarch-gen-hexagon/hexagon_protos.h similarity index 100% rename from library/stdarch/crates/stdarch-gen-hexagon-scalar/hexagon_protos.h rename to library/stdarch/crates/stdarch-gen-hexagon/hexagon_protos.h diff --git a/library/stdarch/crates/stdarch-gen-hexagon/src/hvx.rs b/library/stdarch/crates/stdarch-gen-hexagon/src/hvx.rs new file mode 100644 index 0000000000000..4d4b03c3ac204 --- /dev/null +++ b/library/stdarch/crates/stdarch-gen-hexagon/src/hvx.rs @@ -0,0 +1,1648 @@ +//! Hexagon HVX Code Generator +//! +//! This generator creates v64.rs and v128.rs from scratch using the LLVM HVX +//! header file as the sole source of truth. It parses the C intrinsic prototypes +//! and generates Rust wrapper functions with appropriate attributes. +//! +//! The two generated files provide: +//! - v64.rs: 64-byte vector mode intrinsics (512-bit vectors) +//! - v128.rs: 128-byte vector mode intrinsics (1024-bit vectors) +//! +//! Both modules are available unconditionally, but require the appropriate +//! target features to actually use the intrinsics. +//! +//! Usage: +//! cd crates/stdarch-gen-hexagon +//! cargo run +//! # Output is written to ../core_arch/src/hexagon/v64.rs and v128.rs + +use regex::Regex; +use std::collections::{HashMap, HashSet}; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use stdarch_gen_common::GENERATED_MARKER; + +/// Mappings from HVX intrinsics to architecture-independent SIMD intrinsics. +/// These intrinsics have equivalent semantics and can be lowered to the generic form. +fn get_simd_intrinsic_mappings() -> HashMap<&'static str, &'static str> { + let mut map = HashMap::new(); + // Bitwise operations (element-size independent) + map.insert("vxor", "simd_xor"); + map.insert("vand", "simd_and"); + map.insert("vor", "simd_or"); + // Word (32-bit) arithmetic operations + map.insert("vaddw", "simd_add"); + map.insert("vsubw", "simd_sub"); + map +} + +/// The tracking issue number for the stdarch_hexagon feature +const TRACKING_ISSUE: &str = "151523"; + +/// HVX vector length mode +#[derive(Debug, Clone, Copy, PartialEq)] +enum VectorMode { + /// 64-byte vectors (512 bits) + V64, + /// 128-byte vectors (1024 bits) + V128, +} + +impl VectorMode { + fn bytes(&self) -> u32 { + match self { + VectorMode::V64 => 64, + VectorMode::V128 => 128, + } + } + + fn bits(&self) -> u32 { + self.bytes() * 8 + } + + fn lanes(&self) -> u32 { + self.bytes() / 4 // 32-bit lanes + } + + fn target_feature(&self) -> &'static str { + match self { + VectorMode::V64 => "hvx-length64b", + VectorMode::V128 => "hvx-length128b", + } + } +} + +/// LLVM version the header file is from (for reference) +/// Source: https://github.com/llvm/llvm-project/blob/llvmorg-22.1.0-rc1/clang/lib/Headers/hvx_hexagon_protos.h +const LLVM_VERSION: &str = "22.1.0-rc1"; + +/// Maximum HVX architecture version supported by rustc +/// Check with: rustc --target=hexagon-unknown-linux-musl --print target-features +const MAX_SUPPORTED_ARCH: u32 = 79; + +/// Local header file path (checked into the repository) +const HEADER_FILE: &str = "hvx_hexagon_protos.h"; + +/// Intrinsic information parsed from the LLVM header +#[derive(Debug, Clone)] +struct IntrinsicInfo { + /// The Q6_* intrinsic name (e.g., "Q6_V_vadd_VV") + q6_name: String, + /// The LLVM builtin name without prefix (e.g., "V6_vaddb") + builtin_name: String, + /// The short instruction name for assert_instr (e.g., "vaddb") + instr_name: String, + /// The assembly syntax from the comment + asm_syntax: String, + /// Instruction type + instr_type: String, + /// Execution slots + exec_slots: String, + /// Minimum HVX architecture version required + min_arch: u32, + /// Return type + return_type: RustType, + /// Parameters (name, type) + params: Vec<(String, RustType)>, + /// Whether this is a compound intrinsic (multiple builtins) + is_compound: bool, + /// For compound intrinsics: the parsed expression tree + compound_expr: Option, +} + +/// Expression tree for compound intrinsics +#[derive(Debug, Clone)] +enum CompoundExpr { + /// A call to a builtin: (builtin_name without V6_ prefix, arguments) + BuiltinCall(String, Vec), + /// A parameter reference by name + Param(String), + /// An integer literal (like -1) + IntLiteral(i32), +} + +/// Rust type mappings +#[derive(Debug, Clone, PartialEq)] +enum RustType { + HvxVector, + HvxVectorPair, + HvxVectorPred, + I32, + MutPtrHvxVector, + Unit, +} + +impl RustType { + fn from_c_type(c_type: &str) -> Option { + match c_type.trim() { + "HVX_Vector" => Some(RustType::HvxVector), + "HVX_VectorPair" => Some(RustType::HvxVectorPair), + "HVX_VectorPred" => Some(RustType::HvxVectorPred), + "Word32" => Some(RustType::I32), + "HVX_Vector*" => Some(RustType::MutPtrHvxVector), + "void" => Some(RustType::Unit), + _ => None, + } + } + + fn to_rust_str(&self) -> &'static str { + match self { + RustType::HvxVector => "HvxVector", + RustType::HvxVectorPair => "HvxVectorPair", + RustType::HvxVectorPred => "HvxVectorPred", + RustType::I32 => "i32", + RustType::MutPtrHvxVector => "*mut HvxVector", + RustType::Unit => "()", + } + } + + fn to_extern_str(&self) -> &'static str { + match self { + RustType::HvxVector => "HvxVector", + RustType::HvxVectorPair => "HvxVectorPair", + RustType::HvxVectorPred => "HvxVectorPred", + RustType::I32 => "i32", + RustType::MutPtrHvxVector => "*mut HvxVector", + RustType::Unit => "()", + } + } +} + +/// Parse a compound macro expression into an expression tree +fn parse_compound_expr(expr: &str) -> Option { + let expr = expr.trim(); + + // Try to match an integer literal (like -1) + if let Ok(n) = expr.parse::() { + return Some(CompoundExpr::IntLiteral(n)); + } + + // Try to match a simple parameter name (Vu, Vv, Rt, Qs, Qt, Qx, Vx, etc.) + // These are typically short identifiers in the macro + if expr.len() <= 3 + && expr.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') + && !expr.contains("__") + { + return Some(CompoundExpr::Param(expr.to_lowercase())); + } + + // Check if it's wrapped in extra parens first + if expr.starts_with('(') && expr.ends_with(')') { + // Check if these parens wrap the entire expression + let inner = &expr[1..expr.len() - 1]; + // Count depth: if after removing outer parens the expression is balanced, + // the outer parens were enclosing everything + if is_balanced_parens(inner) { + // But we also need to verify these aren't part of a function call + // If the inner expression is balanced and the whole thing starts with ( + // and ends with ), it's a paren wrapper + let result = parse_compound_expr(inner); + if result.is_some() { + return result; + } + } + } + + // Try to match __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_xxx)(args) + // The args portion may contain nested calls, so we need to find the matching paren + if expr.starts_with("__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_") { + // Find the end of the builtin name (after V6_) + let prefix = "__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_"; + let after_prefix = &expr[prefix.len()..]; + if let Some(paren_pos) = after_prefix.find(')') { + let builtin_name = &after_prefix[..paren_pos]; + let rest = &after_prefix[paren_pos + 1..]; // Skip the closing ) of the WRAP + // rest should now be "(args)" + if rest.starts_with('(') && rest.ends_with(')') { + let args_str = &rest[1..rest.len() - 1]; + let args = parse_compound_args(args_str)?; + return Some(CompoundExpr::BuiltinCall(builtin_name.to_string(), args)); + } + } + } + + // Try to match __builtin_HEXAGON_V6_xxx(args) without wrap + if expr.starts_with("__builtin_HEXAGON_V6_") { + let prefix = "__builtin_HEXAGON_V6_"; + let after_prefix = &expr[prefix.len()..]; + if let Some(paren_pos) = after_prefix.find('(') { + let builtin_name = &after_prefix[..paren_pos]; + let rest = &after_prefix[paren_pos..]; + if rest.starts_with('(') && rest.ends_with(')') { + let args_str = &rest[1..rest.len() - 1]; + let args = parse_compound_args(args_str)?; + return Some(CompoundExpr::BuiltinCall(builtin_name.to_string(), args)); + } + } + } + + None +} + +/// Check if parentheses are balanced in a string +fn is_balanced_parens(s: &str) -> bool { + let mut depth = 0; + for c in s.chars() { + match c { + '(' => depth += 1, + ')' => { + depth -= 1; + if depth < 0 { + return false; + } + } + _ => {} + } + } + depth == 0 +} + +/// Parse comma-separated arguments, respecting nested parentheses +fn parse_compound_args(args_str: &str) -> Option> { + let mut args = Vec::new(); + let mut current = String::new(); + let mut depth = 0; + + for c in args_str.chars() { + match c { + '(' => { + depth += 1; + current.push(c); + } + ')' => { + depth -= 1; + current.push(c); + } + ',' if depth == 0 => { + let arg = current.trim().to_string(); + if !arg.is_empty() { + args.push(parse_compound_expr(&arg)?); + } + current.clear(); + } + _ => current.push(c), + } + } + + // Don't forget the last argument + let arg = current.trim().to_string(); + if !arg.is_empty() { + args.push(parse_compound_expr(&arg)?); + } + + Some(args) +} + +/// Extract all builtin names used in a compound expression +fn collect_builtins_from_expr(expr: &CompoundExpr, builtins: &mut HashSet) { + match expr { + CompoundExpr::BuiltinCall(name, args) => { + builtins.insert(name.clone()); + for arg in args { + collect_builtins_from_expr(arg, builtins); + } + } + CompoundExpr::Param(_) | CompoundExpr::IntLiteral(_) => {} + } +} + +/// Read the local HVX header file +fn read_header(crate_dir: &Path) -> Result { + let header_path = crate_dir.join(HEADER_FILE); + println!("Reading HVX header from: {}", header_path.display()); + println!(" (LLVM version: {})", LLVM_VERSION); + + std::fs::read_to_string(&header_path).map_err(|e| { + format!( + "Failed to read header file {}: {}", + header_path.display(), + e + ) + }) +} + +/// Parse a C function prototype to extract return type and parameters +fn parse_prototype(prototype: &str) -> Option<(RustType, Vec<(String, RustType)>)> { + // Pattern: ReturnType FunctionName(ParamType1 Param1, ParamType2 Param2, ...) + let proto_re = Regex::new(r"(\w+(?:\*)?)\s+Q6_\w+\(([^)]*)\)").unwrap(); + + if let Some(caps) = proto_re.captures(prototype) { + let return_type_str = caps[1].trim(); + let params_str = &caps[2]; + + let return_type = RustType::from_c_type(return_type_str)?; + + let mut params = Vec::new(); + if !params_str.trim().is_empty() { + // Pattern: Type Name or Type* Name + let param_re = Regex::new(r"(\w+\*?)\s+(\w+)").unwrap(); + for param in params_str.split(',') { + let param = param.trim(); + if let Some(pcaps) = param_re.captures(param) { + let ptype_str = pcaps[1].trim(); + let pname = pcaps[2].to_lowercase(); + if let Some(ptype) = RustType::from_c_type(ptype_str) { + params.push((pname, ptype)); + } else { + return None; // Unknown type + } + } + } + } + + Some((return_type, params)) + } else { + None + } +} + +/// Parse the LLVM header file to extract intrinsic information +fn parse_header(content: &str) -> Vec { + let mut intrinsics = Vec::new(); + + let arch_re = Regex::new(r"#if __HVX_ARCH__ >= (\d+)").unwrap(); + + // Regex to extract the simple builtin name from a macro body + // Match: __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_xxx)(args) + let simple_builtin_re = + Regex::new(r"__BUILTIN_VECTOR_WRAP\(__builtin_HEXAGON_(\w+)\)\([^)]*\)\s*$").unwrap(); + + // Also handle builtins without VECTOR_WRAP + let simple_builtin_re2 = Regex::new(r"__builtin_HEXAGON_(\w+)\([^)]*\)\s*$").unwrap(); + + // Regex to extract Q6 name from #define + let q6_name_re = Regex::new(r"#define\s+(Q6_\w+)").unwrap(); + + // Regex to extract macro expression body + let macro_expr_re = Regex::new(r"#define\s+Q6_\w+\([^)]*\)\s+(.+)").unwrap(); + + let lines: Vec<&str> = content.lines().collect(); + let mut current_arch: u32 = 60; + let mut i = 0; + + while i < lines.len() { + // Track architecture version + if let Some(caps) = arch_re.captures(lines[i]) { + if let Ok(arch) = caps[1].parse() { + current_arch = arch; + } + } + + // Look for Assembly Syntax comment block + if lines[i].contains("Assembly Syntax:") { + let mut asm_syntax = String::new(); + let mut prototype = String::new(); + let mut instr_type = String::new(); + let mut exec_slots = String::new(); + + // Parse the comment block + let mut j = i; + while j < lines.len() && !lines[j].starts_with("#define") { + let line = lines[j]; + if line.contains("Assembly Syntax:") { + if let Some(pos) = line.find("Assembly Syntax:") { + asm_syntax = line[pos + 16..].trim().to_string(); + } + } else if line.contains("C Intrinsic Prototype:") { + if let Some(pos) = line.find("C Intrinsic Prototype:") { + prototype = line[pos + 22..].trim().to_string(); + } + } else if line.contains("Instruction Type:") { + if let Some(pos) = line.find("Instruction Type:") { + instr_type = line[pos + 17..].trim().to_string(); + } + } else if line.contains("Execution Slots:") { + if let Some(pos) = line.find("Execution Slots:") { + exec_slots = line[pos + 16..].trim().to_string(); + } + } + j += 1; + } + + // Now find the #define line + while j < lines.len() && !lines[j].starts_with("#define") { + j += 1; + } + + if j < lines.len() { + let define_line = lines[j]; + + // Extract Q6 name and check if it's simple or compound + if let Some(caps) = q6_name_re.captures(define_line) { + let q6_name = caps[1].to_string(); + + // Get the full macro body (handle line continuations) + let mut macro_body = define_line.to_string(); + let mut k = j; + while macro_body.trim_end().ends_with('\\') && k + 1 < lines.len() { + k += 1; + macro_body.push_str(lines[k]); + } + + // Try to extract simple builtin name + let builtin_name = simple_builtin_re + .captures(¯o_body) + .or_else(|| simple_builtin_re2.captures(¯o_body)) + .map(|bcaps| bcaps[1].to_string()); + + // Check if it's a compound intrinsic (multiple __builtin calls) + let builtin_count = macro_body.matches("__builtin_HEXAGON_").count(); + let is_compound = builtin_count > 1; + + // Parse prototype + if let Some((return_type, params)) = parse_prototype(&prototype) { + if is_compound { + // For compound intrinsics, parse the expression + // Extract the macro body after the parameter list + if let Some(expr_caps) = macro_expr_re.captures(¯o_body) { + let expr_str = expr_caps[1].trim().replace(['\n', '\\'], " "); + let expr_str = expr_str.trim(); + + if let Some(compound_expr) = parse_compound_expr(expr_str) { + // For compound intrinsics, we use the outermost builtin + // as the "primary" for the instruction name + let (primary_builtin, instr_name) = match &compound_expr { + CompoundExpr::BuiltinCall(name, _) => { + (name.clone(), name.clone()) + } + _ => continue, + }; + + intrinsics.push(IntrinsicInfo { + q6_name, + builtin_name: format!("V6_{}", primary_builtin), + instr_name, + asm_syntax, + instr_type, + exec_slots, + min_arch: current_arch, + return_type, + params, + is_compound: true, + compound_expr: Some(compound_expr), + }); + } + } + } else if let Some(builtin) = builtin_name { + // Extract short instruction name + let instr_name = builtin + .strip_prefix("V6_") + .map(|s| s.to_string()) + .unwrap_or_else(|| builtin.clone()); + + intrinsics.push(IntrinsicInfo { + q6_name, + builtin_name: builtin, + instr_name, + asm_syntax, + instr_type, + exec_slots, + min_arch: current_arch, + return_type, + params, + is_compound: false, + compound_expr: None, + }); + } + } + } + } + i = j; + } + i += 1; + } + + intrinsics +} + +/// Generate the module documentation +fn generate_module_doc(mode: VectorMode) -> String { + format!( + r#"//! Hexagon HVX {bytes}-byte vector mode intrinsics +//! +//! This module provides intrinsics for the Hexagon Vector Extensions (HVX) +//! in {bytes}-byte vector mode ({bits}-bit vectors). +//! +//! HVX is a wide vector extension designed for high-performance signal processing. +//! [Hexagon HVX Programmer's Reference Manual](https://docs.qualcomm.com/doc/80-N2040-61) +//! +//! ## Vector Types +//! +//! In {bytes}-byte mode: +//! - `HvxVector` is {bits} bits ({bytes} bytes) containing {lanes} x 32-bit values +//! - `HvxVectorPair` is {pair_bits} bits ({pair_bytes} bytes) +//! - `HvxVectorPred` is {bits} bits ({bytes} bytes) for predicate operations +//! +//! To use this module, compile with `-C target-feature=+{target_feature}`. +//! +//! ## Naming Convention +//! +//! Function names preserve the original Q6 naming case because the convention +//! uses case to distinguish register types: +//! - `W` (uppercase) = vector pair (`HvxVectorPair`) +//! - `V` (uppercase) = vector (`HvxVector`) +//! - `Q` (uppercase) = predicate (`HvxVectorPred`) +//! - `R` = scalar register (`i32`) +//! +//! For example, `Q6_W_vcombine_VV` operates on a vector pair while +//! `Q6_V_hi_W` extracts a vector from a pair. +//! +//! ## Architecture Versions +//! +//! Different intrinsics require different HVX architecture versions. Use the +//! appropriate target feature to enable the required version: +//! - HVX v60: `-C target-feature=+hvxv60` (basic HVX operations) +//! - HVX v62: `-C target-feature=+hvxv62` +//! - HVX v65: `-C target-feature=+hvxv65` (includes floating-point support) +//! - HVX v66: `-C target-feature=+hvxv66` +//! - HVX v68: `-C target-feature=+hvxv68` +//! - HVX v69: `-C target-feature=+hvxv69` +//! - HVX v73: `-C target-feature=+hvxv73` +//! - HVX v79: `-C target-feature=+hvxv79` +//! +//! Each version includes all features from previous versions. +"#, + bytes = mode.bytes(), + bits = mode.bits(), + lanes = mode.lanes(), + pair_bytes = mode.bytes() * 2, + pair_bits = mode.bits() * 2, + target_feature = mode.target_feature(), + ) +} + +/// Generate the type definitions for a specific vector mode +fn generate_types(mode: VectorMode) -> String { + let lanes = mode.lanes(); + let pair_lanes = lanes * 2; + let bits = mode.bits(); + let bytes = mode.bytes(); + let pair_bits = bits * 2; + let pair_bytes = bytes * 2; + + format!( + r#" +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +#[cfg(test)] +use stdarch_test::assert_instr; + +use crate::intrinsics::simd::{{simd_add, simd_and, simd_or, simd_sub, simd_xor}}; + +// HVX type definitions for {bytes}-byte vector mode +types! {{ + #![unstable(feature = "stdarch_hexagon", issue = "{TRACKING_ISSUE}")] + + /// HVX vector type ({bits} bits / {bytes} bytes) + /// + /// This type represents a single HVX vector register containing {lanes} x 32-bit values. + pub struct HvxVector({lanes} x i32); + + /// HVX vector pair type ({pair_bits} bits / {pair_bytes} bytes) + /// + /// This type represents a pair of HVX vector registers, often used for + /// operations that produce double-width results. + pub struct HvxVectorPair({pair_lanes} x i32); + + /// HVX vector predicate type ({bits} bits / {bytes} bytes) + /// + /// This type represents a predicate vector used for conditional operations. + /// Each bit corresponds to a lane in the vector. + pub struct HvxVectorPred({lanes} x i32); +}} +"#, + bytes = bytes, + bits = bits, + lanes = lanes, + pair_bits = pair_bits, + pair_bytes = pair_bytes, + pair_lanes = pair_lanes, + TRACKING_ISSUE = TRACKING_ISSUE, + ) +} + +/// Builtin signature information for extern declarations +struct BuiltinSignature { + /// The V6_ prefixed name + full_name: String, + /// The short name (without V6_) + short_name: String, + /// Return type + return_type: RustType, + /// Parameter types + param_types: Vec, +} + +/// Get known signatures for builtins used in compound operations +/// These are the helper builtins that don't have their own Q6_ wrapper +fn get_compound_helper_signatures() -> HashMap { + let mut map = HashMap::new(); + + // vandvrt: HVX_Vector -> i32 -> HVX_Vector + // Converts predicate to vector representation. LLVM uses HVX_Vector for both. + map.insert( + "vandvrt".to_string(), + BuiltinSignature { + full_name: "V6_vandvrt".to_string(), + short_name: "vandvrt".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::I32], + }, + ); + + // vandqrt: HVX_Vector -> i32 -> HVX_Vector + // Converts vector representation back to predicate. LLVM uses HVX_Vector for both. + map.insert( + "vandqrt".to_string(), + BuiltinSignature { + full_name: "V6_vandqrt".to_string(), + short_name: "vandqrt".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::I32], + }, + ); + + // vandvrt_acc: HVX_Vector -> HVX_Vector -> i32 -> HVX_Vector + map.insert( + "vandvrt_acc".to_string(), + BuiltinSignature { + full_name: "V6_vandvrt_acc".to_string(), + short_name: "vandvrt_acc".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector, RustType::I32], + }, + ); + + // vandqrt_acc: HVX_Vector -> HVX_Vector -> i32 -> HVX_Vector + map.insert( + "vandqrt_acc".to_string(), + BuiltinSignature { + full_name: "V6_vandqrt_acc".to_string(), + short_name: "vandqrt_acc".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector, RustType::I32], + }, + ); + + // pred_and: HVX_Vector -> HVX_Vector -> HVX_Vector + map.insert( + "pred_and".to_string(), + BuiltinSignature { + full_name: "V6_pred_and".to_string(), + short_name: "pred_and".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + // pred_and_n: HVX_Vector -> HVX_Vector -> HVX_Vector + map.insert( + "pred_and_n".to_string(), + BuiltinSignature { + full_name: "V6_pred_and_n".to_string(), + short_name: "pred_and_n".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + // pred_or: HVX_Vector -> HVX_Vector -> HVX_Vector + map.insert( + "pred_or".to_string(), + BuiltinSignature { + full_name: "V6_pred_or".to_string(), + short_name: "pred_or".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + // pred_or_n: HVX_Vector -> HVX_Vector -> HVX_Vector + map.insert( + "pred_or_n".to_string(), + BuiltinSignature { + full_name: "V6_pred_or_n".to_string(), + short_name: "pred_or_n".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + // pred_xor: HVX_Vector -> HVX_Vector -> HVX_Vector + map.insert( + "pred_xor".to_string(), + BuiltinSignature { + full_name: "V6_pred_xor".to_string(), + short_name: "pred_xor".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + // pred_not: HVX_Vector -> HVX_Vector + map.insert( + "pred_not".to_string(), + BuiltinSignature { + full_name: "V6_pred_not".to_string(), + short_name: "pred_not".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector], + }, + ); + + // pred_scalar2: i32 -> HVX_Vector + map.insert( + "pred_scalar2".to_string(), + BuiltinSignature { + full_name: "V6_pred_scalar2".to_string(), + short_name: "pred_scalar2".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::I32], + }, + ); + + // Conditional store operations + map.insert( + "vS32b_qpred_ai".to_string(), + BuiltinSignature { + full_name: "V6_vS32b_qpred_ai".to_string(), + short_name: "vS32b_qpred_ai".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::MutPtrHvxVector, + RustType::HvxVector, + ], + }, + ); + + map.insert( + "vS32b_nqpred_ai".to_string(), + BuiltinSignature { + full_name: "V6_vS32b_nqpred_ai".to_string(), + short_name: "vS32b_nqpred_ai".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::MutPtrHvxVector, + RustType::HvxVector, + ], + }, + ); + + map.insert( + "vS32b_nt_qpred_ai".to_string(), + BuiltinSignature { + full_name: "V6_vS32b_nt_qpred_ai".to_string(), + short_name: "vS32b_nt_qpred_ai".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::MutPtrHvxVector, + RustType::HvxVector, + ], + }, + ); + + map.insert( + "vS32b_nt_nqpred_ai".to_string(), + BuiltinSignature { + full_name: "V6_vS32b_nt_nqpred_ai".to_string(), + short_name: "vS32b_nt_nqpred_ai".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::MutPtrHvxVector, + RustType::HvxVector, + ], + }, + ); + + // Conditional accumulation operations + for (suffix, _elem) in [("b", "byte"), ("h", "halfword"), ("w", "word")] { + // vaddbq, vaddhq, vaddwq + map.insert( + format!("vadd{}q", suffix), + BuiltinSignature { + full_name: format!("V6_vadd{}q", suffix), + short_name: format!("vadd{}q", suffix), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + // vaddbnq, vaddhnq, vaddwnq + map.insert( + format!("vadd{}nq", suffix), + BuiltinSignature { + full_name: format!("V6_vadd{}nq", suffix), + short_name: format!("vadd{}nq", suffix), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + } + + // Comparison operations with accumulation + // veqb_and, veqb_or, veqb_xor, etc. + for elem in ["b", "h", "w", "ub", "uh", "uw"] { + for op in ["and", "or", "xor"] { + // veq*_and, veq*_or, veq*_xor + map.insert( + format!("veq{}_{}", elem, op), + BuiltinSignature { + full_name: format!("V6_veq{}_{}", elem, op), + short_name: format!("veq{}_{}", elem, op), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + // vgt*_and, vgt*_or, vgt*_xor + map.insert( + format!("vgt{}_{}", elem, op), + BuiltinSignature { + full_name: format!("V6_vgt{}_{}", elem, op), + short_name: format!("vgt{}_{}", elem, op), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + } + } + + // Floating-point comparison operations (hf = half-float, sf = single-float) + for elem in ["hf", "sf"] { + // Basic comparison: vgt* + map.insert( + format!("vgt{}", elem), + BuiltinSignature { + full_name: format!("V6_vgt{}", elem), + short_name: format!("vgt{}", elem), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + for op in ["and", "or", "xor"] { + // vgt*_and, vgt*_or, vgt*_xor + map.insert( + format!("vgt{}_{}", elem, op), + BuiltinSignature { + full_name: format!("V6_vgt{}_{}", elem, op), + short_name: format!("vgt{}_{}", elem, op), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + } + } + + // Prefix operations with predicate + for elem in ["b", "h", "w"] { + map.insert( + format!("vprefixq{}", elem), + BuiltinSignature { + full_name: format!("V6_vprefixq{}", elem), + short_name: format!("vprefixq{}", elem), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector], + }, + ); + } + + // Scatter operations with predicate + map.insert( + "vscattermhq".to_string(), + BuiltinSignature { + full_name: "V6_vscattermhq".to_string(), + short_name: "vscattermhq".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::I32, + RustType::I32, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + + map.insert( + "vscattermhwq".to_string(), + BuiltinSignature { + full_name: "V6_vscattermhwq".to_string(), + short_name: "vscattermhwq".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::I32, + RustType::I32, + RustType::HvxVectorPair, + RustType::HvxVector, + ], + }, + ); + + map.insert( + "vscattermwq".to_string(), + BuiltinSignature { + full_name: "V6_vscattermwq".to_string(), + short_name: "vscattermwq".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::HvxVector, + RustType::I32, + RustType::I32, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + + // Add with carry saturation + map.insert( + "vaddcarrysat".to_string(), + BuiltinSignature { + full_name: "V6_vaddcarrysat".to_string(), + short_name: "vaddcarrysat".to_string(), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + + // Gather operations with predicate + map.insert( + "vgathermhq".to_string(), + BuiltinSignature { + full_name: "V6_vgathermhq".to_string(), + short_name: "vgathermhq".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::MutPtrHvxVector, + RustType::HvxVector, + RustType::I32, + RustType::I32, + RustType::HvxVector, + ], + }, + ); + + map.insert( + "vgathermhwq".to_string(), + BuiltinSignature { + full_name: "V6_vgathermhwq".to_string(), + short_name: "vgathermhwq".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::MutPtrHvxVector, + RustType::HvxVector, + RustType::I32, + RustType::I32, + RustType::HvxVectorPair, + ], + }, + ); + + map.insert( + "vgathermwq".to_string(), + BuiltinSignature { + full_name: "V6_vgathermwq".to_string(), + short_name: "vgathermwq".to_string(), + return_type: RustType::Unit, + param_types: vec![ + RustType::MutPtrHvxVector, + RustType::HvxVector, + RustType::I32, + RustType::I32, + RustType::HvxVector, + ], + }, + ); + + // Basic comparison operations (without accumulation) + for elem in ["b", "h", "w", "ub", "uh", "uw"] { + // vgt* - greater than + map.insert( + format!("vgt{}", elem), + BuiltinSignature { + full_name: format!("V6_vgt{}", elem), + short_name: format!("vgt{}", elem), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + // veq* - equal + map.insert( + format!("veq{}", elem), + BuiltinSignature { + full_name: format!("V6_veq{}", elem), + short_name: format!("veq{}", elem), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + } + + // Conditional subtraction operations (vsub*q, vsub*nq) + for elem in ["b", "h", "w"] { + map.insert( + format!("vsub{}q", elem), + BuiltinSignature { + full_name: format!("V6_vsub{}q", elem), + short_name: format!("vsub{}q", elem), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + map.insert( + format!("vsub{}nq", elem), + BuiltinSignature { + full_name: format!("V6_vsub{}nq", elem), + short_name: format!("vsub{}nq", elem), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + } + + // vmux - vector mux (select based on predicate) + map.insert( + "vmux".to_string(), + BuiltinSignature { + full_name: "V6_vmux".to_string(), + short_name: "vmux".to_string(), + return_type: RustType::HvxVector, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + + // vswap - vector swap based on predicate + map.insert( + "vswap".to_string(), + BuiltinSignature { + full_name: "V6_vswap".to_string(), + short_name: "vswap".to_string(), + return_type: RustType::HvxVectorPair, + param_types: vec![ + RustType::HvxVector, + RustType::HvxVector, + RustType::HvxVector, + ], + }, + ); + + // shuffeq operations - take vectors (internal pred representation) and return vector + for elem in ["h", "w"] { + map.insert( + format!("shuffeq{}", elem), + BuiltinSignature { + full_name: format!("V6_shuffeq{}", elem), + short_name: format!("shuffeq{}", elem), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + } + + // Predicate AND with vector operations + map.insert( + "vandvqv".to_string(), + BuiltinSignature { + full_name: "V6_vandvqv".to_string(), + short_name: "vandvqv".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + map.insert( + "vandvnqv".to_string(), + BuiltinSignature { + full_name: "V6_vandvnqv".to_string(), + short_name: "vandvnqv".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector], + }, + ); + + // vandnqrt and vandnqrt_acc + map.insert( + "vandnqrt".to_string(), + BuiltinSignature { + full_name: "V6_vandnqrt".to_string(), + short_name: "vandnqrt".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::I32], + }, + ); + + map.insert( + "vandnqrt_acc".to_string(), + BuiltinSignature { + full_name: "V6_vandnqrt_acc".to_string(), + short_name: "vandnqrt_acc".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::HvxVector, RustType::HvxVector, RustType::I32], + }, + ); + + // pred_scalar2v2 + map.insert( + "pred_scalar2v2".to_string(), + BuiltinSignature { + full_name: "V6_pred_scalar2v2".to_string(), + short_name: "pred_scalar2v2".to_string(), + return_type: RustType::HvxVector, + param_types: vec![RustType::I32], + }, + ); + + map +} + +/// Generate extern declarations for all intrinsics for a specific vector mode +fn generate_extern_block(intrinsics: &[IntrinsicInfo], mode: VectorMode) -> String { + let mut output = String::new(); + + // Collect unique builtins to avoid duplicates + let mut seen_builtins: HashSet = HashSet::new(); + let mut decls: Vec<(String, String, RustType, Vec)> = Vec::new(); + + // First, add simple intrinsics + for info in intrinsics.iter().filter(|i| !i.is_compound) { + if seen_builtins.contains(&info.builtin_name) { + continue; + } + seen_builtins.insert(info.builtin_name.clone()); + + let param_types: Vec = info.params.iter().map(|(_, t)| t.clone()).collect(); + decls.push(( + info.builtin_name.clone(), + info.instr_name.clone(), + info.return_type.clone(), + param_types, + )); + } + + // Then, collect all builtins used in compound expressions + let helper_sigs = get_compound_helper_signatures(); + let mut compound_builtins: HashSet = HashSet::new(); + + for info in intrinsics.iter().filter(|i| i.is_compound) { + if let Some(ref expr) = info.compound_expr { + collect_builtins_from_expr(expr, &mut compound_builtins); + } + } + + // Add compound helper builtins + let mut missing_builtins = Vec::new(); + for builtin_name in compound_builtins { + let full_name = format!("V6_{}", builtin_name); + if seen_builtins.contains(&full_name) { + continue; + } + seen_builtins.insert(full_name.clone()); + + if let Some(sig) = helper_sigs.get(&builtin_name) { + decls.push(( + sig.full_name.clone(), + sig.short_name.clone(), + sig.return_type.clone(), + sig.param_types.clone(), + )); + } else { + missing_builtins.push(builtin_name); + } + } + + // Report missing builtins (for development purposes) + if !missing_builtins.is_empty() { + eprintln!("Warning: Missing helper signatures for compound builtins:"); + for name in &missing_builtins { + eprintln!(" - {}", name); + } + } + + // Sort by builtin name for consistent output + decls.sort_by(|a, b| a.0.cmp(&b.0)); + + // Generate intrinsic declarations for the specified mode + output.push_str(&format!( + "// LLVM intrinsic declarations for {}-byte vector mode\n", + mode.bytes() + )); + output.push_str("#[allow(improper_ctypes)]\n"); + output.push_str("unsafe extern \"unadjusted\" {\n"); + + for (builtin_name, instr_name, return_type, param_types) in &decls { + let base_link = builtin_name.replace('_', "."); + // 128-byte mode uses .128B suffix, 64-byte mode doesn't + let link_name = if builtin_name.starts_with("V6_") && mode == VectorMode::V128 { + format!("llvm.hexagon.{}.128B", base_link) + } else { + format!("llvm.hexagon.{}", base_link) + }; + + let params_str = if param_types.is_empty() { + String::new() + } else { + param_types + .iter() + .map(|t| format!("_: {}", t.to_extern_str())) + .collect::>() + .join(", ") + }; + + let return_str = if *return_type == RustType::Unit { + " -> ()".to_string() + } else { + format!(" -> {}", return_type.to_extern_str()) + }; + + output.push_str(&format!( + " #[link_name = \"{}\"]\n fn {}({}){};\n", + link_name, instr_name, params_str, return_str + )); + } + + output.push_str("}\n"); + output +} + +/// Generate Rust code for a compound expression +/// `params` maps parameter names to their types in the function signature +/// Get the type of an expression +fn get_expr_type( + expr: &CompoundExpr, + params: &HashMap, + helper_sigs: &HashMap, +) -> Option { + match expr { + CompoundExpr::BuiltinCall(name, _) => { + helper_sigs.get(name).map(|sig| sig.return_type.clone()) + } + CompoundExpr::Param(name) => params.get(name).cloned(), + CompoundExpr::IntLiteral(_) => Some(RustType::I32), + } +} + +fn generate_compound_expr_code( + expr: &CompoundExpr, + params: &HashMap, + helper_sigs: &HashMap, +) -> String { + match expr { + CompoundExpr::BuiltinCall(name, args) => { + // Get the expected parameter types for this builtin + let expected_types = helper_sigs + .get(name) + .map(|sig| sig.param_types.clone()) + .unwrap_or_default(); + + let args_code: Vec = args + .iter() + .enumerate() + .map(|(i, arg)| { + let arg_code = generate_compound_expr_code(arg, params, helper_sigs); + + // Check if we need to transmute this argument + let expected_type = expected_types.get(i); + let actual_type = get_expr_type(arg, params, helper_sigs); + + // If the builtin expects HvxVector but the arg is HvxVectorPred, transmute + if expected_type == Some(&RustType::HvxVector) + && actual_type == Some(RustType::HvxVectorPred) + { + format!( + "core::mem::transmute::({})", + arg_code + ) + } else { + arg_code + } + }) + .collect(); + format!("{}({})", name, args_code.join(", ")) + } + CompoundExpr::Param(name) => name.clone(), + CompoundExpr::IntLiteral(n) => n.to_string(), + } +} + +/// Get the primary instruction name from a compound expression (innermost significant op) +fn get_compound_primary_instr(expr: &CompoundExpr) -> Option { + match expr { + CompoundExpr::BuiltinCall(name, args) => { + // For vandqrt wrapper, look inside + if name == "vandqrt" && !args.is_empty() { + if let Some(inner) = get_compound_primary_instr(&args[0]) { + return Some(inner); + } + } + // For store operations, use the store name + if name.starts_with("vS32b") { + return Some(name.clone()); + } + // For conditional accumulation, use the add name + if name.starts_with("vadd") && (name.ends_with("q") || name.ends_with("nq")) { + return Some(name.clone()); + } + // For predicate operations + if name.starts_with("pred_") { + return Some(name.clone()); + } + // For comparison operations with accumulation + if (name.starts_with("veq") || name.starts_with("vgt")) + && (name.ends_with("_and") || name.ends_with("_or") || name.ends_with("_xor")) + { + return Some(name.clone()); + } + Some(name.clone()) + } + _ => None, + } +} + +/// Get override implementations for specific compound intrinsics. +/// Some C macros rely on implicit type conversions that don't work with +/// our stricter Rust types, so we provide corrected implementations. +fn get_compound_overrides() -> HashMap<&'static str, &'static str> { + let mut map = HashMap::new(); + + // Q6_V_vand_QR: takes pred, returns vec + // Use transmute to convert pred to vec for LLVM, call vandvrt + map.insert( + "Q6_V_vand_QR", + "vandvrt(core::mem::transmute::(qu), rt)", + ); + + // Q6_V_vandor_VQR: takes vec and pred, returns vec + map.insert( + "Q6_V_vandor_VQR", + "vandvrt_acc(vx, core::mem::transmute::(qu), rt)", + ); + + // Q6_Q_vand_VR: takes vec, returns pred + map.insert( + "Q6_Q_vand_VR", + "core::mem::transmute::(vandqrt(vu, rt))", + ); + + // Q6_Q_vandor_QVR: takes pred and vec, returns pred + map.insert( + "Q6_Q_vandor_QVR", + "core::mem::transmute::(vandqrt_acc(core::mem::transmute::(qx), vu, rt))", + ); + + map +} + +/// Generate wrapper functions for all intrinsics +fn generate_functions(intrinsics: &[IntrinsicInfo]) -> String { + let mut output = String::new(); + let simd_mappings = get_simd_intrinsic_mappings(); + + // Generate simple intrinsics + for info in intrinsics.iter().filter(|i| !i.is_compound) { + let rust_name = &info.q6_name; + + // Generate doc comment + output.push_str(&format!("/// `{}`\n", info.asm_syntax)); + output.push_str("///\n"); + output.push_str(&format!("/// Instruction Type: {}\n", info.instr_type)); + output.push_str(&format!("/// Execution Slots: {}\n", info.exec_slots)); + + // Generate attributes + output.push_str("#[inline]\n"); + output.push_str(&format!( + "#[cfg_attr(target_arch = \"hexagon\", target_feature(enable = \"hvxv{}\"))]\n", + info.min_arch + )); + + // Check if we should use simd intrinsic instead + let use_simd = simd_mappings.get(info.instr_name.as_str()); + + // assert_instr uses the original instruction name + output.push_str(&format!( + "#[cfg_attr(test, assert_instr({}))]\n", + info.instr_name + )); + + output.push_str(&format!( + "#[unstable(feature = \"stdarch_hexagon\", issue = \"{}\")]\n", + TRACKING_ISSUE + )); + + // Generate function signature + let params_str = info + .params + .iter() + .map(|(name, ty)| format!("{}: {}", name, ty.to_rust_str())) + .collect::>() + .join(", "); + + let return_str = if info.return_type == RustType::Unit { + String::new() + } else { + format!(" -> {}", info.return_type.to_rust_str()) + }; + + output.push_str(&format!( + "pub unsafe fn {}({}){} {{\n", + rust_name, params_str, return_str + )); + + // Generate function body + let args_str = info + .params + .iter() + .map(|(name, _)| name.as_str()) + .collect::>() + .join(", "); + + if let Some(simd_fn) = use_simd { + // Use architecture-independent simd intrinsic + output.push_str(&format!(" {}({})\n", simd_fn, args_str)); + } else { + // Use the LLVM intrinsic + output.push_str(&format!(" {}({})\n", info.instr_name, args_str)); + } + + output.push_str("}\n\n"); + } + + // Generate compound intrinsics + let helper_sigs = get_compound_helper_signatures(); + let overrides = get_compound_overrides(); + for info in intrinsics.iter().filter(|i| i.is_compound) { + if let Some(ref compound_expr) = info.compound_expr { + let rust_name = &info.q6_name; + + // Get the primary instruction for assert_instr + let _primary_instr = get_compound_primary_instr(compound_expr) + .unwrap_or_else(|| info.instr_name.clone()); + + // Generate doc comment + output.push_str(&format!("/// `{}`\n", info.asm_syntax)); + output.push_str("///\n"); + output.push_str( + "/// This is a compound operation composed of multiple HVX instructions.\n", + ); + if !info.instr_type.is_empty() { + output.push_str(&format!("/// Instruction Type: {}\n", info.instr_type)); + } + if !info.exec_slots.is_empty() { + output.push_str(&format!("/// Execution Slots: {}\n", info.exec_slots)); + } + + // Generate attributes + output.push_str("#[inline]\n"); + output.push_str(&format!( + "#[cfg_attr(target_arch = \"hexagon\", target_feature(enable = \"hvxv{}\"))]\n", + info.min_arch + )); + + // For compound ops, we skip assert_instr since they emit multiple instructions + // output.push_str(&format!( + // "#[cfg_attr(test, assert_instr({}))]\n", + // primary_instr + // )); + + output.push_str(&format!( + "#[unstable(feature = \"stdarch_hexagon\", issue = \"{}\")]\n", + TRACKING_ISSUE + )); + + // Generate function signature + let params_str = info + .params + .iter() + .map(|(name, ty)| format!("{}: {}", name, ty.to_rust_str())) + .collect::>() + .join(", "); + + let return_str = if info.return_type == RustType::Unit { + String::new() + } else { + format!(" -> {}", info.return_type.to_rust_str()) + }; + + output.push_str(&format!( + "pub unsafe fn {}({}){} {{\n", + rust_name, params_str, return_str + )); + + // Check if we have an override for this intrinsic + let body = if let Some(override_body) = overrides.get(info.q6_name.as_str()) { + override_body.to_string() + } else { + // Build param type map for expression code generation + let param_types: HashMap = info.params.iter().cloned().collect(); + // Generate function body from compound expression + let expr_body = + generate_compound_expr_code(compound_expr, ¶m_types, &helper_sigs); + + // Check if we need to transmute the result + let expr_return_type = get_expr_type(compound_expr, ¶m_types, &helper_sigs); + if info.return_type == RustType::HvxVectorPred + && expr_return_type == Some(RustType::HvxVector) + { + format!( + "core::mem::transmute::({})", + expr_body + ) + } else { + expr_body + } + }; + output.push_str(&format!(" {}\n", body)); + + output.push_str("}\n\n"); + } + } + + output +} + +/// Generate a module file for a specific vector mode +fn generate_module_file( + intrinsics: &[IntrinsicInfo], + output_path: &Path, + mode: VectorMode, +) -> Result<(), String> { + let mut output = + File::create(output_path).map_err(|e| format!("Failed to create output: {}", e))?; + + writeln!(output, "{}", GENERATED_MARKER).map_err(|e| e.to_string())?; + writeln!(output, "{}", generate_module_doc(mode)).map_err(|e| e.to_string())?; + writeln!(output, "{}", generate_types(mode)).map_err(|e| e.to_string())?; + writeln!(output, "{}", generate_extern_block(intrinsics, mode)).map_err(|e| e.to_string())?; + writeln!(output, "{}", generate_functions(intrinsics)).map_err(|e| e.to_string())?; + + // Ensure file is flushed before running rustfmt + drop(output); + + // Run rustfmt on the generated file + let status = std::process::Command::new("rustfmt") + .arg(output_path) + .status() + .map_err(|e| format!("Failed to run rustfmt: {}", e))?; + + if !status.success() { + return Err("rustfmt failed".to_string()); + } + + Ok(()) +} + +/// Parse the HVX header in `crate_dir` and write `v64.rs` and `v128.rs` into `out_dir`. +pub fn generate(crate_dir: &std::path::Path, out_dir: &std::path::Path) -> Result<(), String> { + let header_content = read_header(crate_dir)?; + let all_intrinsics = parse_header(&header_content); + let intrinsics: Vec<_> = all_intrinsics + .into_iter() + .filter(|i| i.min_arch <= MAX_SUPPORTED_ARCH) + .collect(); + for (filename, vmode) in [("v64.rs", VectorMode::V64), ("v128.rs", VectorMode::V128)] { + let path = out_dir.join(filename); + generate_module_file(&intrinsics, &path, vmode)?; + } + Ok(()) +} diff --git a/library/stdarch/crates/stdarch-gen-hexagon/src/main.rs b/library/stdarch/crates/stdarch-gen-hexagon/src/main.rs index c3ad153ab0a7a..88ef4fe11f332 100644 --- a/library/stdarch/crates/stdarch-gen-hexagon/src/main.rs +++ b/library/stdarch/crates/stdarch-gen-hexagon/src/main.rs @@ -1,1728 +1,35 @@ -//! Hexagon HVX Code Generator +//! Hexagon code generator. //! -//! This generator creates v64.rs and v128.rs from scratch using the LLVM HVX -//! header file as the sole source of truth. It parses the C intrinsic prototypes -//! and generates Rust wrapper functions with appropriate attributes. +//! Single binary that produces every generated file under +//! `core_arch/src/hexagon/`: scalar.rs (scalar intrinsics) and +//! v64.rs / v128.rs (HVX intrinsics). //! -//! The two generated files provide: -//! - v64.rs: 64-byte vector mode intrinsics (512-bit vectors) -//! - v128.rs: 128-byte vector mode intrinsics (1024-bit vectors) -//! -//! Both modules are available unconditionally, but require the appropriate -//! target features to actually use the intrinsics. -//! -//! Usage: -//! cd crates/stdarch-gen-hexagon -//! cargo run -//! # Output is written to ../core_arch/src/hexagon/v64.rs and v128.rs - -use regex::Regex; -use std::collections::{HashMap, HashSet}; -use std::fs::File; -use std::io::Write; -use std::path::Path; -use stdarch_gen_common::{run_generator, Mode, GENERATED_MARKER}; - -/// Mappings from HVX intrinsics to architecture-independent SIMD intrinsics. -/// These intrinsics have equivalent semantics and can be lowered to the generic form. -fn get_simd_intrinsic_mappings() -> HashMap<&'static str, &'static str> { - let mut map = HashMap::new(); - // Bitwise operations (element-size independent) - map.insert("vxor", "simd_xor"); - map.insert("vand", "simd_and"); - map.insert("vor", "simd_or"); - // Word (32-bit) arithmetic operations - map.insert("vaddw", "simd_add"); - map.insert("vsubw", "simd_sub"); - map -} - -/// The tracking issue number for the stdarch_hexagon feature -const TRACKING_ISSUE: &str = "151523"; - -/// HVX vector length mode -#[derive(Debug, Clone, Copy, PartialEq)] -enum VectorMode { - /// 64-byte vectors (512 bits) - V64, - /// 128-byte vectors (1024 bits) - V128, -} - -impl VectorMode { - fn bytes(&self) -> u32 { - match self { - VectorMode::V64 => 64, - VectorMode::V128 => 128, - } - } - - fn bits(&self) -> u32 { - self.bytes() * 8 - } - - fn lanes(&self) -> u32 { - self.bytes() / 4 // 32-bit lanes - } - - fn target_feature(&self) -> &'static str { - match self { - VectorMode::V64 => "hvx-length64b", - VectorMode::V128 => "hvx-length128b", - } - } -} - -/// LLVM version the header file is from (for reference) -/// Source: https://github.com/llvm/llvm-project/blob/llvmorg-22.1.0-rc1/clang/lib/Headers/hvx_hexagon_protos.h -const LLVM_VERSION: &str = "22.1.0-rc1"; - -/// Maximum HVX architecture version supported by rustc -/// Check with: rustc --target=hexagon-unknown-linux-musl --print target-features -const MAX_SUPPORTED_ARCH: u32 = 79; - -/// Local header file path (checked into the repository) -const HEADER_FILE: &str = "hvx_hexagon_protos.h"; - -/// Intrinsic information parsed from the LLVM header -#[derive(Debug, Clone)] -struct IntrinsicInfo { - /// The Q6_* intrinsic name (e.g., "Q6_V_vadd_VV") - q6_name: String, - /// The LLVM builtin name without prefix (e.g., "V6_vaddb") - builtin_name: String, - /// The short instruction name for assert_instr (e.g., "vaddb") - instr_name: String, - /// The assembly syntax from the comment - asm_syntax: String, - /// Instruction type - instr_type: String, - /// Execution slots - exec_slots: String, - /// Minimum HVX architecture version required - min_arch: u32, - /// Return type - return_type: RustType, - /// Parameters (name, type) - params: Vec<(String, RustType)>, - /// Whether this is a compound intrinsic (multiple builtins) - is_compound: bool, - /// For compound intrinsics: the parsed expression tree - compound_expr: Option, -} - -/// Expression tree for compound intrinsics -#[derive(Debug, Clone)] -enum CompoundExpr { - /// A call to a builtin: (builtin_name without V6_ prefix, arguments) - BuiltinCall(String, Vec), - /// A parameter reference by name - Param(String), - /// An integer literal (like -1) - IntLiteral(i32), -} - -/// Rust type mappings -#[derive(Debug, Clone, PartialEq)] -enum RustType { - HvxVector, - HvxVectorPair, - HvxVectorPred, - I32, - MutPtrHvxVector, - Unit, -} - -impl RustType { - fn from_c_type(c_type: &str) -> Option { - match c_type.trim() { - "HVX_Vector" => Some(RustType::HvxVector), - "HVX_VectorPair" => Some(RustType::HvxVectorPair), - "HVX_VectorPred" => Some(RustType::HvxVectorPred), - "Word32" => Some(RustType::I32), - "HVX_Vector*" => Some(RustType::MutPtrHvxVector), - "void" => Some(RustType::Unit), - _ => None, - } - } - - fn to_rust_str(&self) -> &'static str { - match self { - RustType::HvxVector => "HvxVector", - RustType::HvxVectorPair => "HvxVectorPair", - RustType::HvxVectorPred => "HvxVectorPred", - RustType::I32 => "i32", - RustType::MutPtrHvxVector => "*mut HvxVector", - RustType::Unit => "()", - } - } - - fn to_extern_str(&self) -> &'static str { - match self { - RustType::HvxVector => "HvxVector", - RustType::HvxVectorPair => "HvxVectorPair", - RustType::HvxVectorPred => "HvxVectorPred", - RustType::I32 => "i32", - RustType::MutPtrHvxVector => "*mut HvxVector", - RustType::Unit => "()", - } - } -} - -/// Parse a compound macro expression into an expression tree -fn parse_compound_expr(expr: &str) -> Option { - let expr = expr.trim(); - - // Try to match an integer literal (like -1) - if let Ok(n) = expr.parse::() { - return Some(CompoundExpr::IntLiteral(n)); - } - - // Try to match a simple parameter name (Vu, Vv, Rt, Qs, Qt, Qx, Vx, etc.) - // These are typically short identifiers in the macro - if expr.len() <= 3 - && expr.chars().all(|c| c.is_ascii_alphanumeric() || c == '_') - && !expr.contains("__") - { - return Some(CompoundExpr::Param(expr.to_lowercase())); - } - - // Check if it's wrapped in extra parens first - if expr.starts_with('(') && expr.ends_with(')') { - // Check if these parens wrap the entire expression - let inner = &expr[1..expr.len() - 1]; - // Count depth: if after removing outer parens the expression is balanced, - // the outer parens were enclosing everything - if is_balanced_parens(inner) { - // But we also need to verify these aren't part of a function call - // If the inner expression is balanced and the whole thing starts with ( - // and ends with ), it's a paren wrapper - let result = parse_compound_expr(inner); - if result.is_some() { - return result; - } - } - } - - // Try to match __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_xxx)(args) - // The args portion may contain nested calls, so we need to find the matching paren - if expr.starts_with("__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_") { - // Find the end of the builtin name (after V6_) - let prefix = "__BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_"; - let after_prefix = &expr[prefix.len()..]; - if let Some(paren_pos) = after_prefix.find(')') { - let builtin_name = &after_prefix[..paren_pos]; - let rest = &after_prefix[paren_pos + 1..]; // Skip the closing ) of the WRAP - // rest should now be "(args)" - if rest.starts_with('(') && rest.ends_with(')') { - let args_str = &rest[1..rest.len() - 1]; - let args = parse_compound_args(args_str)?; - return Some(CompoundExpr::BuiltinCall(builtin_name.to_string(), args)); - } - } - } - - // Try to match __builtin_HEXAGON_V6_xxx(args) without wrap - if expr.starts_with("__builtin_HEXAGON_V6_") { - let prefix = "__builtin_HEXAGON_V6_"; - let after_prefix = &expr[prefix.len()..]; - if let Some(paren_pos) = after_prefix.find('(') { - let builtin_name = &after_prefix[..paren_pos]; - let rest = &after_prefix[paren_pos..]; - if rest.starts_with('(') && rest.ends_with(')') { - let args_str = &rest[1..rest.len() - 1]; - let args = parse_compound_args(args_str)?; - return Some(CompoundExpr::BuiltinCall(builtin_name.to_string(), args)); - } - } - } - - None -} - -/// Check if parentheses are balanced in a string -fn is_balanced_parens(s: &str) -> bool { - let mut depth = 0; - for c in s.chars() { - match c { - '(' => depth += 1, - ')' => { - depth -= 1; - if depth < 0 { - return false; - } - } - _ => {} - } - } - depth == 0 -} - -/// Parse comma-separated arguments, respecting nested parentheses -fn parse_compound_args(args_str: &str) -> Option> { - let mut args = Vec::new(); - let mut current = String::new(); - let mut depth = 0; - - for c in args_str.chars() { - match c { - '(' => { - depth += 1; - current.push(c); - } - ')' => { - depth -= 1; - current.push(c); - } - ',' if depth == 0 => { - let arg = current.trim().to_string(); - if !arg.is_empty() { - args.push(parse_compound_expr(&arg)?); - } - current.clear(); - } - _ => current.push(c), - } - } - - // Don't forget the last argument - let arg = current.trim().to_string(); - if !arg.is_empty() { - args.push(parse_compound_expr(&arg)?); - } - - Some(args) -} - -/// Extract all builtin names used in a compound expression -fn collect_builtins_from_expr(expr: &CompoundExpr, builtins: &mut HashSet) { - match expr { - CompoundExpr::BuiltinCall(name, args) => { - builtins.insert(name.clone()); - for arg in args { - collect_builtins_from_expr(arg, builtins); - } - } - CompoundExpr::Param(_) | CompoundExpr::IntLiteral(_) => {} - } -} - -/// Read the local HVX header file -fn read_header(crate_dir: &Path) -> Result { - let header_path = crate_dir.join(HEADER_FILE); - println!("Reading HVX header from: {}", header_path.display()); - println!(" (LLVM version: {})", LLVM_VERSION); - - std::fs::read_to_string(&header_path).map_err(|e| { - format!( - "Failed to read header file {}: {}", - header_path.display(), - e - ) - }) -} - -/// Parse a C function prototype to extract return type and parameters -fn parse_prototype(prototype: &str) -> Option<(RustType, Vec<(String, RustType)>)> { - // Pattern: ReturnType FunctionName(ParamType1 Param1, ParamType2 Param2, ...) - let proto_re = Regex::new(r"(\w+(?:\*)?)\s+Q6_\w+\(([^)]*)\)").unwrap(); - - if let Some(caps) = proto_re.captures(prototype) { - let return_type_str = caps[1].trim(); - let params_str = &caps[2]; - - let return_type = RustType::from_c_type(return_type_str)?; - - let mut params = Vec::new(); - if !params_str.trim().is_empty() { - // Pattern: Type Name or Type* Name - let param_re = Regex::new(r"(\w+\*?)\s+(\w+)").unwrap(); - for param in params_str.split(',') { - let param = param.trim(); - if let Some(pcaps) = param_re.captures(param) { - let ptype_str = pcaps[1].trim(); - let pname = pcaps[2].to_lowercase(); - if let Some(ptype) = RustType::from_c_type(ptype_str) { - params.push((pname, ptype)); - } else { - return None; // Unknown type - } - } - } - } - - Some((return_type, params)) - } else { - None - } -} - -/// Parse the LLVM header file to extract intrinsic information -fn parse_header(content: &str) -> Vec { - let mut intrinsics = Vec::new(); - - let arch_re = Regex::new(r"#if __HVX_ARCH__ >= (\d+)").unwrap(); - - // Regex to extract the simple builtin name from a macro body - // Match: __BUILTIN_VECTOR_WRAP(__builtin_HEXAGON_V6_xxx)(args) - let simple_builtin_re = - Regex::new(r"__BUILTIN_VECTOR_WRAP\(__builtin_HEXAGON_(\w+)\)\([^)]*\)\s*$").unwrap(); - - // Also handle builtins without VECTOR_WRAP - let simple_builtin_re2 = Regex::new(r"__builtin_HEXAGON_(\w+)\([^)]*\)\s*$").unwrap(); - - // Regex to extract Q6 name from #define - let q6_name_re = Regex::new(r"#define\s+(Q6_\w+)").unwrap(); - - // Regex to extract macro expression body - let macro_expr_re = Regex::new(r"#define\s+Q6_\w+\([^)]*\)\s+(.+)").unwrap(); - - let lines: Vec<&str> = content.lines().collect(); - let mut current_arch: u32 = 60; - let mut i = 0; - - while i < lines.len() { - // Track architecture version - if let Some(caps) = arch_re.captures(lines[i]) { - if let Ok(arch) = caps[1].parse() { - current_arch = arch; - } - } - - // Look for Assembly Syntax comment block - if lines[i].contains("Assembly Syntax:") { - let mut asm_syntax = String::new(); - let mut prototype = String::new(); - let mut instr_type = String::new(); - let mut exec_slots = String::new(); - - // Parse the comment block - let mut j = i; - while j < lines.len() && !lines[j].starts_with("#define") { - let line = lines[j]; - if line.contains("Assembly Syntax:") { - if let Some(pos) = line.find("Assembly Syntax:") { - asm_syntax = line[pos + 16..].trim().to_string(); - } - } else if line.contains("C Intrinsic Prototype:") { - if let Some(pos) = line.find("C Intrinsic Prototype:") { - prototype = line[pos + 22..].trim().to_string(); - } - } else if line.contains("Instruction Type:") { - if let Some(pos) = line.find("Instruction Type:") { - instr_type = line[pos + 17..].trim().to_string(); - } - } else if line.contains("Execution Slots:") { - if let Some(pos) = line.find("Execution Slots:") { - exec_slots = line[pos + 16..].trim().to_string(); - } - } - j += 1; - } - - // Now find the #define line - while j < lines.len() && !lines[j].starts_with("#define") { - j += 1; - } - - if j < lines.len() { - let define_line = lines[j]; - - // Extract Q6 name and check if it's simple or compound - if let Some(caps) = q6_name_re.captures(define_line) { - let q6_name = caps[1].to_string(); - - // Get the full macro body (handle line continuations) - let mut macro_body = define_line.to_string(); - let mut k = j; - while macro_body.trim_end().ends_with('\\') && k + 1 < lines.len() { - k += 1; - macro_body.push_str(lines[k]); - } - - // Try to extract simple builtin name - let builtin_name = simple_builtin_re - .captures(¯o_body) - .or_else(|| simple_builtin_re2.captures(¯o_body)) - .map(|bcaps| bcaps[1].to_string()); - - // Check if it's a compound intrinsic (multiple __builtin calls) - let builtin_count = macro_body.matches("__builtin_HEXAGON_").count(); - let is_compound = builtin_count > 1; - - // Parse prototype - if let Some((return_type, params)) = parse_prototype(&prototype) { - if is_compound { - // For compound intrinsics, parse the expression - // Extract the macro body after the parameter list - if let Some(expr_caps) = macro_expr_re.captures(¯o_body) { - let expr_str = expr_caps[1].trim().replace(['\n', '\\'], " "); - let expr_str = expr_str.trim(); - - if let Some(compound_expr) = parse_compound_expr(expr_str) { - // For compound intrinsics, we use the outermost builtin - // as the "primary" for the instruction name - let (primary_builtin, instr_name) = match &compound_expr { - CompoundExpr::BuiltinCall(name, _) => { - (name.clone(), name.clone()) - } - _ => continue, - }; - - intrinsics.push(IntrinsicInfo { - q6_name, - builtin_name: format!("V6_{}", primary_builtin), - instr_name, - asm_syntax, - instr_type, - exec_slots, - min_arch: current_arch, - return_type, - params, - is_compound: true, - compound_expr: Some(compound_expr), - }); - } - } - } else if let Some(builtin) = builtin_name { - // Extract short instruction name - let instr_name = builtin - .strip_prefix("V6_") - .map(|s| s.to_string()) - .unwrap_or_else(|| builtin.clone()); - - intrinsics.push(IntrinsicInfo { - q6_name, - builtin_name: builtin, - instr_name, - asm_syntax, - instr_type, - exec_slots, - min_arch: current_arch, - return_type, - params, - is_compound: false, - compound_expr: None, - }); - } - } - } - } - i = j; - } - i += 1; - } - - intrinsics -} - -/// Generate the module documentation -fn generate_module_doc(mode: VectorMode) -> String { - format!( - r#"//! Hexagon HVX {bytes}-byte vector mode intrinsics -//! -//! This module provides intrinsics for the Hexagon Vector Extensions (HVX) -//! in {bytes}-byte vector mode ({bits}-bit vectors). -//! -//! HVX is a wide vector extension designed for high-performance signal processing. -//! [Hexagon HVX Programmer's Reference Manual](https://docs.qualcomm.com/doc/80-N2040-61) -//! -//! ## Vector Types -//! -//! In {bytes}-byte mode: -//! - `HvxVector` is {bits} bits ({bytes} bytes) containing {lanes} x 32-bit values -//! - `HvxVectorPair` is {pair_bits} bits ({pair_bytes} bytes) -//! - `HvxVectorPred` is {bits} bits ({bytes} bytes) for predicate operations -//! -//! To use this module, compile with `-C target-feature=+{target_feature}`. -//! -//! ## Naming Convention -//! -//! Function names preserve the original Q6 naming case because the convention -//! uses case to distinguish register types: -//! - `W` (uppercase) = vector pair (`HvxVectorPair`) -//! - `V` (uppercase) = vector (`HvxVector`) -//! - `Q` (uppercase) = predicate (`HvxVectorPred`) -//! - `R` = scalar register (`i32`) -//! -//! For example, `Q6_W_vcombine_VV` operates on a vector pair while -//! `Q6_V_hi_W` extracts a vector from a pair. -//! -//! ## Architecture Versions -//! -//! Different intrinsics require different HVX architecture versions. Use the -//! appropriate target feature to enable the required version: -//! - HVX v60: `-C target-feature=+hvxv60` (basic HVX operations) -//! - HVX v62: `-C target-feature=+hvxv62` -//! - HVX v65: `-C target-feature=+hvxv65` (includes floating-point support) -//! - HVX v66: `-C target-feature=+hvxv66` -//! - HVX v68: `-C target-feature=+hvxv68` -//! - HVX v69: `-C target-feature=+hvxv69` -//! - HVX v73: `-C target-feature=+hvxv73` -//! - HVX v79: `-C target-feature=+hvxv79` -//! -//! Each version includes all features from previous versions. -"#, - bytes = mode.bytes(), - bits = mode.bits(), - lanes = mode.lanes(), - pair_bytes = mode.bytes() * 2, - pair_bits = mode.bits() * 2, - target_feature = mode.target_feature(), - ) -} - -/// Generate the type definitions for a specific vector mode -fn generate_types(mode: VectorMode) -> String { - let lanes = mode.lanes(); - let pair_lanes = lanes * 2; - let bits = mode.bits(); - let bytes = mode.bytes(); - let pair_bits = bits * 2; - let pair_bytes = bytes * 2; - - format!( - r#" -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -#[cfg(test)] -use stdarch_test::assert_instr; - -use crate::intrinsics::simd::{{simd_add, simd_and, simd_or, simd_sub, simd_xor}}; - -// HVX type definitions for {bytes}-byte vector mode -types! {{ - #![unstable(feature = "stdarch_hexagon", issue = "{TRACKING_ISSUE}")] - - /// HVX vector type ({bits} bits / {bytes} bytes) - /// - /// This type represents a single HVX vector register containing {lanes} x 32-bit values. - pub struct HvxVector({lanes} x i32); - - /// HVX vector pair type ({pair_bits} bits / {pair_bytes} bytes) - /// - /// This type represents a pair of HVX vector registers, often used for - /// operations that produce double-width results. - pub struct HvxVectorPair({pair_lanes} x i32); - - /// HVX vector predicate type ({bits} bits / {bytes} bytes) - /// - /// This type represents a predicate vector used for conditional operations. - /// Each bit corresponds to a lane in the vector. - pub struct HvxVectorPred({lanes} x i32); -}} -"#, - bytes = bytes, - bits = bits, - lanes = lanes, - pair_bits = pair_bits, - pair_bytes = pair_bytes, - pair_lanes = pair_lanes, - TRACKING_ISSUE = TRACKING_ISSUE, - ) -} - -/// Builtin signature information for extern declarations -struct BuiltinSignature { - /// The V6_ prefixed name - full_name: String, - /// The short name (without V6_) - short_name: String, - /// Return type - return_type: RustType, - /// Parameter types - param_types: Vec, -} - -/// Get known signatures for builtins used in compound operations -/// These are the helper builtins that don't have their own Q6_ wrapper -fn get_compound_helper_signatures() -> HashMap { - let mut map = HashMap::new(); - - // vandvrt: HVX_Vector -> i32 -> HVX_Vector - // Converts predicate to vector representation. LLVM uses HVX_Vector for both. - map.insert( - "vandvrt".to_string(), - BuiltinSignature { - full_name: "V6_vandvrt".to_string(), - short_name: "vandvrt".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::I32], - }, - ); - - // vandqrt: HVX_Vector -> i32 -> HVX_Vector - // Converts vector representation back to predicate. LLVM uses HVX_Vector for both. - map.insert( - "vandqrt".to_string(), - BuiltinSignature { - full_name: "V6_vandqrt".to_string(), - short_name: "vandqrt".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::I32], - }, - ); - - // vandvrt_acc: HVX_Vector -> HVX_Vector -> i32 -> HVX_Vector - map.insert( - "vandvrt_acc".to_string(), - BuiltinSignature { - full_name: "V6_vandvrt_acc".to_string(), - short_name: "vandvrt_acc".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector, RustType::I32], - }, - ); - - // vandqrt_acc: HVX_Vector -> HVX_Vector -> i32 -> HVX_Vector - map.insert( - "vandqrt_acc".to_string(), - BuiltinSignature { - full_name: "V6_vandqrt_acc".to_string(), - short_name: "vandqrt_acc".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector, RustType::I32], - }, - ); - - // pred_and: HVX_Vector -> HVX_Vector -> HVX_Vector - map.insert( - "pred_and".to_string(), - BuiltinSignature { - full_name: "V6_pred_and".to_string(), - short_name: "pred_and".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - - // pred_and_n: HVX_Vector -> HVX_Vector -> HVX_Vector - map.insert( - "pred_and_n".to_string(), - BuiltinSignature { - full_name: "V6_pred_and_n".to_string(), - short_name: "pred_and_n".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - - // pred_or: HVX_Vector -> HVX_Vector -> HVX_Vector - map.insert( - "pred_or".to_string(), - BuiltinSignature { - full_name: "V6_pred_or".to_string(), - short_name: "pred_or".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - - // pred_or_n: HVX_Vector -> HVX_Vector -> HVX_Vector - map.insert( - "pred_or_n".to_string(), - BuiltinSignature { - full_name: "V6_pred_or_n".to_string(), - short_name: "pred_or_n".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); +//! Run in check or bless mode via `STDARCH_GEN_MODE`. - // pred_xor: HVX_Vector -> HVX_Vector -> HVX_Vector - map.insert( - "pred_xor".to_string(), - BuiltinSignature { - full_name: "V6_pred_xor".to_string(), - short_name: "pred_xor".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); +mod hvx; +mod scalar; - // pred_not: HVX_Vector -> HVX_Vector - map.insert( - "pred_not".to_string(), - BuiltinSignature { - full_name: "V6_pred_not".to_string(), - short_name: "pred_not".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector], - }, - ); - - // pred_scalar2: i32 -> HVX_Vector - map.insert( - "pred_scalar2".to_string(), - BuiltinSignature { - full_name: "V6_pred_scalar2".to_string(), - short_name: "pred_scalar2".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::I32], - }, - ); - - // Conditional store operations - map.insert( - "vS32b_qpred_ai".to_string(), - BuiltinSignature { - full_name: "V6_vS32b_qpred_ai".to_string(), - short_name: "vS32b_qpred_ai".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::MutPtrHvxVector, - RustType::HvxVector, - ], - }, - ); - - map.insert( - "vS32b_nqpred_ai".to_string(), - BuiltinSignature { - full_name: "V6_vS32b_nqpred_ai".to_string(), - short_name: "vS32b_nqpred_ai".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::MutPtrHvxVector, - RustType::HvxVector, - ], - }, - ); - - map.insert( - "vS32b_nt_qpred_ai".to_string(), - BuiltinSignature { - full_name: "V6_vS32b_nt_qpred_ai".to_string(), - short_name: "vS32b_nt_qpred_ai".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::MutPtrHvxVector, - RustType::HvxVector, - ], - }, - ); - - map.insert( - "vS32b_nt_nqpred_ai".to_string(), - BuiltinSignature { - full_name: "V6_vS32b_nt_nqpred_ai".to_string(), - short_name: "vS32b_nt_nqpred_ai".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::MutPtrHvxVector, - RustType::HvxVector, - ], - }, - ); - - // Conditional accumulation operations - for (suffix, _elem) in [("b", "byte"), ("h", "halfword"), ("w", "word")] { - // vaddbq, vaddhq, vaddwq - map.insert( - format!("vadd{}q", suffix), - BuiltinSignature { - full_name: format!("V6_vadd{}q", suffix), - short_name: format!("vadd{}q", suffix), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - // vaddbnq, vaddhnq, vaddwnq - map.insert( - format!("vadd{}nq", suffix), - BuiltinSignature { - full_name: format!("V6_vadd{}nq", suffix), - short_name: format!("vadd{}nq", suffix), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - } - - // Comparison operations with accumulation - // veqb_and, veqb_or, veqb_xor, etc. - for elem in ["b", "h", "w", "ub", "uh", "uw"] { - for op in ["and", "or", "xor"] { - // veq*_and, veq*_or, veq*_xor - map.insert( - format!("veq{}_{}", elem, op), - BuiltinSignature { - full_name: format!("V6_veq{}_{}", elem, op), - short_name: format!("veq{}_{}", elem, op), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - // vgt*_and, vgt*_or, vgt*_xor - map.insert( - format!("vgt{}_{}", elem, op), - BuiltinSignature { - full_name: format!("V6_vgt{}_{}", elem, op), - short_name: format!("vgt{}_{}", elem, op), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - } - } - - // Floating-point comparison operations (hf = half-float, sf = single-float) - for elem in ["hf", "sf"] { - // Basic comparison: vgt* - map.insert( - format!("vgt{}", elem), - BuiltinSignature { - full_name: format!("V6_vgt{}", elem), - short_name: format!("vgt{}", elem), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - - for op in ["and", "or", "xor"] { - // vgt*_and, vgt*_or, vgt*_xor - map.insert( - format!("vgt{}_{}", elem, op), - BuiltinSignature { - full_name: format!("V6_vgt{}_{}", elem, op), - short_name: format!("vgt{}_{}", elem, op), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - } - } - - // Prefix operations with predicate - for elem in ["b", "h", "w"] { - map.insert( - format!("vprefixq{}", elem), - BuiltinSignature { - full_name: format!("V6_vprefixq{}", elem), - short_name: format!("vprefixq{}", elem), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector], - }, - ); - } - - // Scatter operations with predicate - map.insert( - "vscattermhq".to_string(), - BuiltinSignature { - full_name: "V6_vscattermhq".to_string(), - short_name: "vscattermhq".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::I32, - RustType::I32, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - - map.insert( - "vscattermhwq".to_string(), - BuiltinSignature { - full_name: "V6_vscattermhwq".to_string(), - short_name: "vscattermhwq".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::I32, - RustType::I32, - RustType::HvxVectorPair, - RustType::HvxVector, - ], - }, - ); - - map.insert( - "vscattermwq".to_string(), - BuiltinSignature { - full_name: "V6_vscattermwq".to_string(), - short_name: "vscattermwq".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::HvxVector, - RustType::I32, - RustType::I32, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - - // Add with carry saturation - map.insert( - "vaddcarrysat".to_string(), - BuiltinSignature { - full_name: "V6_vaddcarrysat".to_string(), - short_name: "vaddcarrysat".to_string(), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - - // Gather operations with predicate - map.insert( - "vgathermhq".to_string(), - BuiltinSignature { - full_name: "V6_vgathermhq".to_string(), - short_name: "vgathermhq".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::MutPtrHvxVector, - RustType::HvxVector, - RustType::I32, - RustType::I32, - RustType::HvxVector, - ], - }, - ); - - map.insert( - "vgathermhwq".to_string(), - BuiltinSignature { - full_name: "V6_vgathermhwq".to_string(), - short_name: "vgathermhwq".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::MutPtrHvxVector, - RustType::HvxVector, - RustType::I32, - RustType::I32, - RustType::HvxVectorPair, - ], - }, - ); - - map.insert( - "vgathermwq".to_string(), - BuiltinSignature { - full_name: "V6_vgathermwq".to_string(), - short_name: "vgathermwq".to_string(), - return_type: RustType::Unit, - param_types: vec![ - RustType::MutPtrHvxVector, - RustType::HvxVector, - RustType::I32, - RustType::I32, - RustType::HvxVector, - ], - }, - ); - - // Basic comparison operations (without accumulation) - for elem in ["b", "h", "w", "ub", "uh", "uw"] { - // vgt* - greater than - map.insert( - format!("vgt{}", elem), - BuiltinSignature { - full_name: format!("V6_vgt{}", elem), - short_name: format!("vgt{}", elem), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - // veq* - equal - map.insert( - format!("veq{}", elem), - BuiltinSignature { - full_name: format!("V6_veq{}", elem), - short_name: format!("veq{}", elem), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - } - - // Conditional subtraction operations (vsub*q, vsub*nq) - for elem in ["b", "h", "w"] { - map.insert( - format!("vsub{}q", elem), - BuiltinSignature { - full_name: format!("V6_vsub{}q", elem), - short_name: format!("vsub{}q", elem), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - map.insert( - format!("vsub{}nq", elem), - BuiltinSignature { - full_name: format!("V6_vsub{}nq", elem), - short_name: format!("vsub{}nq", elem), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - } - - // vmux - vector mux (select based on predicate) - map.insert( - "vmux".to_string(), - BuiltinSignature { - full_name: "V6_vmux".to_string(), - short_name: "vmux".to_string(), - return_type: RustType::HvxVector, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - - // vswap - vector swap based on predicate - map.insert( - "vswap".to_string(), - BuiltinSignature { - full_name: "V6_vswap".to_string(), - short_name: "vswap".to_string(), - return_type: RustType::HvxVectorPair, - param_types: vec![ - RustType::HvxVector, - RustType::HvxVector, - RustType::HvxVector, - ], - }, - ); - - // shuffeq operations - take vectors (internal pred representation) and return vector - for elem in ["h", "w"] { - map.insert( - format!("shuffeq{}", elem), - BuiltinSignature { - full_name: format!("V6_shuffeq{}", elem), - short_name: format!("shuffeq{}", elem), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - } - - // Predicate AND with vector operations - map.insert( - "vandvqv".to_string(), - BuiltinSignature { - full_name: "V6_vandvqv".to_string(), - short_name: "vandvqv".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - - map.insert( - "vandvnqv".to_string(), - BuiltinSignature { - full_name: "V6_vandvnqv".to_string(), - short_name: "vandvnqv".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector], - }, - ); - - // vandnqrt and vandnqrt_acc - map.insert( - "vandnqrt".to_string(), - BuiltinSignature { - full_name: "V6_vandnqrt".to_string(), - short_name: "vandnqrt".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::I32], - }, - ); - - map.insert( - "vandnqrt_acc".to_string(), - BuiltinSignature { - full_name: "V6_vandnqrt_acc".to_string(), - short_name: "vandnqrt_acc".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::HvxVector, RustType::HvxVector, RustType::I32], - }, - ); - - // pred_scalar2v2 - map.insert( - "pred_scalar2v2".to_string(), - BuiltinSignature { - full_name: "V6_pred_scalar2v2".to_string(), - short_name: "pred_scalar2v2".to_string(), - return_type: RustType::HvxVector, - param_types: vec![RustType::I32], - }, - ); - - map -} - -/// Generate extern declarations for all intrinsics for a specific vector mode -fn generate_extern_block(intrinsics: &[IntrinsicInfo], mode: VectorMode) -> String { - let mut output = String::new(); - - // Collect unique builtins to avoid duplicates - let mut seen_builtins: HashSet = HashSet::new(); - let mut decls: Vec<(String, String, RustType, Vec)> = Vec::new(); - - // First, add simple intrinsics - for info in intrinsics.iter().filter(|i| !i.is_compound) { - if seen_builtins.contains(&info.builtin_name) { - continue; - } - seen_builtins.insert(info.builtin_name.clone()); - - let param_types: Vec = info.params.iter().map(|(_, t)| t.clone()).collect(); - decls.push(( - info.builtin_name.clone(), - info.instr_name.clone(), - info.return_type.clone(), - param_types, - )); - } - - // Then, collect all builtins used in compound expressions - let helper_sigs = get_compound_helper_signatures(); - let mut compound_builtins: HashSet = HashSet::new(); - - for info in intrinsics.iter().filter(|i| i.is_compound) { - if let Some(ref expr) = info.compound_expr { - collect_builtins_from_expr(expr, &mut compound_builtins); - } - } - - // Add compound helper builtins - let mut missing_builtins = Vec::new(); - for builtin_name in compound_builtins { - let full_name = format!("V6_{}", builtin_name); - if seen_builtins.contains(&full_name) { - continue; - } - seen_builtins.insert(full_name.clone()); - - if let Some(sig) = helper_sigs.get(&builtin_name) { - decls.push(( - sig.full_name.clone(), - sig.short_name.clone(), - sig.return_type.clone(), - sig.param_types.clone(), - )); - } else { - missing_builtins.push(builtin_name); - } - } - - // Report missing builtins (for development purposes) - if !missing_builtins.is_empty() { - eprintln!("Warning: Missing helper signatures for compound builtins:"); - for name in &missing_builtins { - eprintln!(" - {}", name); - } - } - - // Sort by builtin name for consistent output - decls.sort_by(|a, b| a.0.cmp(&b.0)); - - // Generate intrinsic declarations for the specified mode - output.push_str(&format!( - "// LLVM intrinsic declarations for {}-byte vector mode\n", - mode.bytes() - )); - output.push_str("#[allow(improper_ctypes)]\n"); - output.push_str("unsafe extern \"unadjusted\" {\n"); - - for (builtin_name, instr_name, return_type, param_types) in &decls { - let base_link = builtin_name.replace('_', "."); - // 128-byte mode uses .128B suffix, 64-byte mode doesn't - let link_name = if builtin_name.starts_with("V6_") && mode == VectorMode::V128 { - format!("llvm.hexagon.{}.128B", base_link) - } else { - format!("llvm.hexagon.{}", base_link) - }; - - let params_str = if param_types.is_empty() { - String::new() - } else { - param_types - .iter() - .map(|t| format!("_: {}", t.to_extern_str())) - .collect::>() - .join(", ") - }; - - let return_str = if *return_type == RustType::Unit { - " -> ()".to_string() - } else { - format!(" -> {}", return_type.to_extern_str()) - }; - - output.push_str(&format!( - " #[link_name = \"{}\"]\n fn {}({}){};\n", - link_name, instr_name, params_str, return_str - )); - } - - output.push_str("}\n"); - output -} - -/// Generate Rust code for a compound expression -/// `params` maps parameter names to their types in the function signature -/// Get the type of an expression -fn get_expr_type( - expr: &CompoundExpr, - params: &HashMap, - helper_sigs: &HashMap, -) -> Option { - match expr { - CompoundExpr::BuiltinCall(name, _) => { - helper_sigs.get(name).map(|sig| sig.return_type.clone()) - } - CompoundExpr::Param(name) => params.get(name).cloned(), - CompoundExpr::IntLiteral(_) => Some(RustType::I32), - } -} - -fn generate_compound_expr_code( - expr: &CompoundExpr, - params: &HashMap, - helper_sigs: &HashMap, -) -> String { - match expr { - CompoundExpr::BuiltinCall(name, args) => { - // Get the expected parameter types for this builtin - let expected_types = helper_sigs - .get(name) - .map(|sig| sig.param_types.clone()) - .unwrap_or_default(); - - let args_code: Vec = args - .iter() - .enumerate() - .map(|(i, arg)| { - let arg_code = generate_compound_expr_code(arg, params, helper_sigs); - - // Check if we need to transmute this argument - let expected_type = expected_types.get(i); - let actual_type = get_expr_type(arg, params, helper_sigs); - - // If the builtin expects HvxVector but the arg is HvxVectorPred, transmute - if expected_type == Some(&RustType::HvxVector) - && actual_type == Some(RustType::HvxVectorPred) - { - format!( - "core::mem::transmute::({})", - arg_code - ) - } else { - arg_code - } - }) - .collect(); - format!("{}({})", name, args_code.join(", ")) - } - CompoundExpr::Param(name) => name.clone(), - CompoundExpr::IntLiteral(n) => n.to_string(), - } -} - -/// Get the primary instruction name from a compound expression (innermost significant op) -fn get_compound_primary_instr(expr: &CompoundExpr) -> Option { - match expr { - CompoundExpr::BuiltinCall(name, args) => { - // For vandqrt wrapper, look inside - if name == "vandqrt" && !args.is_empty() { - if let Some(inner) = get_compound_primary_instr(&args[0]) { - return Some(inner); - } - } - // For store operations, use the store name - if name.starts_with("vS32b") { - return Some(name.clone()); - } - // For conditional accumulation, use the add name - if name.starts_with("vadd") && (name.ends_with("q") || name.ends_with("nq")) { - return Some(name.clone()); - } - // For predicate operations - if name.starts_with("pred_") { - return Some(name.clone()); - } - // For comparison operations with accumulation - if (name.starts_with("veq") || name.starts_with("vgt")) - && (name.ends_with("_and") || name.ends_with("_or") || name.ends_with("_xor")) - { - return Some(name.clone()); - } - Some(name.clone()) - } - _ => None, - } -} - -/// Get override implementations for specific compound intrinsics. -/// Some C macros rely on implicit type conversions that don't work with -/// our stricter Rust types, so we provide corrected implementations. -fn get_compound_overrides() -> HashMap<&'static str, &'static str> { - let mut map = HashMap::new(); - - // Q6_V_vand_QR: takes pred, returns vec - // Use transmute to convert pred to vec for LLVM, call vandvrt - map.insert( - "Q6_V_vand_QR", - "vandvrt(core::mem::transmute::(qu), rt)", - ); - - // Q6_V_vandor_VQR: takes vec and pred, returns vec - map.insert( - "Q6_V_vandor_VQR", - "vandvrt_acc(vx, core::mem::transmute::(qu), rt)", - ); - - // Q6_Q_vand_VR: takes vec, returns pred - map.insert( - "Q6_Q_vand_VR", - "core::mem::transmute::(vandqrt(vu, rt))", - ); - - // Q6_Q_vandor_QVR: takes pred and vec, returns pred - map.insert( - "Q6_Q_vandor_QVR", - "core::mem::transmute::(vandqrt_acc(core::mem::transmute::(qx), vu, rt))", - ); - - map -} - -/// Generate wrapper functions for all intrinsics -fn generate_functions(intrinsics: &[IntrinsicInfo]) -> String { - let mut output = String::new(); - let simd_mappings = get_simd_intrinsic_mappings(); - - // Generate simple intrinsics - for info in intrinsics.iter().filter(|i| !i.is_compound) { - let rust_name = &info.q6_name; - - // Generate doc comment - output.push_str(&format!("/// `{}`\n", info.asm_syntax)); - output.push_str("///\n"); - output.push_str(&format!("/// Instruction Type: {}\n", info.instr_type)); - output.push_str(&format!("/// Execution Slots: {}\n", info.exec_slots)); - - // Generate attributes - output.push_str("#[inline]\n"); - output.push_str(&format!( - "#[cfg_attr(target_arch = \"hexagon\", target_feature(enable = \"hvxv{}\"))]\n", - info.min_arch - )); - - // Check if we should use simd intrinsic instead - let use_simd = simd_mappings.get(info.instr_name.as_str()); - - // assert_instr uses the original instruction name - output.push_str(&format!( - "#[cfg_attr(test, assert_instr({}))]\n", - info.instr_name - )); - - output.push_str(&format!( - "#[unstable(feature = \"stdarch_hexagon\", issue = \"{}\")]\n", - TRACKING_ISSUE - )); - - // Generate function signature - let params_str = info - .params - .iter() - .map(|(name, ty)| format!("{}: {}", name, ty.to_rust_str())) - .collect::>() - .join(", "); - - let return_str = if info.return_type == RustType::Unit { - String::new() - } else { - format!(" -> {}", info.return_type.to_rust_str()) - }; - - output.push_str(&format!( - "pub unsafe fn {}({}){} {{\n", - rust_name, params_str, return_str - )); - - // Generate function body - let args_str = info - .params - .iter() - .map(|(name, _)| name.as_str()) - .collect::>() - .join(", "); - - if let Some(simd_fn) = use_simd { - // Use architecture-independent simd intrinsic - output.push_str(&format!(" {}({})\n", simd_fn, args_str)); - } else { - // Use the LLVM intrinsic - output.push_str(&format!(" {}({})\n", info.instr_name, args_str)); - } - - output.push_str("}\n\n"); - } - - // Generate compound intrinsics - let helper_sigs = get_compound_helper_signatures(); - let overrides = get_compound_overrides(); - for info in intrinsics.iter().filter(|i| i.is_compound) { - if let Some(ref compound_expr) = info.compound_expr { - let rust_name = &info.q6_name; - - // Get the primary instruction for assert_instr - let _primary_instr = get_compound_primary_instr(compound_expr) - .unwrap_or_else(|| info.instr_name.clone()); - - // Generate doc comment - output.push_str(&format!("/// `{}`\n", info.asm_syntax)); - output.push_str("///\n"); - output.push_str( - "/// This is a compound operation composed of multiple HVX instructions.\n", - ); - if !info.instr_type.is_empty() { - output.push_str(&format!("/// Instruction Type: {}\n", info.instr_type)); - } - if !info.exec_slots.is_empty() { - output.push_str(&format!("/// Execution Slots: {}\n", info.exec_slots)); - } - - // Generate attributes - output.push_str("#[inline]\n"); - output.push_str(&format!( - "#[cfg_attr(target_arch = \"hexagon\", target_feature(enable = \"hvxv{}\"))]\n", - info.min_arch - )); - - // For compound ops, we skip assert_instr since they emit multiple instructions - // output.push_str(&format!( - // "#[cfg_attr(test, assert_instr({}))]\n", - // primary_instr - // )); - - output.push_str(&format!( - "#[unstable(feature = \"stdarch_hexagon\", issue = \"{}\")]\n", - TRACKING_ISSUE - )); - - // Generate function signature - let params_str = info - .params - .iter() - .map(|(name, ty)| format!("{}: {}", name, ty.to_rust_str())) - .collect::>() - .join(", "); - - let return_str = if info.return_type == RustType::Unit { - String::new() - } else { - format!(" -> {}", info.return_type.to_rust_str()) - }; - - output.push_str(&format!( - "pub unsafe fn {}({}){} {{\n", - rust_name, params_str, return_str - )); - - // Check if we have an override for this intrinsic - let body = if let Some(override_body) = overrides.get(info.q6_name.as_str()) { - override_body.to_string() - } else { - // Build param type map for expression code generation - let param_types: HashMap = info.params.iter().cloned().collect(); - // Generate function body from compound expression - let expr_body = - generate_compound_expr_code(compound_expr, ¶m_types, &helper_sigs); - - // Check if we need to transmute the result - let expr_return_type = get_expr_type(compound_expr, ¶m_types, &helper_sigs); - if info.return_type == RustType::HvxVectorPred - && expr_return_type == Some(RustType::HvxVector) - { - format!( - "core::mem::transmute::({})", - expr_body - ) - } else { - expr_body - } - }; - output.push_str(&format!(" {}\n", body)); - - output.push_str("}\n\n"); - } - } - - output -} - -/// Generate a module file for a specific vector mode -fn generate_module_file( - intrinsics: &[IntrinsicInfo], - output_path: &Path, - mode: VectorMode, -) -> Result<(), String> { - let mut output = - File::create(output_path).map_err(|e| format!("Failed to create output: {}", e))?; - - writeln!(output, "{}", GENERATED_MARKER).map_err(|e| e.to_string())?; - writeln!(output, "{}", generate_module_doc(mode)).map_err(|e| e.to_string())?; - writeln!(output, "{}", generate_types(mode)).map_err(|e| e.to_string())?; - writeln!(output, "{}", generate_extern_block(intrinsics, mode)).map_err(|e| e.to_string())?; - writeln!(output, "{}", generate_functions(intrinsics)).map_err(|e| e.to_string())?; - - // Ensure file is flushed before running rustfmt - drop(output); - - // Run rustfmt on the generated file - let status = std::process::Command::new("rustfmt") - .arg(output_path) - .status() - .map_err(|e| format!("Failed to run rustfmt: {}", e))?; - - if !status.success() { - return Err("rustfmt failed".to_string()); - } - - Ok(()) -} +use std::path::PathBuf; +use stdarch_gen_common::{run_generator, Mode}; fn main() -> Result<(), String> { - println!("=== Hexagon HVX Code Generator ===\n"); - - // Get the crate directory first (needed for both reading header and writing output) let crate_dir = std::env::var("CARGO_MANIFEST_DIR") - .map(std::path::PathBuf::from) + .map(PathBuf::from) .unwrap_or_else(|_| std::env::current_dir().unwrap()); - // Read and parse the local LLVM header - println!("Step 1: Reading LLVM HVX header..."); - let header_content = read_header(&crate_dir)?; - println!(" Read {} bytes", header_content.len()); - - println!("\nStep 2: Parsing intrinsic definitions..."); - let all_intrinsics = parse_header(&header_content); - println!(" Found {} intrinsic definitions", all_intrinsics.len()); - - // Filter out intrinsics requiring architecture versions not yet supported by rustc - let intrinsics: Vec<_> = all_intrinsics - .into_iter() - .filter(|i| i.min_arch <= MAX_SUPPORTED_ARCH) - .collect(); - let filtered_count = intrinsics.len(); - println!( - " Filtered to {} intrinsics (max supported: hvxv{})", - filtered_count, MAX_SUPPORTED_ARCH - ); - - // Count simple vs compound - let simple_count = intrinsics.iter().filter(|i| !i.is_compound).count(); - let compound_count = intrinsics.iter().filter(|i| i.is_compound).count(); - println!(" Simple intrinsics: {}", simple_count); - println!(" Compound intrinsics: {}", compound_count); - - // Print some sample intrinsics for verification - println!("\n Sample simple intrinsics:"); - for info in intrinsics.iter().filter(|i| !i.is_compound).take(5) { - println!( - " {} -> {} ({})", - info.q6_name, info.builtin_name, info.asm_syntax - ); - } - - println!("\n Sample compound intrinsics:"); - for info in intrinsics.iter().filter(|i| i.is_compound).take(5) { - println!(" {} ({})", info.q6_name, info.asm_syntax); - } - - // Count architecture versions - let mut arch_counts: HashMap = HashMap::new(); - for info in &intrinsics { - *arch_counts.entry(info.min_arch).or_insert(0) += 1; - } - println!("\n By architecture version:"); - let mut archs: Vec<_> = arch_counts.iter().collect(); - archs.sort_by_key(|(k, _)| *k); - for (arch, count) in archs { - println!(" HVX v{}: {} intrinsics", arch, count); - } - - // Generate output files let hexagon_dir = crate_dir.join("../core_arch/src/hexagon"); - // Either "check" to check the output versus the committed output, or "bless" // to update the output. let mode = Mode::from_env(); - println!("\nStep 3: Generating v64.rs and v128.rs (mode: {mode:?})..."); + run_generator(&hexagon_dir, mode, |out_dir| -> Result<(), String> { - for (filename, vmode) in [("v64.rs", VectorMode::V64), ("v128.rs", VectorMode::V128)] { - let path = out_dir.join(filename); - generate_module_file(&intrinsics, &path, vmode)?; - println!(" Output: {}", hexagon_dir.join(filename).display()); - } + // Here scalar::generate writes scalar.rs . + scalar::generate(&crate_dir, out_dir)?; + // Here hvx::generate writes v64.rs and v128.rs . + hvx::generate(&crate_dir, out_dir)?; Ok(()) }) .map_err(|e| e.to_string())?; - println!("\n=== Results ==="); - println!( - " Generated {} simple wrapper functions per module", - simple_count - ); - println!( - " Generated {} compound wrapper functions per module", - compound_count - ); - println!( - " Total: {} functions per module", - simple_count + compound_count - ); - println!(" Output files: v64.rs, v128.rs"); - Ok(()) } diff --git a/library/stdarch/crates/stdarch-gen-hexagon-scalar/src/main.rs b/library/stdarch/crates/stdarch-gen-hexagon/src/scalar.rs similarity index 96% rename from library/stdarch/crates/stdarch-gen-hexagon-scalar/src/main.rs rename to library/stdarch/crates/stdarch-gen-hexagon/src/scalar.rs index 934c7e28fe374..4beee35df97ae 100644 --- a/library/stdarch/crates/stdarch-gen-hexagon-scalar/src/main.rs +++ b/library/stdarch/crates/stdarch-gen-hexagon/src/scalar.rs @@ -21,6 +21,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::Write; use std::path::Path; +use stdarch_gen_common::GENERATED_MARKER; /// Extract the instruction mnemonic from the assembly syntax string. /// @@ -630,6 +631,7 @@ fn generate_scalar_file(intrinsics: &[ScalarIntrinsic], output_path: &Path) -> R let mut output = File::create(output_path).map_err(|e| format!("Failed to create output: {}", e))?; + writeln!(output, "{}", GENERATED_MARKER).map_err(|e| e.to_string())?; writeln!(output, "{}", generate_module_doc()).map_err(|e| e.to_string())?; writeln!(output, "").map_err(|e| e.to_string())?; writeln!(output, "{}", generate_extern_block(intrinsics)).map_err(|e| e.to_string())?; @@ -651,28 +653,12 @@ fn generate_scalar_file(intrinsics: &[ScalarIntrinsic], output_path: &Path) -> R Ok(()) } -fn main() -> Result<(), String> { - println!("=== Hexagon Scalar Code Generator ===\n"); - - let crate_dir = std::env::var("CARGO_MANIFEST_DIR") - .map(std::path::PathBuf::from) - .unwrap_or_else(|_| std::env::current_dir().unwrap()); - - let header_content = read_header(&crate_dir)?; - println!("Read {} bytes", header_content.len()); - +/// Parse the scalar header in `crate_dir` and write `scalar.rs` into `out_dir`. +pub fn generate(crate_dir: &std::path::Path, out_dir: &std::path::Path) -> Result<(), String> { + let header_content = read_header(crate_dir)?; let intrinsics = parse_header(&header_content); - println!("Parsed {} scalar intrinsics", intrinsics.len()); - - let hexagon_dir = std::env::args() - .nth(1) - .map(std::path::PathBuf::from) - .unwrap_or_else(|| crate_dir.join("../core_arch/src/hexagon")); - std::fs::create_dir_all(&hexagon_dir).map_err(|e| e.to_string())?; - let scalar_path = hexagon_dir.join("scalar.rs"); - + std::fs::create_dir_all(out_dir).map_err(|e| e.to_string())?; + let scalar_path = out_dir.join("scalar.rs"); generate_scalar_file(&intrinsics, &scalar_path)?; - println!("Generated scalar.rs at {}", scalar_path.display()); - Ok(()) } diff --git a/library/stdarch/crates/stdarch-gen-loongarch/lasx.spec b/library/stdarch/crates/stdarch-gen-loongarch/lasx.spec index 41432adf2508c..d3efb6c9606a2 100644 --- a/library/stdarch/crates/stdarch-gen-loongarch/lasx.spec +++ b/library/stdarch/crates/stdarch-gen-loongarch/lasx.spec @@ -1872,11 +1872,13 @@ asm-fmts = xd, xj data-types = V4DF, V4DF /// lasx_xvfrecip_s +impl = portable name = lasx_xvfrecip_s asm-fmts = xd, xj data-types = V8SF, V8SF /// lasx_xvfrecip_d +impl = portable name = lasx_xvfrecip_d asm-fmts = xd, xj data-types = V4DF, V4DF @@ -1912,11 +1914,13 @@ asm-fmts = xd, xj data-types = V4DF, V4DF /// lasx_xvfrsqrt_s +impl = portable name = lasx_xvfrsqrt_s asm-fmts = xd, xj data-types = V8SF, V8SF /// lasx_xvfrsqrt_d +impl = portable name = lasx_xvfrsqrt_d asm-fmts = xd, xj data-types = V4DF, V4DF @@ -2067,41 +2071,49 @@ asm-fmts = xd, xj data-types = V4DI, V4DI /// lasx_xvmuh_b +impl = portable name = lasx_xvmuh_b asm-fmts = xd, xj, xk data-types = V32QI, V32QI, V32QI /// lasx_xvmuh_h +impl = portable name = lasx_xvmuh_h asm-fmts = xd, xj, xk data-types = V16HI, V16HI, V16HI /// lasx_xvmuh_w +impl = portable name = lasx_xvmuh_w asm-fmts = xd, xj, xk data-types = V8SI, V8SI, V8SI /// lasx_xvmuh_d +impl = portable name = lasx_xvmuh_d asm-fmts = xd, xj, xk data-types = V4DI, V4DI, V4DI /// lasx_xvmuh_bu +impl = portable name = lasx_xvmuh_bu asm-fmts = xd, xj, xk data-types = UV32QI, UV32QI, UV32QI /// lasx_xvmuh_hu +impl = portable name = lasx_xvmuh_hu asm-fmts = xd, xj, xk data-types = UV16HI, UV16HI, UV16HI /// lasx_xvmuh_wu +impl = portable name = lasx_xvmuh_wu asm-fmts = xd, xj, xk data-types = UV8SI, UV8SI, UV8SI /// lasx_xvmuh_du +impl = portable name = lasx_xvmuh_du asm-fmts = xd, xj, xk data-types = UV4DI, UV4DI, UV4DI @@ -2560,41 +2572,49 @@ asm-fmts = xd, xj data-types = V4DF, V4DF /// lasx_xvfrintrz_s +impl = portable name = lasx_xvfrintrz_s asm-fmts = xd, xj data-types = V8SF, V8SF /// lasx_xvfrintrz_d +impl = portable name = lasx_xvfrintrz_d asm-fmts = xd, xj data-types = V4DF, V4DF /// lasx_xvfrintrp_s +impl = portable name = lasx_xvfrintrp_s asm-fmts = xd, xj data-types = V8SF, V8SF /// lasx_xvfrintrp_d +impl = portable name = lasx_xvfrintrp_d asm-fmts = xd, xj data-types = V4DF, V4DF /// lasx_xvfrintrm_s +impl = portable name = lasx_xvfrintrm_s asm-fmts = xd, xj data-types = V8SF, V8SF /// lasx_xvfrintrm_d +impl = portable name = lasx_xvfrintrm_d asm-fmts = xd, xj data-types = V4DF, V4DF /// lasx_xvld +impl = portable name = lasx_xvld asm-fmts = xd, rj, si12 data-types = V32QI, CVPOINTER, SI /// lasx_xvst +impl = portable name = lasx_xvst asm-fmts = xd, rj, si12 data-types = VOID, V32QI, CVPOINTER, SI @@ -2681,11 +2701,13 @@ asm-fmts = xd, i13 data-types = V4DI, HI /// lasx_xvldx +impl = portable name = lasx_xvldx asm-fmts = xd, rj, rk data-types = V32QI, CVPOINTER, DI /// lasx_xvstx +impl = portable name = lasx_xvstx asm-fmts = xd, rj, rk data-types = VOID, V32QI, CVPOINTER, DI @@ -3297,21 +3319,25 @@ asm-fmts = xd, xj, xk data-types = V16HI, V16HI, UV32QI, V32QI /// lasx_xvrotr_b +impl = portable name = lasx_xvrotr_b asm-fmts = xd, xj, xk data-types = V32QI, V32QI, V32QI /// lasx_xvrotr_h +impl = portable name = lasx_xvrotr_h asm-fmts = xd, xj, xk data-types = V16HI, V16HI, V16HI /// lasx_xvrotr_w +impl = portable name = lasx_xvrotr_w asm-fmts = xd, xj, xk data-types = V8SI, V8SI, V8SI /// lasx_xvrotr_d +impl = portable name = lasx_xvrotr_d asm-fmts = xd, xj, xk data-types = V4DI, V4DI, V4DI @@ -3397,21 +3423,25 @@ asm-fmts = xd, xj data-types = UV4DI, UV4DI /// lasx_xvrotri_b +impl = portable name = lasx_xvrotri_b asm-fmts = xd, xj, ui3 data-types = V32QI, V32QI, UQI /// lasx_xvrotri_h +impl = portable name = lasx_xvrotri_h asm-fmts = xd, xj, ui4 data-types = V16HI, V16HI, UQI /// lasx_xvrotri_w +impl = portable name = lasx_xvrotri_w asm-fmts = xd, xj, ui5 data-types = V8SI, V8SI, UQI /// lasx_xvrotri_d +impl = portable name = lasx_xvrotri_d asm-fmts = xd, xj, ui6 data-types = V4DI, V4DI, UQI diff --git a/library/stdarch/crates/stdarch-gen-loongarch/lsx.spec b/library/stdarch/crates/stdarch-gen-loongarch/lsx.spec index 211c3c0fcfe62..79dc4217da293 100644 --- a/library/stdarch/crates/stdarch-gen-loongarch/lsx.spec +++ b/library/stdarch/crates/stdarch-gen-loongarch/lsx.spec @@ -1959,11 +1959,13 @@ asm-fmts = vd, vj data-types = V2DF, V2DF /// lsx_vfrecip_s +impl = portable name = lsx_vfrecip_s asm-fmts = vd, vj data-types = V4SF, V4SF /// lsx_vfrecip_d +impl = portable name = lsx_vfrecip_d asm-fmts = vd, vj data-types = V2DF, V2DF @@ -1999,11 +2001,13 @@ asm-fmts = vd, vj data-types = V2DF, V2DF /// lsx_vfrsqrt_s +impl = portable name = lsx_vfrsqrt_s asm-fmts = vd, vj data-types = V4SF, V4SF /// lsx_vfrsqrt_d +impl = portable name = lsx_vfrsqrt_d asm-fmts = vd, vj data-types = V2DF, V2DF @@ -2129,41 +2133,49 @@ asm-fmts = vd, vj data-types = V2DI, V2DI /// lsx_vmuh_b +impl = portable name = lsx_vmuh_b asm-fmts = vd, vj, vk data-types = V16QI, V16QI, V16QI /// lsx_vmuh_h +impl = portable name = lsx_vmuh_h asm-fmts = vd, vj, vk data-types = V8HI, V8HI, V8HI /// lsx_vmuh_w +impl = portable name = lsx_vmuh_w asm-fmts = vd, vj, vk data-types = V4SI, V4SI, V4SI /// lsx_vmuh_d +impl = portable name = lsx_vmuh_d asm-fmts = vd, vj, vk data-types = V2DI, V2DI, V2DI /// lsx_vmuh_bu +impl = portable name = lsx_vmuh_bu asm-fmts = vd, vj, vk data-types = UV16QI, UV16QI, UV16QI /// lsx_vmuh_hu +impl = portable name = lsx_vmuh_hu asm-fmts = vd, vj, vk data-types = UV8HI, UV8HI, UV8HI /// lsx_vmuh_wu +impl = portable name = lsx_vmuh_wu asm-fmts = vd, vj, vk data-types = UV4SI, UV4SI, UV4SI /// lsx_vmuh_du +impl = portable name = lsx_vmuh_du asm-fmts = vd, vj, vk data-types = UV2DI, UV2DI, UV2DI @@ -2623,31 +2635,37 @@ asm-fmts = vd, vj data-types = V2DF, V2DF /// lsx_vfrintrz_s +impl = portable name = lsx_vfrintrz_s asm-fmts = vd, vj data-types = V4SF, V4SF /// lsx_vfrintrz_d +impl = portable name = lsx_vfrintrz_d asm-fmts = vd, vj data-types = V2DF, V2DF /// lsx_vfrintrp_s +impl = portable name = lsx_vfrintrp_s asm-fmts = vd, vj data-types = V4SF, V4SF /// lsx_vfrintrp_d +impl = portable name = lsx_vfrintrp_d asm-fmts = vd, vj data-types = V2DF, V2DF /// lsx_vfrintrm_s +impl = portable name = lsx_vfrintrm_s asm-fmts = vd, vj data-types = V4SF, V4SF /// lsx_vfrintrm_d +impl = portable name = lsx_vfrintrm_d asm-fmts = vd, vj data-types = V2DF, V2DF @@ -3133,21 +3151,25 @@ asm-fmts = vd, vj, vk data-types = V2DI, V2DI, UV2DI, V2DI /// lsx_vrotr_b +impl = portable name = lsx_vrotr_b asm-fmts = vd, vj, vk data-types = V16QI, V16QI, V16QI /// lsx_vrotr_h +impl = portable name = lsx_vrotr_h asm-fmts = vd, vj, vk data-types = V8HI, V8HI, V8HI /// lsx_vrotr_w +impl = portable name = lsx_vrotr_w asm-fmts = vd, vj, vk data-types = V4SI, V4SI, V4SI /// lsx_vrotr_d +impl = portable name = lsx_vrotr_d asm-fmts = vd, vj, vk data-types = V2DI, V2DI, V2DI @@ -3233,21 +3255,25 @@ asm-fmts = vd, vj data-types = UV2DI, UV2DI /// lsx_vrotri_b +impl = portable name = lsx_vrotri_b asm-fmts = vd, vj, ui3 data-types = V16QI, V16QI, UQI /// lsx_vrotri_h +impl = portable name = lsx_vrotri_h asm-fmts = vd, vj, ui4 data-types = V8HI, V8HI, UQI /// lsx_vrotri_w +impl = portable name = lsx_vrotri_w asm-fmts = vd, vj, ui5 data-types = V4SI, V4SI, UQI /// lsx_vrotri_d +impl = portable name = lsx_vrotri_d asm-fmts = vd, vj, ui6 data-types = V2DI, V2DI, UQI @@ -3503,11 +3529,13 @@ asm-fmts = vd, vj, ui8 data-types = V4SI, V4SI, V4SI, USI /// lsx_vld +impl = portable name = lsx_vld asm-fmts = vd, rj, si12 data-types = V16QI, CVPOINTER, SI /// lsx_vst +impl = portable name = lsx_vst asm-fmts = vd, rj, si12 data-types = VOID, V16QI, CVPOINTER, SI @@ -3559,11 +3587,13 @@ asm-fmts = vd, vj, vk, va data-types = V16QI, V16QI, V16QI, V16QI /// lsx_vldx +impl = portable name = lsx_vldx asm-fmts = vd, rj, rk data-types = V16QI, CVPOINTER, DI /// lsx_vstx +impl = portable name = lsx_vstx asm-fmts = vd, rj, rk data-types = VOID, V16QI, CVPOINTER, DI diff --git a/library/stdarch/crates/stdarch-gen-loongarch/src/portable-intrinsics.txt b/library/stdarch/crates/stdarch-gen-loongarch/src/portable-intrinsics.txt index abbfcb3365d2b..0bd33c248bd3b 100644 --- a/library/stdarch/crates/stdarch-gen-loongarch/src/portable-intrinsics.txt +++ b/library/stdarch/crates/stdarch-gen-loongarch/src/portable-intrinsics.txt @@ -263,6 +263,36 @@ lsx_vshuf4i_b lsx_vshuf4i_h lsx_vshuf4i_w lsx_vshuf4i_d +lsx_vld +lsx_vst +lsx_vldx +lsx_vstx +lsx_vrotr_b +lsx_vrotr_h +lsx_vrotr_w +lsx_vrotr_d +lsx_vrotri_b +lsx_vrotri_h +lsx_vrotri_w +lsx_vrotri_d +lsx_vfrecip_s +lsx_vfrecip_d +lsx_vfrsqrt_s +lsx_vfrsqrt_d +lsx_vfrintrp_s +lsx_vfrintrp_d +lsx_vfrintrm_s +lsx_vfrintrm_d +lsx_vfrintrz_s +lsx_vfrintrz_d +lsx_vmuh_b +lsx_vmuh_h +lsx_vmuh_w +lsx_vmuh_d +lsx_vmuh_bu +lsx_vmuh_hu +lsx_vmuh_wu +lsx_vmuh_du # LASX intrinsics lasx_xvsll_b @@ -527,3 +557,33 @@ lasx_xvpackod_d lasx_xvshuf4i_b lasx_xvshuf4i_h lasx_xvshuf4i_w +lasx_xvld +lasx_xvst +lasx_xvldx +lasx_xvstx +lasx_xvrotr_b +lasx_xvrotr_h +lasx_xvrotr_w +lasx_xvrotr_d +lasx_xvrotri_b +lasx_xvrotri_h +lasx_xvrotri_w +lasx_xvrotri_d +lasx_xvfrecip_s +lasx_xvfrecip_d +lasx_xvfrsqrt_s +lasx_xvfrsqrt_d +lasx_xvfrintrp_s +lasx_xvfrintrp_d +lasx_xvfrintrm_s +lasx_xvfrintrm_d +lasx_xvfrintrz_s +lasx_xvfrintrz_d +lasx_xvmuh_b +lasx_xvmuh_h +lasx_xvmuh_w +lasx_xvmuh_d +lasx_xvmuh_bu +lasx_xvmuh_hu +lasx_xvmuh_wu +lasx_xvmuh_du diff --git a/library/stdarch/crates/stdarch-test/Cargo.toml b/library/stdarch/crates/stdarch-test/Cargo.toml index e88258bfd30d0..eddd3b7f78936 100644 --- a/library/stdarch/crates/stdarch-test/Cargo.toml +++ b/library/stdarch/crates/stdarch-test/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" assert-instr-macro = { path = "../assert-instr-macro" } simd-test-macro = { path = "../simd-test-macro" } rustc-demangle = "0.1.8" -cfg-if = "1.0" [target.'cfg(windows)'.dependencies] cc = "1.0" diff --git a/library/stdarch/crates/stdarch-test/src/lib.rs b/library/stdarch/crates/stdarch-test/src/lib.rs index c468ebd12bb0d..9ef25a7957c1d 100644 --- a/library/stdarch/crates/stdarch-test/src/lib.rs +++ b/library/stdarch/crates/stdarch-test/src/lib.rs @@ -6,18 +6,16 @@ #![deny(rust_2018_idioms)] #![allow(clippy::missing_docs_in_private_items, clippy::print_stdout)] -#[macro_use] -extern crate cfg_if; - pub use assert_instr_macro::*; pub use simd_test_macro::*; use std::{cmp, collections::HashSet, env, hash, hint::black_box, str, sync::LazyLock}; -cfg_if! { - if #[cfg(target_arch = "wasm32")] { +cfg_select! { + target_arch = "wasm32" => { pub mod wasm; use wasm::disassemble_myself; - } else { + } + _ => { mod disassembly; use crate::disassembly::disassemble_myself; } diff --git a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs index 32726d1bf450b..be948df541b79 100644 --- a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs +++ b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs @@ -305,7 +305,7 @@ fn verify_all_signatures() { } // FIXME: these have not been added to Intrinsics Guide yet - if ["amx-avx512", "amx-fp8", "amx-movrs", "amx-tf32", "movrs"] + if ["amx-avx512", "amx-fp8", "amx-movrs", "movrs"] .iter() .any(|f| feature.contains(f)) { diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index cb4a3593c51d6..02201f43c08ce 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -56,7 +56,14 @@ cfg_select! { } } -#[cfg(target_env = "musl")] +// `target_abi = "pauthtest"` is currently only used by the Linux/musl +// `aarch64-unknown-linux-pauthtest` target. That target only supports unwinding +// via libunwind. +#[cfg(target_abi = "pauthtest")] +#[link(name = "unwind")] +unsafe extern "C" {} + +#[cfg(all(target_env = "musl", not(target_abi = "pauthtest")))] cfg_select! { all(feature = "llvm-libunwind", feature = "system-llvm-libunwind") => { compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time"); diff --git a/package.json b/package.json index a4f6e18bcf422..6bd8a5be6a105 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "browser-ui-test": "^0.24.0", + "browser-ui-test": "^0.24.1", "es-check": "^9.4.4", "eslint": "^8.57.1", "typescript": "^5.8.3" diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 7bdcb483eb923..0ac18df2084e3 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -140,6 +140,18 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs) { target: builder.config.host_target, }); + let rustc_perf_dir = builder.build.tempdir().join("rustc-perf"); + let results_dir = rustc_perf_dir.join("results"); + builder.create_dir(&results_dir); + + let mut cmd = command(collector.tool_path); + + // We need to set the working directory to `src/tools/rustc-perf`, so that it can find the directory + // with compile-time benchmarks. + cmd.current_dir(builder.src.join("src/tools/rustc-perf")); + + let db_path = results_dir.join("results.db"); + let is_profiling = match &args.cmd { PerfCommand::Eprintln { .. } | PerfCommand::Samply { .. } @@ -151,32 +163,23 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs) { Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); } - let compiler = builder.compiler(builder.top_stage, builder.config.host_target); - builder.std(compiler, builder.config.host_target); - - if let Some(opts) = args.cmd.shared_opts() - && opts.profiles.contains(&Profile::Doc) - { - builder.ensure(Rustdoc { target_compiler: compiler }); - } + let prepare_rustc = || { + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + builder.std(compiler, builder.config.host_target); - let sysroot = builder.ensure(Sysroot::new(compiler)); - let mut rustc = sysroot.clone(); - rustc.push("bin"); - rustc.push("rustc"); - rustc.set_extension(EXE_EXTENSION); - - let rustc_perf_dir = builder.build.tempdir().join("rustc-perf"); - let results_dir = rustc_perf_dir.join("results"); - builder.create_dir(&results_dir); - - let mut cmd = command(collector.tool_path); - - // We need to set the working directory to `src/tools/rustc-perf`, so that it can find the directory - // with compile-time benchmarks. - cmd.current_dir(builder.src.join("src/tools/rustc-perf")); + if let Some(opts) = args.cmd.shared_opts() + && opts.profiles.contains(&Profile::Doc) + { + builder.ensure(Rustdoc { target_compiler: compiler }); + } - let db_path = results_dir.join("results.db"); + let sysroot = builder.ensure(Sysroot::new(compiler)); + let mut rustc = sysroot.clone(); + rustc.push("bin"); + rustc.push("rustc"); + rustc.set_extension(EXE_EXTENSION); + rustc + }; match &args.cmd { PerfCommand::Eprintln { opts } @@ -191,7 +194,7 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); }); cmd.arg("--out-dir").arg(&results_dir); - cmd.arg(rustc); + cmd.arg(prepare_rustc()); apply_shared_opts(&mut cmd, opts); cmd.run(builder); @@ -202,7 +205,7 @@ Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); cmd.arg("bench_local"); cmd.arg("--db").arg(&db_path); cmd.arg("--id").arg(id); - cmd.arg(rustc); + cmd.arg(prepare_rustc()); apply_shared_opts(&mut cmd, opts); cmd.run(builder); diff --git a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile b/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile index 8f7c7ebe35559..d8bfd6f52cb8b 100644 --- a/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile +++ b/src/ci/docker/host-x86_64/optional-x86_64-gnu-parallel-frontend/Dockerfile @@ -24,13 +24,20 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +ENV PARALLEL_FRONTEND_THREADS=4 +ENV ITERATION_COUNT=2 + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --enable-sanitizers \ --enable-profiler \ --enable-compiler-docs \ - --set llvm.libzstd=true + --set llvm.libzstd=true \ + --set rust.parallel-frontend-threads=${PARALLEL_FRONTEND_THREADS} # Build the toolchain with multiple parallel frontend threads and then run tests # Tests are still compiled serially at the moment (intended to be changed in follow-ups). -ENV SCRIPT python3 ../x.py --stage 2 test --set rust.parallel-frontend-threads=4 +# Running compiletest only tests for parallel frontend, then the rest without compiletest-only +# options (i.e. `--parallel-frontend-threads=4 --iteration-count=2`) +COPY ./scripts/optional-x86_64-gnu-parallel-frontend.sh /scripts/ +ENV SCRIPT="Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh b/src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh new file mode 100755 index 0000000000000..ed9aed263f25e --- /dev/null +++ b/src/ci/docker/scripts/optional-x86_64-gnu-parallel-frontend.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -eux -o pipefail + +if [ ! -v RUST_TEST_THREADS ]; then + RUST_TEST_THREADS_=$(python3 -c "print(max(1, $(nproc) // ${PARALLEL_FRONTEND_THREADS}))") +else + RUST_TEST_THREADS_=${RUST_TEST_THREADS} +fi + +RUST_TEST_THREADS=${RUST_TEST_THREADS_} \ + python3 ../x.py --stage 2 test \ + tests/ui \ + -- \ + --parallel-frontend-threads="${PARALLEL_FRONTEND_THREADS}" \ + --iteration-count="${ITERATION_COUNT}" diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm3.sh b/src/ci/docker/scripts/x86_64-gnu-llvm3.sh index 6ba0c738713b2..c8d67f0e80c4f 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm3.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm3.sh @@ -19,3 +19,7 @@ set -ex # Rebuild the stdlib with the size optimizations enabled and run tests again. RUSTFLAGS_NOT_BOOTSTRAP="--cfg feature=\"optimize_for_size\"" ../x.py --stage 1 test \ library/std library/alloc library/core + +# Rebuild the stdlib forcing the use of intrinsic fallbacks and run core tests again. +RUSTFLAGS_NOT_BOOTSTRAP="-Zforce-intrinsic-fallback" ../x.py --stage 1 test \ + library/core diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 74f1a0abdde8e..a8eebe7599fda 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -380,6 +380,8 @@ auto: - name: optional-x86_64-gnu-parallel-frontend # This test can be flaky, so do not cancel CI if it fails, for now. continue_on_error: true + env: + DOCKER_SCRIPT: optional-x86_64-gnu-parallel-frontend.sh <<: *job-linux-4c # This job ensures commits landing on nightly still pass the full diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 3cd34f24c6e3d..a8c27c5615007 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -29,33 +29,18 @@ use crate::passes::{self, Condition}; use crate::scrape_examples::{AllCallLocations, ScrapeExamplesOptions}; use crate::{html, opts, theme}; -#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub(crate) enum OutputFormat { - Json, - #[default] + /// `--output-format=json` without `--show-coverage`. + /// + /// JSON description of crate API. + IrJson, + /// `--output-format=json` with `--show-coverage`. + CoverageJson, Html, Doctest, } -impl OutputFormat { - pub(crate) fn is_json(&self) -> bool { - matches!(self, OutputFormat::Json) - } -} - -impl TryFrom<&str> for OutputFormat { - type Error = String; - - fn try_from(value: &str) -> Result { - match value { - "json" => Ok(OutputFormat::Json), - "html" => Ok(OutputFormat::Html), - "doctest" => Ok(OutputFormat::Doctest), - _ => Err(format!("unknown output format `{value}`")), - } - } -} - /// Either an input crate, markdown file, or nothing (--merge=finalize). pub(crate) enum InputMode { /// The `--merge=finalize` step does not need an input crate to rustdoc. @@ -329,7 +314,8 @@ pub(crate) enum EmitType { HtmlStaticFiles, HtmlNonStaticFiles, // not explicitly nameable by the user for now - JsonFiles, + IrJsonFiles, + CoverageJsonFiles, DepInfo(Option), } @@ -338,7 +324,8 @@ impl fmt::Display for EmitType { f.write_str(match self { Self::HtmlStaticFiles => "html-static-files", Self::HtmlNonStaticFiles => "html-non-static-files", - Self::JsonFiles => "json-files", + Self::IrJsonFiles => "ir-json-files", + Self::CoverageJsonFiles => "coverage-json-files", Self::DepInfo(_) => "dep-info", }) } @@ -479,40 +466,48 @@ impl Options { let show_coverage = matches.opt_present("show-coverage"); let output_format_s = matches.opt_str("output-format"); - let output_format = match output_format_s { - Some(ref s) => match OutputFormat::try_from(s.as_str()) { - Ok(out_fmt) => out_fmt, - Err(e) => dcx.fatal(e), - }, - None => OutputFormat::default(), + let output_format = match output_format_s.as_deref() { + None | Some("html") => OutputFormat::Html, + Some("json") => { + if show_coverage { + OutputFormat::CoverageJson + } else { + OutputFormat::IrJson + } + } + Some("doctest") => OutputFormat::Doctest, + Some(other) => dcx.fatal(format!("unknown output format `{other}`")), }; - // check for `--output-format=json` + // check for `--output-format` stability, and compatibility with `--show-coverage` match ( output_format_s.as_ref().map(|_| output_format), show_coverage, nightly_options::is_unstable_enabled(matches), ) { - (None | Some(OutputFormat::Json), true, _) => {} + (None | Some(OutputFormat::CoverageJson), true, _) => {} (_, true, _) => { dcx.fatal(format!( "`--output-format={}` is not supported for the `--show-coverage` option", - output_format_s.unwrap_or_default(), + output_format_s.expect("checked for none above"), )); } // If `-Zunstable-options` is used, nothing to check after this point. (_, false, true) => {} (None | Some(OutputFormat::Html), false, _) => {} - (Some(OutputFormat::Json), false, false) => { + (Some(OutputFormat::IrJson), false, false) => { dcx.fatal( - "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)", + "the -Z unstable-options flag must be passed to enable --output-format=json for documentation generation (see https://github.com/rust-lang/rust/issues/76578)", ); } (Some(OutputFormat::Doctest), false, false) => { dcx.fatal( - "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/134529)", + "the -Z unstable-options flag must be passed to enable --output-format=doctest (see https://github.com/rust-lang/rust/issues/134529)", ); } + (Some(OutputFormat::CoverageJson), false, _) => { + unreachable!("CoverageJson is only possible when show_coverage is true") + } } let mut emit = FxIndexMap::default(); @@ -531,18 +526,18 @@ impl Options { match typ { EmitType::DepInfo(_) => match output_format { - OutputFormat::Json | OutputFormat::Html => {} + OutputFormat::Html | OutputFormat::IrJson | OutputFormat::CoverageJson => {} OutputFormat::Doctest => unreachable!(), }, EmitType::HtmlStaticFiles | EmitType::HtmlNonStaticFiles => match output_format { OutputFormat::Html => {} - OutputFormat::Json => dcx.fatal(format!( + OutputFormat::IrJson | OutputFormat::CoverageJson => dcx.fatal(format!( "the `--emit={typ}` flag is not supported with `--output-format=json`", )), OutputFormat::Doctest => unreachable!(), }, - EmitType::JsonFiles => unreachable!(), + EmitType::IrJsonFiles | EmitType::CoverageJsonFiles => unreachable!(), } // De-duplicate emit types and the last wins. @@ -558,7 +553,8 @@ impl Options { // will have already been rejected above. if emit.is_empty() { match output_format { - OutputFormat::Json => emit.push(EmitType::JsonFiles), + OutputFormat::IrJson => emit.push(EmitType::IrJsonFiles), + OutputFormat::CoverageJson => emit.push(EmitType::CoverageJsonFiles), OutputFormat::Html => { emit.push(EmitType::HtmlStaticFiles); emit.push(EmitType::HtmlNonStaticFiles); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index fccfa3f57e930..5bdedf7ae3d54 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -75,8 +75,6 @@ pub(crate) struct DocContext<'tcx> { pub(crate) inlined: FxHashSet, /// Used by `calculate_doc_coverage`. pub(crate) output_format: OutputFormat, - /// Used by `strip_private`. - pub(crate) show_coverage: bool, } impl<'tcx> DocContext<'tcx> { @@ -139,7 +137,7 @@ impl<'tcx> DocContext<'tcx> { /// /// If another option like `--show-coverage` is enabled, it will return `false`. pub(crate) fn is_json_output(&self) -> bool { - self.output_format.is_json() && !self.show_coverage + self.output_format == OutputFormat::IrJson } /// If `--document-private-items` was passed to rustdoc. @@ -385,7 +383,6 @@ pub(crate) fn run_global_ctxt( cache: Cache::new(render_options.document_private, render_options.document_hidden), inlined: FxHashSet::default(), output_format, - show_coverage, }; for cnum in tcx.crates(()) { diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 433e4487eb9d5..2d6865dc689b6 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -134,7 +134,7 @@ impl<'tcx> JsonRenderer<'tcx> { impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> { const DESCR: &'static str = "json"; const RUN_ON_MODULE: bool = false; - const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::JsonFiles; + const NON_STATIC_FILE_EMIT_TYPE: EmitType = EmitType::IrJsonFiles; type ModuleData = (); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index a4f8e3e12e510..17f5af024ac7f 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -984,11 +984,13 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { }, ) }), - config::OutputFormat::Json => sess.time("render_json", || { + config::OutputFormat::IrJson => sess.time("render_json", || { run_renderer(krate, render_opts, cache, tcx, json::JsonRenderer::init) }), - // Already handled above with doctest runners. - config::OutputFormat::Doctest => unreachable!(), + // Already handled above with doctest runners or coverage early return + config::OutputFormat::Doctest | config::OutputFormat::CoverageJson => { + unreachable!() + } } }) }) diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 200a5a71b453a..adf98afc46cc0 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -11,6 +11,7 @@ use serde::Serialize; use tracing::debug; use crate::clean; +use crate::config::OutputFormat; use crate::core::DocContext; use crate::html::markdown::{ErrorCodes, find_testable_code}; use crate::passes::Pass; @@ -131,8 +132,7 @@ impl CoverageCalculator<'_, '_> { fn print_results(&self) { let output_format = self.ctx.output_format; - // In this case we want to ensure that the `OutputFormat` is JSON and NOT the `DocContext`. - if output_format.is_json() { + if output_format == OutputFormat::CoverageJson { println!("{}", self.to_json()); return; } diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 5cd64d6a4a995..e4541eb2d6061 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -525,7 +525,7 @@ fn is_uninit_value_valid_for_layout<'tcx>(cx: &LateContext<'tcx>, layout: TyAndL match layout.layout.backend_repr { BackendRepr::Scalar(s) => s.is_uninit_valid(), - BackendRepr::ScalarPair(a, b) => a.is_uninit_valid() && b.is_uninit_valid(), + BackendRepr::ScalarPair { a, b, b_offset: _ } => a.is_uninit_valid() && b.is_uninit_valid(), BackendRepr::SimdVector { element, count } => count == 0 || element.is_uninit_valid(), BackendRepr::SimdScalableVector { element, .. } => element.is_uninit_valid(), // Here validity is determined by the structural fields instead. diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 5014541faeb01..9cca7c30817f9 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -313,7 +313,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { Immediate::ScalarPair(sc_first, sc_second) => { // The first scalar has an offset of zero; compute the offset of the 2nd. let ofs_second = { - let rustc_abi::BackendRepr::ScalarPair(a, b) = imm.layout.backend_repr + let rustc_abi::BackendRepr::ScalarPair { a: _, b: _, b_offset } = + imm.layout.backend_repr else { span_bug!( this.cur_span(), @@ -321,7 +322,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { imm.layout ) }; - a.size(this).align_to(b.default_align(this).abi).bytes_usize() + b_offset.bytes_usize() }; write_scalar(this, sc_first, 0)?; diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index ef6c6f0f586ae..a07c2029f4b38 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.25" +wasm-component-ld = "0.5.26" diff --git a/tests/codegen-llvm/range-len-try-from.rs b/tests/codegen-llvm/range-len-try-from.rs new file mode 100644 index 0000000000000..e8f204b45e81b --- /dev/null +++ b/tests/codegen-llvm/range-len-try-from.rs @@ -0,0 +1,43 @@ +// `0..slice.len()` should propagate the same upper bound as +// `slice.iter().enumerate()`, allowing the checked index conversion to be +// removed inside the loop. + +//@ compile-flags: -Copt-level=3 +//@ only-64bit + +#![crate_type = "lib"] + +use std::convert::TryFrom; +use std::hint::black_box; + +// CHECK-LABEL: @score_round_enumerate +#[no_mangle] +pub fn score_round_enumerate(candidates: &[bool]) { + // The length check itself can still fail. + // CHECK: call void {{.*}}unwrap_failed + // But the checked conversion inside the loop should not add another panic path. + // CHECK-NOT: call void {{.*}}unwrap_failed + // CHECK: ret void + u32::try_from(candidates.len()).unwrap(); + + for (i, _) in candidates.iter().enumerate() { + u32::try_from(i).unwrap(); + black_box(42); + } +} + +// CHECK-LABEL: @score_round_range +#[no_mangle] +pub fn score_round_range(candidates: &[bool]) { + // The length check itself can still fail. + // CHECK: call void {{.*}}unwrap_failed + // But the checked conversion inside the loop should not add another panic path. + // CHECK-NOT: call void {{.*}}unwrap_failed + // CHECK: ret void + u32::try_from(candidates.len()).unwrap(); + + for i in 0..candidates.len() { + u32::try_from(i).unwrap(); + black_box(42); + } +} diff --git a/tests/run-make/unstable-flag-required/README.md b/tests/run-make/unstable-flag-required/README.md deleted file mode 100644 index e5251fdf9b5d9..0000000000000 --- a/tests/run-make/unstable-flag-required/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This is a collection of tests that verify `--unstable-options` is required. -It should eventually be removed in favor of UI tests once compiletest stops -passing --unstable-options by default (#82639). diff --git a/tests/run-make/unstable-flag-required/output-format-json.stderr b/tests/run-make/unstable-flag-required/output-format-json.stderr deleted file mode 100644 index fb4079beb2799..0000000000000 --- a/tests/run-make/unstable-flag-required/output-format-json.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578) - diff --git a/tests/run-make/unstable-flag-required/rmake.rs b/tests/run-make/unstable-flag-required/rmake.rs deleted file mode 100644 index c521436c203d5..0000000000000 --- a/tests/run-make/unstable-flag-required/rmake.rs +++ /dev/null @@ -1,12 +0,0 @@ -// The flag `--output-format` is unauthorized on beta and stable releases, which led -// to confusion for maintainers doing testing on nightly. Tying it to an unstable flag -// elucidates this, and this test checks that `--output-format` cannot be passed on its -// own. -// See https://github.com/rust-lang/rust/pull/82497 - -use run_make_support::{diff, rustdoc}; - -fn main() { - let out = rustdoc().output_format("json").input("x.html").run_fail().stderr_utf8(); - diff().expected_file("output-format-json.stderr").actual_text("actual-json", out).run(); -} diff --git a/tests/run-make/unstable-flag-required/x.rs b/tests/run-make/unstable-flag-required/x.rs deleted file mode 100644 index 5df7576133a68..0000000000000 --- a/tests/run-make/unstable-flag-required/x.rs +++ /dev/null @@ -1 +0,0 @@ -// nothing to see here diff --git a/tests/run-make/wasm-emscripten-main-symbol/main.rs b/tests/run-make/wasm-emscripten-main-symbol/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/tests/run-make/wasm-emscripten-main-symbol/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/wasm-emscripten-main-symbol/rmake.rs b/tests/run-make/wasm-emscripten-main-symbol/rmake.rs new file mode 100644 index 0000000000000..03bbdd0bcb62b --- /dev/null +++ b/tests/run-make/wasm-emscripten-main-symbol/rmake.rs @@ -0,0 +1,45 @@ +//@ only-wasm32-unknown-emscripten + +// On wasm the age-old C trick of a `main` that is either `int main(void)` or +// `int main(int, char**)` doesn't work, because wasm requires caller and callee +// signatures to match. The platform ABI (as used by Clang) therefore mangles +// the entry point by signature; the argc/argv form is emitted as +// `__main_argc_argv`. Rust's emscripten target uses the argc/argv form, so its +// entry point must be emitted under that name rather than as a raw `main`. +// +// This matters beyond cosmetics: emscripten's own crt references +// `__main_argc_argv` directly on some entry paths (notably `crt1_proxy_main.o`, +// used by `-sPROXY_TO_PTHREAD`), which fail to link against a raw `main`. +// +// The JS-visible name of the entry point stays `_main`; emscripten bridges that +// to the wasm `__main_argc_argv` export internally. + +use run_make_support::{rfs, rustc, wasmparser}; +use wasmparser::ExternalKind; + +fn main() { + rustc().input("main.rs").target("wasm32-unknown-emscripten").output("main.js").run(); + + let file = rfs::read("main.wasm"); + let mut entry = None; + let mut has_plain_main = false; + for payload in wasmparser::Parser::new(0).parse_all(&file) { + if let wasmparser::Payload::ExportSection(s) = payload.unwrap() { + for export in s { + let export = export.unwrap(); + match export.name { + "__main_argc_argv" => entry = Some(export.kind), + "main" => has_plain_main = true, + _ => {} + } + } + } + } + + assert_eq!( + entry, + Some(ExternalKind::Func), + "the emscripten entry point must be exported as the wasm C-ABI symbol `__main_argc_argv`", + ); + assert!(!has_plain_main, "a raw `main` symbol must not be exported on wasm"); +} diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs b/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs new file mode 100644 index 0000000000000..0609b515e5ca8 --- /dev/null +++ b/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --show-coverage --output-format=json --emit=dep-info -Zunstable-options +//@ build-pass diff --git a/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout b/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout new file mode 100644 index 0000000000000..f3ba8205ddedf --- /dev/null +++ b/tests/rustdoc-ui/output-format-coveragejson-emit-depinfo.stdout @@ -0,0 +1 @@ +{"$DIR/output-format-coveragejson-emit-depinfo.rs":{"total":1,"with_docs":0,"total_examples":0,"with_examples":0}} diff --git a/tests/rustdoc-ui/output-format-doctests-unstable.rs b/tests/rustdoc-ui/output-format-doctests-unstable.rs new file mode 100644 index 0000000000000..b409f619fcc42 --- /dev/null +++ b/tests/rustdoc-ui/output-format-doctests-unstable.rs @@ -0,0 +1,4 @@ +//@ compile-flags: --output-format=doctest +pub struct Foo; + +//~? ERROR the -Z unstable-options flag must be passed to enable --output-format=doctest (see https://github.com/rust-lang/rust/issues/134529) diff --git a/tests/rustdoc-ui/output-format-doctests-unstable.stderr b/tests/rustdoc-ui/output-format-doctests-unstable.stderr new file mode 100644 index 0000000000000..b4e920efb2b0f --- /dev/null +++ b/tests/rustdoc-ui/output-format-doctests-unstable.stderr @@ -0,0 +1,2 @@ +error: the -Z unstable-options flag must be passed to enable --output-format=doctest (see https://github.com/rust-lang/rust/issues/134529) + diff --git a/tests/rustdoc-ui/output-format-irjson-emit-depinfo.rs b/tests/rustdoc-ui/output-format-irjson-emit-depinfo.rs new file mode 100644 index 0000000000000..7b5e7eaf998d4 --- /dev/null +++ b/tests/rustdoc-ui/output-format-irjson-emit-depinfo.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --output-format=json --emit=dep-info -Zunstable-options +//@ build-pass diff --git a/tests/rustdoc-ui/output-format-irjson-unstable.rs b/tests/rustdoc-ui/output-format-irjson-unstable.rs new file mode 100644 index 0000000000000..88ba753616bb9 --- /dev/null +++ b/tests/rustdoc-ui/output-format-irjson-unstable.rs @@ -0,0 +1,4 @@ +//@ compile-flags: --output-format=json +pub struct Foo; + +//~? ERROR the -Z unstable-options flag must be passed to enable --output-format=json for documentation diff --git a/tests/rustdoc-ui/output-format-irjson-unstable.stderr b/tests/rustdoc-ui/output-format-irjson-unstable.stderr new file mode 100644 index 0000000000000..dd9cea9301189 --- /dev/null +++ b/tests/rustdoc-ui/output-format-irjson-unstable.stderr @@ -0,0 +1,2 @@ +error: the -Z unstable-options flag must be passed to enable --output-format=json for documentation generation (see https://github.com/rust-lang/rust/issues/76578) + diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr b/tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr new file mode 100644 index 0000000000000..8d8e8c6d12281 --- /dev/null +++ b/tests/rustdoc-ui/output-format-json-emit-html.html_non_static_coverage.stderr @@ -0,0 +1,2 @@ +error: the `--emit=html-non-static-files` flag is not supported with `--output-format=json` + diff --git a/tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr b/tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr new file mode 100644 index 0000000000000..bc1ddc1b155d1 --- /dev/null +++ b/tests/rustdoc-ui/output-format-json-emit-html.html_static_coverage.stderr @@ -0,0 +1,2 @@ +error: the `--emit=html-static-files` flag is not supported with `--output-format=json` + diff --git a/tests/rustdoc-ui/output-format-json-emit-html.rs b/tests/rustdoc-ui/output-format-json-emit-html.rs index 7ce3bf756ec92..f97392bab5b68 100644 --- a/tests/rustdoc-ui/output-format-json-emit-html.rs +++ b/tests/rustdoc-ui/output-format-json-emit-html.rs @@ -1,7 +1,11 @@ -//@ revisions: html_static html_non_static +//@ revisions: html_static html_non_static html_static_coverage html_non_static_coverage //@ compile-flags: -Zunstable-options --output-format json //@[html_static] compile-flags: --emit html-static-files +//@[html_static_coverage] compile-flags: --emit html-static-files --show-coverage //@[html_non_static] compile-flags: --emit html-non-static-files +//@[html_non_static_coverage] compile-flags: --emit html-non-static-files --show-coverage //[html_static]~? ERROR the `--emit=html-static-files` flag is not supported with `--output-format=json` +//[html_static_coverage]~? ERROR the `--emit=html-static-files` flag is not supported with `--output-format=json` //[html_non_static]~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json` +//[html_non_static_coverage]~? ERROR the `--emit=html-non-static-files` flag is not supported with `--output-format=json` diff --git a/tests/rustdoc-ui/output-format-unknown.rs b/tests/rustdoc-ui/output-format-unknown.rs new file mode 100644 index 0000000000000..281a9ceb4cfd7 --- /dev/null +++ b/tests/rustdoc-ui/output-format-unknown.rs @@ -0,0 +1,4 @@ +//@ compile-flags: --output-format=da-doo-ron-ron + +pub struct Foo; +//~? ERROR unknown output format `da-doo-ron-ron` diff --git a/tests/rustdoc-ui/output-format-unknown.stderr b/tests/rustdoc-ui/output-format-unknown.stderr new file mode 100644 index 0000000000000..0f34e62b628ef --- /dev/null +++ b/tests/rustdoc-ui/output-format-unknown.stderr @@ -0,0 +1,2 @@ +error: unknown output format `da-doo-ron-ron` + diff --git a/tests/ui/abi/too-big-byval-abi-issue-148853.rs b/tests/ui/abi/too-big-byval-abi-issue-148853.rs new file mode 100644 index 0000000000000..503ef06ff98f3 --- /dev/null +++ b/tests/ui/abi/too-big-byval-abi-issue-148853.rs @@ -0,0 +1,12 @@ +//@ only-64bit +//@ edition: 2024 +//@ build-fail + +#![crate_type = "lib"] + +#[repr(C)] +pub struct Big([u8; 1 << 63]); + +#[unsafe(no_mangle)] +pub extern "C" fn foo(_x: Big) {} +//~^ ERROR values of the type `[u8; 9223372036854775808]` are too big for the target architecture diff --git a/tests/ui/abi/too-big-byval-abi-issue-148853.stderr b/tests/ui/abi/too-big-byval-abi-issue-148853.stderr new file mode 100644 index 0000000000000..b9247040ded25 --- /dev/null +++ b/tests/ui/abi/too-big-byval-abi-issue-148853.stderr @@ -0,0 +1,8 @@ +error: values of the type `[u8; 9223372036854775808]` are too big for the target architecture + --> $DIR/too-big-byval-abi-issue-148853.rs:11:1 + | +LL | pub extern "C" fn foo(_x: Big) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index f08d1200b9fbc..74d2bf16190de 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -102,22 +102,23 @@ error: layout_of(S) = Layout { align: AbiAlign { abi: Align(4 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, true, ), valid_range: 0..=4294967295, }, - Initialized { + b: Initialized { value: Int( I32, true, ), valid_range: 0..=4294967295, }, - ), + b_offset: Size(4 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -174,22 +175,23 @@ error: layout_of(Result) = Layout { align: AbiAlign { abi: Align(4 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Initialized { + b: Initialized { value: Int( I32, true, ), valid_range: 0..=4294967295, }, - ), + b_offset: Size(4 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -222,22 +224,23 @@ error: layout_of(Result) = Layout { variants: [ VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Initialized { + b: Initialized { value: Int( I32, true, ), valid_range: 0..=4294967295, }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], @@ -249,22 +252,23 @@ error: layout_of(Result) = Layout { }, VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Initialized { + b: Initialized { value: Int( I32, true, ), valid_range: 0..=4294967295, }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.rs b/tests/ui/layout/enum-scalar-pair-int-ptr.rs index 184f61fe79653..ff16c7e7c3af8 100644 --- a/tests/ui/layout/enum-scalar-pair-int-ptr.rs +++ b/tests/ui/layout/enum-scalar-pair-int-ptr.rs @@ -1,6 +1,7 @@ //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" //@ normalize-stderr: "Int\(I[0-9]+," -> "Int(I?," //@ normalize-stderr: "valid_range: 0..=[0-9]+" -> "valid_range: $$VALID_RANGE" +//@ normalize-stderr: "b_offset: Size\([0-9]+ bytes\)" -> "b_offset: Size(? bytes)" //! Enum layout tests related to scalar pairs with an int/ptr common primitive. diff --git a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr index 5d54fd432371e..afba5a24ee23d 100644 --- a/tests/ui/layout/enum-scalar-pair-int-ptr.stderr +++ b/tests/ui/layout/enum-scalar-pair-int-ptr.stderr @@ -1,11 +1,11 @@ -error: backend_repr: ScalarPair(Initialized { value: Int(I?, false), valid_range: $VALID_RANGE }, Initialized { value: Pointer(AddressSpace(0)), valid_range: $VALID_RANGE }) - --> $DIR/enum-scalar-pair-int-ptr.rs:12:1 +error: backend_repr: ScalarPair { a: Initialized { value: Int(I?, false), valid_range: $VALID_RANGE }, b: Initialized { value: Pointer(AddressSpace(0)), valid_range: $VALID_RANGE }, b_offset: Size(? bytes) } + --> $DIR/enum-scalar-pair-int-ptr.rs:13:1 | LL | enum ScalarPairPointerWithInt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: backend_repr: Memory { sized: true } - --> $DIR/enum-scalar-pair-int-ptr.rs:21:1 + --> $DIR/enum-scalar-pair-int-ptr.rs:22:1 | LL | enum NotScalarPairPointerWithSmallerInt { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr index 3b41129456dda..e9732d9373a48 100644 --- a/tests/ui/layout/enum.stderr +++ b/tests/ui/layout/enum.stderr @@ -10,7 +10,7 @@ error: size: Size(16 bytes) LL | enum UninhabitedVariantSpace { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }) +error: backend_repr: ScalarPair { a: Initialized { value: Int(I8, false), valid_range: 0..=1 }, b: Initialized { value: Int(I8, false), valid_range: 0..=255 }, b_offset: Size(1 bytes) } --> $DIR/enum.rs:21:1 | LL | enum ScalarPairDifferingSign { diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 7e6294f894c3e..021d7b36ac5de 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -3,21 +3,22 @@ error: layout_of(MissingPayloadField) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -50,21 +51,22 @@ error: layout_of(MissingPayloadField) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -100,22 +102,23 @@ error: layout_of(CommonPayloadField) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Initialized { + b: Initialized { value: Int( I8, false, ), valid_range: 0..=255, }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -148,22 +151,23 @@ error: layout_of(CommonPayloadField) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Initialized { + b: Initialized { value: Int( I8, false, ), valid_range: 0..=255, }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -175,22 +179,23 @@ error: layout_of(CommonPayloadField) = Layout { }, VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Initialized { + b: Initialized { value: Int( I8, false, ), valid_range: 0..=255, }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -216,21 +221,22 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -263,21 +269,22 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -289,21 +296,22 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { }, VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -329,21 +337,22 @@ error: layout_of(NicheFirst) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=4, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -380,22 +389,23 @@ error: layout_of(NicheFirst) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=2, }, - Initialized { + b: Initialized { value: Int( I8, false, ), valid_range: 0..=255, }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(0 bytes), Size(1 bytes), @@ -452,21 +462,22 @@ error: layout_of(NicheSecond) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=4, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -503,22 +514,23 @@ error: layout_of(NicheSecond) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=2, }, - Initialized { + b: Initialized { value: Int( I8, false, ), valid_range: 0..=255, }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), Size(0 bytes), diff --git a/tests/ui/macros/local-ambiguity-option-ordering.rs b/tests/ui/macros/local-ambiguity-option-ordering.rs new file mode 100644 index 0000000000000..fd9d8e17ef48f --- /dev/null +++ b/tests/ui/macros/local-ambiguity-option-ordering.rs @@ -0,0 +1,49 @@ +// Test the order in which meta-variable options causing ambiguity are presented in error messages. + +#![crate_type = "lib"] + +macro_rules! ambiguity_1 { + ($($i:ident)* $j:ident) => {}; +} + +ambiguity_1!(error); //~ ERROR local ambiguity + +macro_rules! ambiguity_2 { + ( $( $( ; $i:ident )? $( $j:ident )? ; )* ) => {}; +} + +ambiguity_2!( ; error ); //~ ERROR local ambiguity +// +// Parse tree: +// - `$(...)*`: +// - Try one repetition +// - `$(; $i)?`: +// - Try entering +// - Parse `;` +// ----> `$i` can parse `error` +// - Try ignoring +// - `$($j)?`: +// - Try entering +// - `$j` cannot parse `;` +// - failure +// - Try ignoring +// - Parse `;` +// - `$(...)*`: +// - Try another repetition +// - `$(; $i)?`: +// - Try entering +// - Cannot parse `;` +// - failure +// - Try ignoring +// - `$($j)?`: +// - Try entering +// ------------> `$j` can parse `error` +// - Try ignoring +// - Cannot parse `;` +// - failure +// - Try ignoring +// - EOF vs `error` +// - failure +// - Try no repetitions +// - EOF vs `;` +// - failure diff --git a/tests/ui/macros/local-ambiguity-option-ordering.stderr b/tests/ui/macros/local-ambiguity-option-ordering.stderr new file mode 100644 index 0000000000000..a6c79595767a0 --- /dev/null +++ b/tests/ui/macros/local-ambiguity-option-ordering.stderr @@ -0,0 +1,14 @@ +error: local ambiguity when calling macro `ambiguity_1`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). + --> $DIR/local-ambiguity-option-ordering.rs:9:14 + | +LL | ambiguity_1!(error); + | ^^^^^ + +error: local ambiguity when calling macro `ambiguity_2`: multiple parsing options: built-in NTs ident ('i') or ident ('j'). + --> $DIR/local-ambiguity-option-ordering.rs:15:17 + | +LL | ambiguity_2!( ; error ); + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr index 28fafa7800305..3b94d3751f227 100644 --- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -78,21 +78,22 @@ error: layout_of(TwoVariants) = Layout { align: AbiAlign { abi: Align(4 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -125,21 +126,22 @@ error: layout_of(TwoVariants) = Layout { variants: [ VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], @@ -151,21 +153,22 @@ error: layout_of(TwoVariants) = Layout { }, VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr index 45193552b507f..757bbba9c381a 100644 --- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -78,21 +78,22 @@ error: layout_of(TwoVariants) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -125,21 +126,22 @@ error: layout_of(TwoVariants) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -151,21 +153,22 @@ error: layout_of(TwoVariants) = Layout { }, VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr index 28fafa7800305..3b94d3751f227 100644 --- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -78,21 +78,22 @@ error: layout_of(TwoVariants) = Layout { align: AbiAlign { abi: Align(4 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -125,21 +126,22 @@ error: layout_of(TwoVariants) = Layout { variants: [ VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], @@ -151,21 +153,22 @@ error: layout_of(TwoVariants) = Layout { }, VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr index 28fafa7800305..3b94d3751f227 100644 --- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -78,21 +78,22 @@ error: layout_of(TwoVariants) = Layout { align: AbiAlign { abi: Align(4 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -125,21 +126,22 @@ error: layout_of(TwoVariants) = Layout { variants: [ VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], @@ -151,21 +153,22 @@ error: layout_of(TwoVariants) = Layout { }, VariantLayout { size: Size(8 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I32, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(4 bytes), + }, field_offsets: [ Size(4 bytes), ], diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr index c2f7fec38c81f..13051fbdaf493 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.stderr +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -78,21 +78,22 @@ error: layout_of(TwoVariantsU8) = Layout { align: AbiAlign { abi: Align(1 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), @@ -125,21 +126,22 @@ error: layout_of(TwoVariantsU8) = Layout { variants: [ VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], @@ -151,21 +153,22 @@ error: layout_of(TwoVariantsU8) = Layout { }, VariantLayout { size: Size(2 bytes), - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Int( I8, false, ), valid_range: 0..=1, }, - Union { + b: Union { value: Int( I8, false, ), }, - ), + b_offset: Size(1 bytes), + }, field_offsets: [ Size(1 bytes), ], diff --git a/tests/ui/suggestions/suggest-add-self-issue-131084.rs b/tests/ui/suggestions/suggest-add-self-issue-131084.rs new file mode 100644 index 0000000000000..adad0f56857d8 --- /dev/null +++ b/tests/ui/suggestions/suggest-add-self-issue-131084.rs @@ -0,0 +1,28 @@ +//@ check-fail + +// A recovered `¶m` should not make the missing-`self` suggestion insert +// the receiver after the leading `&`. + +struct SomeStruct; + +impl SomeStruct { + fn some_fn(&some_name) { + //~^ ERROR expected one of `:`, `@`, or `|`, found `)` + self + //~^ ERROR expected value, found module `self` + } + + fn mut_param(mut some_name) { + //~^ ERROR expected one of `:`, `@`, or `|`, found `)` + self + //~^ ERROR expected value, found module `self` + } + + fn type_before_name(String s) { + //~^ ERROR expected one of `:`, `@`, or `|`, found `s` + self + //~^ ERROR expected value, found module `self` + } +} + +fn main() {} diff --git a/tests/ui/suggestions/suggest-add-self-issue-131084.stderr b/tests/ui/suggestions/suggest-add-self-issue-131084.stderr new file mode 100644 index 0000000000000..1af7eec726273 --- /dev/null +++ b/tests/ui/suggestions/suggest-add-self-issue-131084.stderr @@ -0,0 +1,93 @@ +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/suggest-add-self-issue-131084.rs:9:26 + | +LL | fn some_fn(&some_name) { + | ^ expected one of `:`, `@`, or `|` + | +help: if this is a `self` type, give it a parameter name + | +LL | fn some_fn(self: &some_name) { + | +++++ +help: if this is a parameter name, give it a type + | +LL - fn some_fn(&some_name) { +LL + fn some_fn(some_name: &TypeName) { + | +help: if this is a type, explicitly ignore the parameter name + | +LL | fn some_fn(_: &some_name) { + | ++ + +error: expected one of `:`, `@`, or `|`, found `)` + --> $DIR/suggest-add-self-issue-131084.rs:15:31 + | +LL | fn mut_param(mut some_name) { + | ^ expected one of `:`, `@`, or `|` + | +help: if this is a `self` type, give it a parameter name + | +LL | fn mut_param(self: mut some_name) { + | +++++ +help: if this is a parameter name, give it a type + | +LL | fn mut_param(mut some_name: TypeName) { + | ++++++++++ +help: if this is a type, explicitly ignore the parameter name + | +LL | fn mut_param(_: mut some_name) { + | ++ + +error: expected one of `:`, `@`, or `|`, found `s` + --> $DIR/suggest-add-self-issue-131084.rs:21:32 + | +LL | fn type_before_name(String s) { + | -------^ + | | | + | | expected one of `:`, `@`, or `|` + | help: declare the type after the parameter binding: `: ` + +error[E0424]: expected value, found module `self` + --> $DIR/suggest-add-self-issue-131084.rs:11:9 + | +LL | fn some_fn(&some_name) { + | ------- this function doesn't have a `self` parameter +LL | +LL | self + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + | +help: add a `self` receiver parameter to make the associated `fn` a method + | +LL | fn some_fn(&self, &some_name) { + | ++++++ + +error[E0424]: expected value, found module `self` + --> $DIR/suggest-add-self-issue-131084.rs:17:9 + | +LL | fn mut_param(mut some_name) { + | --------- this function doesn't have a `self` parameter +LL | +LL | self + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + | +help: add a `self` receiver parameter to make the associated `fn` a method + | +LL | fn mut_param(&self, mut some_name) { + | ++++++ + +error[E0424]: expected value, found module `self` + --> $DIR/suggest-add-self-issue-131084.rs:23:9 + | +LL | fn type_before_name(String s) { + | ---------------- this function doesn't have a `self` parameter +LL | +LL | self + | ^^^^ `self` value is a keyword only available in methods with a `self` parameter + | +help: add a `self` receiver parameter to make the associated `fn` a method + | +LL | fn type_before_name(&self, String s) { + | ++++++ + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0424`. diff --git a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr index ca26e3dd03f35..f656a274703ee 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-2.current.stderr @@ -12,7 +12,7 @@ help: the trait `PartialEq` is not implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-3.stderr b/tests/ui/type-alias-impl-trait/self-referential-3.stderr index 8592de243adac..7bc4c6def624d 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-3.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-3.stderr @@ -13,7 +13,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/type-alias-impl-trait/self-referential-4.stderr b/tests/ui/type-alias-impl-trait/self-referential-4.stderr index c6bf1973fcbb1..76c5611906d34 100644 --- a/tests/ui/type-alias-impl-trait/self-referential-4.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential-4.stderr @@ -12,7 +12,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Foo<'static, 'b>` --> $DIR/self-referential-4.rs:13:31 @@ -28,7 +28,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `Moo<'static, 'a>` --> $DIR/self-referential-4.rs:20:31 @@ -44,7 +44,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type-alias-impl-trait/self-referential.stderr b/tests/ui/type-alias-impl-trait/self-referential.stderr index 7b4e6e9cac528..62d85466cde1a 100644 --- a/tests/ui/type-alias-impl-trait/self-referential.stderr +++ b/tests/ui/type-alias-impl-trait/self-referential.stderr @@ -13,7 +13,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Foo<'a, 'b>::{opaque#0}<'a, 'b>)` --> $DIR/self-referential.rs:14:31 @@ -30,7 +30,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: can't compare `&i32` with `(i32, Moo<'b, 'a>::{opaque#0}<'b, 'a>)` --> $DIR/self-referential.rs:22:31 @@ -47,7 +47,7 @@ help: the trait `PartialEq` is implemented for `i32` ::: $SRC_DIR/core/src/cmp.rs:LL:COL | = note: in this macro invocation - = note: this error originates in the macro `partial_eq_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `impl_partial_eq_for_primitive` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/type/pattern_types/non_null.stderr b/tests/ui/type/pattern_types/non_null.stderr index 7d3e61770c2c7..88ff73ca2a4a4 100644 --- a/tests/ui/type/pattern_types/non_null.stderr +++ b/tests/ui/type/pattern_types/non_null.stderr @@ -143,8 +143,8 @@ error: layout_of((*const [u8]) is !null) = Layout { align: AbiAlign { abi: Align(8 bytes), }, - backend_repr: ScalarPair( - Initialized { + backend_repr: ScalarPair { + a: Initialized { value: Pointer( AddressSpace( 0, @@ -152,14 +152,15 @@ error: layout_of((*const [u8]) is !null) = Layout { ), valid_range: 1..=18446744073709551615, }, - Initialized { + b: Initialized { value: Int( I64, false, ), valid_range: 0..=18446744073709551615, }, - ), + b_offset: Size(8 bytes), + }, fields: Arbitrary { offsets: [ Size(0 bytes), diff --git a/yarn.lock b/yarn.lock index cd35ba9089e46..3d5855dec80cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -74,18 +74,18 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@puppeteer/browsers@3.0.4": - version "3.0.4" - resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.0.4.tgz" - integrity sha512-HGM8iAmGTf+Y7t0373szVbTmt3d7vPkYL/1bpOkOFO0YUYLgSeuYBCzESklogNPvOBnZ/MRD5f07OkpqH1trtA== +"@puppeteer/browsers@3.0.6": + version "3.0.6" + resolved "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.0.6.tgz" + integrity sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA== dependencies: modern-tar "^0.7.6" - yargs "^17.7.2" + yargs "^18.0.0" "@ungap/structured-clone@^1.2.0": - version "1.3.1" - resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz" - integrity sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ== + version "1.3.0" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== acorn-jsx@^5.3.2: version "5.3.2" @@ -112,13 +112,23 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-regex@^6.2.2: + version "6.2.2" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz" + integrity sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg== + +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^6.2.1: + version "6.2.3" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz" + integrity sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg== + argparse@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" @@ -130,9 +140,9 @@ balanced-match@^1.0.0: integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== brace-expansion@^1.1.7: - version "1.1.15" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz" - integrity sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg== + version "1.1.14" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz" + integrity sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -144,10 +154,10 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browser-ui-test@^0.24.0: - version "0.24.0" - resolved "https://registry.npmjs.org/browser-ui-test/-/browser-ui-test-0.24.0.tgz" - integrity sha512-jVpAdq/M1cCHG/2K6pAS8NUYJ6BcNSHune72JOheeoASk+oLuGcWcY1SalYAdkWet3dlyfUSyKKtq+DDjYgdVg== +browser-ui-test@^0.24.1: + version "0.24.1" + resolved "https://registry.yarnpkg.com/browser-ui-test/-/browser-ui-test-0.24.1.tgz#1b186b652e2c6593ae1d698408d0e6ba0f32bff5" + integrity sha512-+S+gDOxc7GGfDUmZeRUcCAUzBVbD6qS7TzZSg1CFN/lgJyXf2MCG8CUbvHTsEi/oG5Iuuza1XzKDPpAAvfSUNw== dependencies: css-unit-converter "^1.1.2" pngjs "^3.4.0" @@ -175,14 +185,14 @@ chromium-bidi@16.0.1: mitt "^3.0.1" zod "^3.24.1" -cliui@^8.0.1: - version "8.0.1" - resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" - integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== +cliui@^9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz" + integrity sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w== dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.1" - wrap-ansi "^7.0.0" + string-width "^7.2.0" + strip-ansi "^7.1.0" + wrap-ansi "^9.0.0" color-convert@^2.0.1: version "2.0.1" @@ -227,10 +237,10 @@ deep-is@^0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -devtools-protocol@0.0.1624250: - version "0.0.1624250" - resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1624250.tgz" - integrity sha512-YFAat/lOiIk0ARmBweG+ygrEcbZrq5B9urRyUoeQKp53MlidHXE2TmTbxKcaXoQj7u/aX+jebDO4BW55rs0WwA== +devtools-protocol@0.0.1638949: + version "0.0.1638949" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1638949.tgz" + integrity sha512-mXwg4Fqnv0WR4iuAT/gYUmctNkjILwXFHyZ+m7Ty1dfr0ezZt2U3gnrrJTfRobJTHoXf+IbuFvFITzLrLFjwJA== doctrine@^3.0.0: version "3.0.0" @@ -239,10 +249,10 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^10.3.0: + version "10.6.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== es-check@^9.4.4: version "9.6.4" @@ -431,6 +441,11 @@ get-caller-file@^2.0.5: resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-east-asian-width@^1.0.0: + version "1.6.0" + resolved "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz" + integrity sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA== + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" @@ -510,11 +525,6 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -538,9 +548,9 @@ isexe@^2.0.0: integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== js-yaml@^4.1.0: - version "4.2.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz" - integrity sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw== + version "4.1.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -706,28 +716,28 @@ punycode@^2.1.0: resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -puppeteer-core@25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.1.0.tgz" - integrity sha512-jKzy5y4WG6uNuFbTWgW1D7mqoT9o0nllc/6a1DGF775T1mPmgw3scdFEtEq67yVFikavQmbYq6NLfbTfxHSlqQ== +puppeteer-core@25.3.0: + version "25.3.0" + resolved "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.3.0.tgz" + integrity sha512-fm+wpUr2oigH1PXZvwgATrM2tYWHMDG8ASzTEe9uukCye4X5Ldx1K5BTHPFKITrIWvQQAQ256d1NpbEveBcKjA== dependencies: - "@puppeteer/browsers" "3.0.4" + "@puppeteer/browsers" "3.0.6" chromium-bidi "16.0.1" - devtools-protocol "0.0.1624250" + devtools-protocol "0.0.1638949" typed-query-selector "^2.12.2" webdriver-bidi-protocol "0.4.2" ws "^8.21.0" puppeteer@^25.1.0: - version "25.1.0" - resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-25.1.0.tgz" - integrity sha512-7L6/0JM7XStK99lIL4xQySyNEXNfII6pk0BxkI5kKBTOhR7AsoQiv067YTsE/rIXxQiq9ajlO4WcqBjS/FWK1A== + version "25.3.0" + resolved "https://registry.npmjs.org/puppeteer/-/puppeteer-25.3.0.tgz" + integrity sha512-O1tx8S315aw8eI99HZ5ZNcVEzJ9+jKF//eO5UvfZ3cXJ6okZ5sX3Y50u7DJaM+ewEK4LqXP068tBhfRaWikj+g== dependencies: - "@puppeteer/browsers" "3.0.4" + "@puppeteer/browsers" "3.0.6" chromium-bidi "16.0.1" - devtools-protocol "0.0.1624250" + devtools-protocol "0.0.1638949" lilconfig "^3.1.3" - puppeteer-core "25.1.0" + puppeteer-core "25.3.0" typed-query-selector "^2.12.2" queue-microtask@^1.2.2: @@ -740,11 +750,6 @@ readline-sync@^1.4.10: resolved "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz" integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" @@ -781,22 +786,29 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== +string-width@^7.0.0, string-width@^7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz" + integrity sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ== dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" + emoji-regex "^10.3.0" + get-east-asian-width "^1.0.0" + strip-ansi "^7.1.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz" + integrity sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w== + dependencies: + ansi-regex "^6.2.2" + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" @@ -867,14 +879,14 @@ word-wrap@^1.2.5: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== +wrap-ansi@^9.0.0: + version "9.0.2" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz" + integrity sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww== dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" + ansi-styles "^6.2.1" + string-width "^7.0.0" + strip-ansi "^7.1.0" wrappy@1: version "1.0.2" @@ -891,23 +903,22 @@ y18n@^5.0.5: resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@^21.1.1: - version "21.1.1" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" - integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== +yargs-parser@^22.0.0: + version "22.0.0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz" + integrity sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw== -yargs@^17.7.2: - version "17.7.2" - resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" - integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== +yargs@^18.0.0: + version "18.0.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz" + integrity sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg== dependencies: - cliui "^8.0.1" + cliui "^9.0.1" escalade "^3.1.1" get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.3" + string-width "^7.2.0" y18n "^5.0.5" - yargs-parser "^21.1.1" + yargs-parser "^22.0.0" yocto-queue@^0.1.0: version "0.1.0"