From c8c6598f17128b3ac1ec3573dc54876d24cc7a77 Mon Sep 17 00:00:00 2001 From: "Celina G. Val" Date: Wed, 12 Jun 2024 16:01:38 -0700 Subject: [PATCH 01/15] Unify intrinsics body handling in StableMIR rust-lang/rust#120675 introduced a new mechanism to declare intrinsics which will potentially replace the rust-intrinsic ABI. The new mechanism introduces a placeholder body and mark the intrinsic with #[rustc_intrinsic_must_be_overridden]. In practice, this means that backends should not generate code for the placeholder, and shim the intrinsic. The new annotation is an internal compiler implementation, and it doesn't need to be exposed to StableMIR users. In this PR, intrinsics marked with `rustc_intrinsic_must_be_overridden` are handled the same way as intrinsics that do not have a body. --- compiler/rustc_smir/src/rustc_smir/context.rs | 16 +++++--------- compiler/rustc_smir/src/rustc_smir/mod.rs | 21 +++++++++++++++++-- compiler/stable_mir/src/compiler_interface.rs | 4 ---- compiler/stable_mir/src/ty.rs | 7 ++++++- .../stable-mir/check_intrinsics.rs | 19 ++++++++++------- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index a8688c88601c5..64174981b79a3 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -63,9 +63,10 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } fn has_body(&self, def: DefId) -> bool { - let tables = self.0.borrow(); - let def_id = tables[def]; - tables.tcx.is_mir_available(def_id) + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let def_id = def.internal(&mut *tables, tcx); + tables.item_has_body(def_id) } fn foreign_modules(&self, crate_num: CrateNum) -> Vec { @@ -322,13 +323,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> { tcx.intrinsic(def_id).unwrap().name.to_string() } - fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool { - let mut tables = self.0.borrow_mut(); - let tcx = tables.tcx; - let def_id = def.0.internal(&mut *tables, tcx); - tcx.intrinsic_raw(def_id).unwrap().must_be_overridden - } - fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; @@ -515,7 +509,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let mut tables = self.0.borrow_mut(); let instance = tables.instances[def]; tables - .has_body(instance) + .instance_has_body(instance) .then(|| BodyBuilder::new(tables.tcx, instance).build(&mut *tables)) } diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index d13e780332632..89f9adfcfd663 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -51,9 +51,13 @@ impl<'tcx> Tables<'tcx> { self.mir_consts.create_or_fetch(constant) } - pub(crate) fn has_body(&self, instance: Instance<'tcx>) -> bool { + /// Return whether the instance as a body available. + /// + /// Items and intrinsics may have a body available from its definition. + /// Shims body may be generated depending on their type. + pub(crate) fn instance_has_body(&self, instance: Instance<'tcx>) -> bool { let def_id = instance.def_id(); - self.tcx.is_mir_available(def_id) + self.item_has_body(def_id) || !matches!( instance.def, ty::InstanceDef::Virtual(..) @@ -61,6 +65,19 @@ impl<'tcx> Tables<'tcx> { | ty::InstanceDef::Item(..) ) } + + /// Return whether the item has a body defined by the user. + /// + /// Note that intrinsics may have a placeholder body that shouldn't be used in practice. + /// In StableMIR, we handle this case as if the body is not available. + pub(crate) fn item_has_body(&self, def_id: DefId) -> bool { + let must_override = if let Some(intrinsic) = self.tcx.intrinsic(def_id) { + intrinsic.must_be_overridden + } else { + false + }; + !must_override && self.tcx.is_mir_available(def_id) + } } /// Build a stable mir crate from a given crate number. diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 085dfd9ea8909..3e138e3c2e04e 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -94,10 +94,6 @@ pub trait Context { /// Retrieve the plain function name of an intrinsic. fn intrinsic_name(&self, def: IntrinsicDef) -> Symbol; - /// Returns whether the intrinsic has no meaningful body and all backends - /// need to shim all calls to it. - fn intrinsic_must_be_overridden(&self, def: IntrinsicDef) -> bool; - /// Retrieve the closure signature for the given generic arguments. fn closure_sig(&self, args: &GenericArgs) -> PolyFnSig; diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index bcbe87f7303b3..cdf1b0641ff3f 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -658,6 +658,11 @@ impl FnDef { with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) } + // Check if the function body is available. + pub fn has_body(&self) -> bool { + with(|ctx| ctx.has_body(self.0)) + } + /// Get the information of the intrinsic if this function is a definition of one. pub fn as_intrinsic(&self) -> Option { with(|cx| cx.intrinsic(self.def_id())) @@ -684,7 +689,7 @@ impl IntrinsicDef { /// Returns whether the intrinsic has no meaningful body and all backends /// need to shim all calls to it. pub fn must_be_overridden(&self) -> bool { - with(|cx| cx.intrinsic_must_be_overridden(*self)) + with(|cx| !cx.has_body(self.0)) } } diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs index 7e247ce0c75d2..d7f37f36681bd 100644 --- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs +++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs @@ -55,16 +55,19 @@ fn test_intrinsics() -> ControlFlow<()> { /// /// If by any chance this test breaks because you changed how an intrinsic is implemented, please /// update the test to invoke a different intrinsic. +/// +/// In StableMIR, we only expose intrinsic body if they are not marked with +/// `rustc_intrinsic_must_be_overridden`. fn check_instance(instance: &Instance) { assert_eq!(instance.kind, InstanceKind::Intrinsic); let name = instance.intrinsic_name().unwrap(); if instance.has_body() { let Some(body) = instance.body() else { unreachable!("Expected a body") }; assert!(!body.blocks.is_empty()); - assert_matches!(name.as_str(), "likely" | "vtable_size"); + assert_eq!(&name, "likely"); } else { assert!(instance.body().is_none()); - assert_eq!(&name, "size_of_val"); + assert_matches!(name.as_str(), "size_of_val" | "vtable_size"); } } @@ -75,11 +78,13 @@ fn check_def(fn_def: FnDef) { let name = intrinsic.fn_name(); match name.as_str() { - "likely" | "size_of_val" => { + "likely" => { assert!(!intrinsic.must_be_overridden()); + assert!(fn_def.has_body()); } - "vtable_size" => { + "vtable_size" | "size_of_val" => { assert!(intrinsic.must_be_overridden()); + assert!(!fn_def.has_body()); } _ => unreachable!("Unexpected intrinsic: {}", name), } @@ -96,9 +101,9 @@ impl<'a> MirVisitor for CallsVisitor<'a> { TerminatorKind::Call { func, .. } => { let TyKind::RigidTy(RigidTy::FnDef(def, args)) = func.ty(self.locals).unwrap().kind() - else { - return; - }; + else { + return; + }; self.calls.push((def, args.clone())); } _ => {} From dfc55145270c5ec8de1bcd19ae05f056100108a5 Mon Sep 17 00:00:00 2001 From: beetrees Date: Thu, 13 Jun 2024 16:09:45 +0100 Subject: [PATCH 02/15] Add `f16` and `f128` inline ASM support for `x86` and `x86-64` --- compiler/rustc_codegen_llvm/src/asm.rs | 100 +++++++ .../src/check/intrinsicck.rs | 4 + compiler/rustc_target/src/asm/mod.rs | 12 + compiler/rustc_target/src/asm/x86.rs | 22 +- tests/assembly/asm/x86-types.rs | 244 ++++++++++++++++-- tests/ui/asm/x86_64/type-check-3.stderr | 10 +- 6 files changed, 350 insertions(+), 42 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index db28c6857b743..60e63b956db6e 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -959,6 +959,43 @@ fn llvm_fixup_input<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + bx.bitcast(value, bx.type_vector(bx.type_i32(), 4)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.insert_element( + bx.const_undef(bx.type_vector(bx.type_f16(), 8)), + value, + bx.const_usize(0), + ); + bx.bitcast(value, bx.type_vector(bx.type_i16(), 8)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), @@ -1036,6 +1073,39 @@ fn llvm_fixup_output<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if bx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + bx.bitcast(value, bx.type_f128()) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.bitcast(value, bx.type_vector(bx.type_f16(), 8)); + bx.extract_element(value, bx.const_usize(0)) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), @@ -1109,6 +1179,36 @@ fn llvm_fixup_output_type<'ll, 'tcx>( InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), Abi::Vector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if cx.sess().asm_arch == Some(InlineAsmArch::X86) + && s.primitive() == Primitive::Float(Float::F128) => + { + cx.type_vector(cx.type_i32(), 4) + } + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_vector(cx.type_i16(), 8), + ( + InlineAsmRegClass::X86( + X86InlineAsmRegClass::xmm_reg + | X86InlineAsmRegClass::ymm_reg + | X86InlineAsmRegClass::zmm_reg, + ), + Abi::Vector { element, count: count @ (8 | 16) }, + ) if element.primitive() == Primitive::Float(Float::F16) => { + cx.type_vector(cx.type_i16(), count) + } ( InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg | ArmInlineAsmRegClass::sreg_low16), Abi::Scalar(s), diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 2672614a89548..88cbd0217f2b2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -62,8 +62,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64), ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128), ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize), + ty::Float(FloatTy::F16) => Some(InlineAsmType::F16), ty::Float(FloatTy::F32) => Some(InlineAsmType::F32), ty::Float(FloatTy::F64) => Some(InlineAsmType::F64), + ty::Float(FloatTy::F128) => Some(InlineAsmType::F128), ty::FnPtr(_) => Some(asm_ty_isize), ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Some(asm_ty_isize), ty::Adt(adt, args) if adt.repr().simd() => { @@ -105,8 +107,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { width => bug!("unsupported pointer width: {width}"), }) } + ty::Float(FloatTy::F16) => Some(InlineAsmType::VecF16(size)), ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)), ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)), + ty::Float(FloatTy::F128) => Some(InlineAsmType::VecF128(size)), _ => None, } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 5f4ce5ed59974..b057bf94a087a 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -707,15 +707,19 @@ pub enum InlineAsmType { I32, I64, I128, + F16, F32, F64, + F128, VecI8(u64), VecI16(u64), VecI32(u64), VecI64(u64), VecI128(u64), + VecF16(u64), VecF32(u64), VecF64(u64), + VecF128(u64), } impl InlineAsmType { @@ -730,15 +734,19 @@ impl InlineAsmType { Self::I32 => 4, Self::I64 => 8, Self::I128 => 16, + Self::F16 => 2, Self::F32 => 4, Self::F64 => 8, + Self::F128 => 16, Self::VecI8(n) => n * 1, Self::VecI16(n) => n * 2, Self::VecI32(n) => n * 4, Self::VecI64(n) => n * 8, Self::VecI128(n) => n * 16, + Self::VecF16(n) => n * 2, Self::VecF32(n) => n * 4, Self::VecF64(n) => n * 8, + Self::VecF128(n) => n * 16, }) } } @@ -751,15 +759,19 @@ impl fmt::Display for InlineAsmType { Self::I32 => f.write_str("i32"), Self::I64 => f.write_str("i64"), Self::I128 => f.write_str("i128"), + Self::F16 => f.write_str("f16"), Self::F32 => f.write_str("f32"), Self::F64 => f.write_str("f64"), + Self::F128 => f.write_str("f128"), Self::VecI8(n) => write!(f, "i8x{n}"), Self::VecI16(n) => write!(f, "i16x{n}"), Self::VecI32(n) => write!(f, "i32x{n}"), Self::VecI64(n) => write!(f, "i64x{n}"), Self::VecI128(n) => write!(f, "i128x{n}"), + Self::VecF16(n) => write!(f, "f16x{n}"), Self::VecF32(n) => write!(f, "f32x{n}"), Self::VecF64(n) => write!(f, "f64x{n}"), + Self::VecF128(n) => write!(f, "f128x{n}"), } } } diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 28413a5bcbd17..8452961c17c0f 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -107,26 +107,26 @@ impl X86InlineAsmRegClass { match self { Self::reg | Self::reg_abcd => { if arch == InlineAsmArch::X86_64 { - types! { _: I16, I32, I64, F32, F64; } + types! { _: I16, I32, I64, F16, F32, F64; } } else { - types! { _: I16, I32, F32; } + types! { _: I16, I32, F16, F32; } } } Self::reg_byte => types! { _: I8; }, Self::xmm_reg => types! { - sse: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + sse: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); }, Self::ymm_reg => types! { - avx: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4); + avx: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); }, Self::zmm_reg => types! { - avx512f: I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4), - VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8); + avx512f: I32, I64, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), + VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); }, Self::kreg => types! { avx512f: I8, I16; diff --git a/tests/assembly/asm/x86-types.rs b/tests/assembly/asm/x86-types.rs index 2b4ebb05349ba..8e229614420b6 100644 --- a/tests/assembly/asm/x86-types.rs +++ b/tests/assembly/asm/x86-types.rs @@ -7,7 +7,7 @@ //@ compile-flags: -C llvm-args=--x86-asm-syntax=intel //@ compile-flags: -C target-feature=+avx512bw -#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd, f16, f128)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -41,6 +41,8 @@ pub struct i32x4(i32, i32, i32, i32); #[repr(simd)] pub struct i64x2(i64, i64); #[repr(simd)] +pub struct f16x8(f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x4(f32, f32, f32, f32); #[repr(simd)] pub struct f64x2(f64, f64); @@ -87,6 +89,8 @@ pub struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); #[repr(simd)] pub struct i64x4(i64, i64, i64, i64); #[repr(simd)] +pub struct f16x16(f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16, f16); +#[repr(simd)] pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] pub struct f64x4(f64, f64, f64, f64); @@ -198,35 +202,59 @@ pub struct i32x16(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i3 #[repr(simd)] pub struct i64x8(i64, i64, i64, i64, i64, i64, i64, i64); #[repr(simd)] +pub struct f16x32( + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, + f16, +); +#[repr(simd)] pub struct f32x16(f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32); #[repr(simd)] pub struct f64x8(f64, f64, f64, f64, f64, f64, f64, f64); -impl Copy for i8 {} -impl Copy for i16 {} -impl Copy for i32 {} -impl Copy for f32 {} -impl Copy for i64 {} -impl Copy for f64 {} -impl Copy for ptr {} -impl Copy for i8x16 {} -impl Copy for i16x8 {} -impl Copy for i32x4 {} -impl Copy for i64x2 {} -impl Copy for f32x4 {} -impl Copy for f64x2 {} -impl Copy for i8x32 {} -impl Copy for i16x16 {} -impl Copy for i32x8 {} -impl Copy for i64x4 {} -impl Copy for f32x8 {} -impl Copy for f64x4 {} -impl Copy for i8x64 {} -impl Copy for i16x32 {} -impl Copy for i32x16 {} -impl Copy for i64x8 {} -impl Copy for f32x16 {} -impl Copy for f64x8 {} +macro_rules! impl_copy { + ($($ty:ident)*) => { + $( + impl Copy for $ty {} + )* + }; +} + +impl_copy!( + i8 i16 f16 i32 f32 i64 f64 f128 ptr + i8x16 i16x8 i32x4 i64x2 f16x8 f32x4 f64x2 + i8x32 i16x16 i32x8 i64x4 f16x16 f32x8 f64x4 + i8x64 i16x32 i32x16 i64x8 f16x32 f32x16 f64x8 +); extern "C" { fn extern_func(); @@ -292,6 +320,13 @@ macro_rules! check_reg { // CHECK: #NO_APP check!(reg_i16 i16 reg "mov"); +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f16 f16 reg "mov"); + // CHECK-LABEL: reg_i32: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -334,6 +369,13 @@ check!(reg_ptr ptr reg "mov"); // CHECK: #NO_APP check!(reg_abcd_i16 i16 reg_abcd "mov"); +// CHECK-LABEL: reg_abcd_f16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_f16 f16 reg_abcd "mov"); + // CHECK-LABEL: reg_abcd_i32: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -375,6 +417,12 @@ check!(reg_abcd_ptr ptr reg_abcd "mov"); // CHECK: #NO_APP check!(reg_byte i8 reg_byte "mov"); +// CHECK-LABEL: xmm_reg_f16: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16 f16 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_i32: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -399,6 +447,12 @@ check!(xmm_reg_i64 i64 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_f64 f64 xmm_reg "movaps"); +// CHECK-LABEL: xmm_reg_f128: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f128 f128 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_ptr: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -429,6 +483,12 @@ check!(xmm_reg_i32x4 i32x4 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_i64x2 i64x2 xmm_reg "movaps"); +// CHECK-LABEL: xmm_reg_f16x8: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f16x8 f16x8 xmm_reg "movaps"); + // CHECK-LABEL: xmm_reg_f32x4: // CHECK: #APP // CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} @@ -441,6 +501,12 @@ check!(xmm_reg_f32x4 f32x4 xmm_reg "movaps"); // CHECK: #NO_APP check!(xmm_reg_f64x2 f64x2 xmm_reg "movaps"); +// CHECK-LABEL: ymm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16 f16 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_i32: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -465,6 +531,12 @@ check!(ymm_reg_i64 i64 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_f64 f64 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f128 f128 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_ptr: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -495,6 +567,12 @@ check!(ymm_reg_i32x4 i32x4 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_i64x2 i64x2 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x8 f16x8 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_f32x4: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -531,6 +609,12 @@ check!(ymm_reg_i32x8 i32x8 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_i64x4 i64x4 ymm_reg "vmovaps"); +// CHECK-LABEL: ymm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f16x16 f16x16 ymm_reg "vmovaps"); + // CHECK-LABEL: ymm_reg_f32x8: // CHECK: #APP // CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} @@ -543,6 +627,12 @@ check!(ymm_reg_f32x8 f32x8 ymm_reg "vmovaps"); // CHECK: #NO_APP check!(ymm_reg_f64x4 f64x4 ymm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16 f16 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_i32: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -567,6 +657,12 @@ check!(zmm_reg_i64 i64 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_f64 f64 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f128: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f128 f128 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_ptr: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -597,6 +693,12 @@ check!(zmm_reg_i32x4 i32x4 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x2 i64x2 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x8 f16x8 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x4: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -633,6 +735,12 @@ check!(zmm_reg_i32x8 i32x8 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x4 i64x4 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x16 f16x16 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x8: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -669,6 +777,12 @@ check!(zmm_reg_i32x16 i32x16 zmm_reg "vmovaps"); // CHECK: #NO_APP check!(zmm_reg_i64x8 i64x8 zmm_reg "vmovaps"); +// CHECK-LABEL: zmm_reg_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f16x32 f16x32 zmm_reg "vmovaps"); + // CHECK-LABEL: zmm_reg_f32x16: // CHECK: #APP // CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} @@ -717,6 +831,12 @@ check!(kreg_ptr ptr kreg "kmovq"); // CHECK: #NO_APP check_reg!(eax_i16 i16 "eax" "mov"); +// CHECK-LABEL: eax_f16: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_f16 f16 "eax" "mov"); + // CHECK-LABEL: eax_i32: // CHECK: #APP // CHECK: mov eax, eax @@ -756,6 +876,12 @@ check_reg!(eax_ptr ptr "eax" "mov"); #[cfg(i686)] check_reg!(ah_byte i8 "ah" "mov"); +// CHECK-LABEL: xmm0_f16: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16 f16 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_i32: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -780,6 +906,12 @@ check_reg!(xmm0_i64 i64 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_f64 f64 "xmm0" "movaps"); +// CHECK-LABEL: xmm0_f128: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f128 f128 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_ptr: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -810,6 +942,12 @@ check_reg!(xmm0_i32x4 i32x4 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_i64x2 i64x2 "xmm0" "movaps"); +// CHECK-LABEL: xmm0_f16x8: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f16x8 f16x8 "xmm0" "movaps"); + // CHECK-LABEL: xmm0_f32x4: // CHECK: #APP // CHECK: movaps xmm0, xmm0 @@ -822,6 +960,12 @@ check_reg!(xmm0_f32x4 f32x4 "xmm0" "movaps"); // CHECK: #NO_APP check_reg!(xmm0_f64x2 f64x2 "xmm0" "movaps"); +// CHECK-LABEL: ymm0_f16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16 f16 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_i32: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -846,6 +990,12 @@ check_reg!(ymm0_i64 i64 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_f64 f64 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f128: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f128 f128 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_ptr: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -876,6 +1026,12 @@ check_reg!(ymm0_i32x4 i32x4 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_i64x2 i64x2 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x8 f16x8 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_f32x4: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -912,6 +1068,12 @@ check_reg!(ymm0_i32x8 i32x8 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_i64x4 i64x4 "ymm0" "vmovaps"); +// CHECK-LABEL: ymm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f16x16 f16x16 "ymm0" "vmovaps"); + // CHECK-LABEL: ymm0_f32x8: // CHECK: #APP // CHECK: vmovaps ymm0, ymm0 @@ -924,6 +1086,12 @@ check_reg!(ymm0_f32x8 f32x8 "ymm0" "vmovaps"); // CHECK: #NO_APP check_reg!(ymm0_f64x4 f64x4 "ymm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16 f16 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_i32: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -948,6 +1116,12 @@ check_reg!(zmm0_i64 i64 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_f64 f64 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f128: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f128 f128 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_ptr: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -978,6 +1152,12 @@ check_reg!(zmm0_i32x4 i32x4 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x2 i64x2 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x8 f16x8 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x4: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -1014,6 +1194,12 @@ check_reg!(zmm0_i32x8 i32x8 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x4 i64x4 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x16 f16x16 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x8: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 @@ -1050,6 +1236,12 @@ check_reg!(zmm0_i32x16 i32x16 "zmm0" "vmovaps"); // CHECK: #NO_APP check_reg!(zmm0_i64x8 i64x8 "zmm0" "vmovaps"); +// CHECK-LABEL: zmm0_f16x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f16x32 f16x32 "zmm0" "vmovaps"); + // CHECK-LABEL: zmm0_f32x16: // CHECK: #APP // CHECK: vmovaps zmm0, zmm0 diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index 34bfcd71caca7..202b97ca5c0e8 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -4,7 +4,7 @@ error: type `i128` cannot be used with this register class LL | asm!("{}", in(reg) 0i128); | ^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `__m128` cannot be used with this register class --> $DIR/type-check-3.rs:16:28 @@ -12,7 +12,7 @@ error: type `__m128` cannot be used with this register class LL | asm!("{}", in(reg) _mm_setzero_ps()); | ^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `__m256` cannot be used with this register class --> $DIR/type-check-3.rs:18:28 @@ -20,7 +20,7 @@ error: type `__m256` cannot be used with this register class LL | asm!("{}", in(reg) _mm256_setzero_ps()); | ^^^^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 error: type `u8` cannot be used with this register class --> $DIR/type-check-3.rs:20:32 @@ -28,7 +28,7 @@ error: type `u8` cannot be used with this register class LL | asm!("{}", in(xmm_reg) 0u8); | ^^^ | - = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + = note: register class `xmm_reg` supports these types: i32, i64, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: `avx512bw` target feature is not enabled --> $DIR/type-check-3.rs:29:29 @@ -81,7 +81,7 @@ error: type `i8` cannot be used with this register class LL | asm!("{}", in(reg) 0i8); | ^^^ | - = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f16, f32, f64 = help: consider using the `reg_byte` register class instead error: incompatible types for asm inout argument From 4440f50996e12611e82735b57a0be143b18e9ea3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 3 Mar 2024 15:34:22 +0300 Subject: [PATCH 03/15] rustc_span: Add conveniences for working with span formats --- compiler/rustc_span/src/lib.rs | 1 + compiler/rustc_span/src/span_encoding.rs | 248 ++++++++++++++--------- 2 files changed, 149 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 99fcaf917fe9c..7b4506d33cac2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -520,6 +520,7 @@ impl SpanData { pub fn with_hi(&self, hi: BytePos) -> Span { Span::new(self.lo, hi, self.ctxt, self.parent) } + /// Avoid if possible, `Span::update_ctxt` should be preferred. #[inline] fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 52a1267f8918c..8227597ac6f92 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -4,10 +4,10 @@ use crate::SPAN_TRACK; use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; - // This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. // See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 use rustc_serialize::int_overflow::DebugStrictAdd; +use std::mem::transmute; /// A compressed span. /// @@ -87,45 +87,130 @@ pub struct Span { ctxt_or_parent_or_marker: u16, } -impl Span { +// Convenience structures for all span formats. +#[derive(Clone, Copy)] +struct InlineCtxt { + lo: u32, + len: u16, + ctxt: u16, +} + +#[derive(Clone, Copy)] +struct InlineParent { + lo: u32, + len_with_tag: u16, + parent: u16, +} + +#[derive(Clone, Copy)] +struct PartiallyInterned { + index: u32, + _marker1: u16, + ctxt: u16, +} + +#[derive(Clone, Copy)] +struct Interned { + index: u32, + _marker1: u16, + _marker2: u16, +} + +impl InlineCtxt { #[inline] - fn data_inline_ctxt(self) -> SpanData { - let len = self.len_with_tag_or_marker as u32; + fn data(self) -> SpanData { + let len = self.len as u32; debug_assert!(len <= MAX_LEN); SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), + lo: BytePos(self.lo), + hi: BytePos(self.lo.debug_strict_add(len)), + ctxt: SyntaxContext::from_u32(self.ctxt as u32), parent: None, } } #[inline] - fn data_inline_parent(self) -> SpanData { - let len = (self.len_with_tag_or_marker & !PARENT_TAG) as u32; + fn span(lo: u32, len: u16, ctxt: u16) -> Span { + unsafe { transmute(InlineCtxt { lo, len, ctxt }) } + } +} + +impl InlineParent { + #[inline] + fn data(self) -> SpanData { + let len = (self.len_with_tag & !PARENT_TAG) as u32; debug_assert!(len <= MAX_LEN); - let parent = LocalDefId { - local_def_index: DefIndex::from_u32(self.ctxt_or_parent_or_marker as u32), - }; SpanData { - lo: BytePos(self.lo_or_index), - hi: BytePos(self.lo_or_index.debug_strict_add(len)), + lo: BytePos(self.lo), + hi: BytePos(self.lo.debug_strict_add(len)), ctxt: SyntaxContext::root(), - parent: Some(parent), + parent: Some(LocalDefId { local_def_index: DefIndex::from_u32(self.parent as u32) }), } } #[inline] - fn data_partially_interned(self) -> SpanData { + fn span(lo: u32, len_with_tag: u16, parent: u16) -> Span { + unsafe { transmute(InlineParent { lo, len_with_tag, parent }) } + } +} + +impl PartiallyInterned { + #[inline] + fn data(self) -> SpanData { SpanData { - ctxt: SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32), - ..with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + ctxt: SyntaxContext::from_u32(self.ctxt as u32), + ..with_span_interner(|interner| interner.spans[self.index as usize]) } } #[inline] - fn data_interned(self) -> SpanData { - with_span_interner(|interner| interner.spans[self.lo_or_index as usize]) + fn span(index: u32, ctxt: u16) -> Span { + unsafe { transmute(PartiallyInterned { index, _marker1: BASE_LEN_INTERNED_MARKER, ctxt }) } } } +impl Interned { + #[inline] + fn data(self) -> SpanData { + with_span_interner(|interner| interner.spans[self.index as usize]) + } + #[inline] + fn span(index: u32) -> Span { + let _marker1 = BASE_LEN_INTERNED_MARKER; + unsafe { transmute(Interned { index, _marker1, _marker2: CTXT_INTERNED_MARKER }) } + } +} + +// This code is very hot, and converting span to an enum and matching on it doesn't optimize away +// properly. So we are using a macro emulating such a match, but expand it directly to an if-else +// chain. +macro_rules! match_span_kind { + ( + $span:expr, + InlineCtxt($span1:ident) => $arm1:expr, + InlineParent($span2:ident) => $arm2:expr, + PartiallyInterned($span3:ident) => $arm3:expr, + Interned($span4:ident) => $arm4:expr, + ) => { + if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { + if $span.len_with_tag_or_marker & PARENT_TAG == 0 { + // Inline-context format. + let $span1: &mut InlineCtxt = unsafe { transmute(&mut *$span) }; + $arm1 + } else { + // Inline-parent format. + let $span2: &mut InlineParent = unsafe { transmute(&mut *$span) }; + $arm2 + } + } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { + // Partially-interned format. + let $span3: &mut PartiallyInterned = unsafe { transmute(&mut *$span) }; + $arm3 + } else { + // Interned format. + let $span4: &mut Interned = unsafe { transmute(&mut *$span) }; + $arm4 + } + }; +} + // `MAX_LEN` is chosen so that `PARENT_TAG | MAX_LEN` is distinct from // `BASE_LEN_INTERNED_MARKER`. (If `MAX_LEN` was 1 higher, this wouldn't be true.) const MAX_LEN: u32 = 0b0111_1111_1111_1110; @@ -154,23 +239,13 @@ impl Span { let (len, ctxt32) = (hi.0 - lo.0, ctxt.as_u32()); if len <= MAX_LEN { if ctxt32 <= MAX_CTXT && parent.is_none() { - // Inline-context format. - return Span { - lo_or_index: lo.0, - len_with_tag_or_marker: len as u16, - ctxt_or_parent_or_marker: ctxt32 as u16, - }; + return InlineCtxt::span(lo.0, len as u16, ctxt32 as u16); } else if ctxt32 == 0 && let Some(parent) = parent && let parent32 = parent.local_def_index.as_u32() && parent32 <= MAX_CTXT { - // Inline-parent format. - return Span { - lo_or_index: lo.0, - len_with_tag_or_marker: PARENT_TAG | len as u16, - ctxt_or_parent_or_marker: parent32 as u16, - }; + return InlineParent::span(lo.0, PARENT_TAG | len as u16, parent32 as u16); } } @@ -179,20 +254,10 @@ impl Span { with_span_interner(|interner| interner.intern(&SpanData { lo, hi, ctxt, parent })) }; if ctxt32 <= MAX_CTXT { - // Partially-interned format. - Span { - // Interned ctxt should never be read, so it can use any value. - lo_or_index: index(SyntaxContext::from_u32(u32::MAX)), - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker: ctxt32 as u16, - } + // Interned ctxt should never be read, so it can use any value. + PartiallyInterned::span(index(SyntaxContext::from_u32(u32::MAX)), ctxt32 as u16) } else { - // Interned format. - Span { - lo_or_index: index(ctxt), - len_with_tag_or_marker: BASE_LEN_INTERNED_MARKER, - ctxt_or_parent_or_marker: CTXT_INTERNED_MARKER, - } + Interned::span(index(ctxt)) } } @@ -208,21 +273,13 @@ impl Span { /// Internal function to translate between an encoded span and the expanded representation. /// This function must not be used outside the incremental engine. #[inline] - pub fn data_untracked(self) -> SpanData { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - self.data_inline_ctxt() - } else { - // Inline-parent format. - self.data_inline_parent() - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - self.data_partially_interned() - } else { - // Interned format. - self.data_interned() + pub fn data_untracked(mut self) -> SpanData { + match_span_kind! { + &mut self, + InlineCtxt(span) => span.data(), + InlineParent(span) => span.data(), + PartiallyInterned(span) => span.data(), + Interned(span) => span.data(), } } @@ -249,42 +306,41 @@ impl Span { #[inline] pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) { let (updated_ctxt32, data); - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. + match_span_kind! { + self, + InlineCtxt(span) => { updated_ctxt32 = - update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); + update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); // Any small new context including zero will preserve the format. if updated_ctxt32 <= MAX_CTXT { - self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; + span.ctxt = updated_ctxt32 as u16; return; } - data = self.data_inline_ctxt(); - } else { - // Inline-parent format. + data = span.data(); + }, + InlineParent(span) => { updated_ctxt32 = update(SyntaxContext::root()).as_u32(); // Only if the new context is zero the format will be preserved. if updated_ctxt32 == 0 { // Do nothing. return; } - data = self.data_inline_parent(); - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - updated_ctxt32 = - update(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)).as_u32(); - // Any small new context excluding zero will preserve the format. - // Zero may change the format to `InlineParent` if parent and len are small enough. - if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { - self.ctxt_or_parent_or_marker = updated_ctxt32 as u16; - return; - } - data = self.data_partially_interned(); - } else { - // Interned format. - data = self.data_interned(); - updated_ctxt32 = update(data.ctxt).as_u32(); + data = span.data(); + }, + PartiallyInterned(span) => { + updated_ctxt32 = update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); + // Any small new context excluding zero will preserve the format. + // Zero may change the format to `InlineParent` if parent and len are small enough. + if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { + span.ctxt = updated_ctxt32 as u16; + return; + } + data = span.data(); + }, + Interned(span) => { + data = span.data(); + updated_ctxt32 = update(data.ctxt).as_u32(); + }, } // We could not keep the span in the same inline format, fall back to the complete logic. @@ -294,21 +350,13 @@ impl Span { // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. #[inline] - fn inline_ctxt(self) -> Result { - if self.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { - if self.len_with_tag_or_marker & PARENT_TAG == 0 { - // Inline-context format. - Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) - } else { - // Inline-parent format. - Ok(SyntaxContext::root()) - } - } else if self.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { - // Partially-interned format. - Ok(SyntaxContext::from_u32(self.ctxt_or_parent_or_marker as u32)) - } else { - // Interned format. - Err(self.lo_or_index as usize) + fn inline_ctxt(mut self) -> Result { + match_span_kind! { + &mut self, + InlineCtxt(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), + InlineParent(_span) => Ok(SyntaxContext::root()), + PartiallyInterned(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), + Interned(span) => Err(span.index as usize), } } From 6fea953267298e98ee630e595efcfe1c3a287976 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 12 Jun 2024 01:58:29 +0300 Subject: [PATCH 04/15] rustc_span: By-value interface for ctxt update --- compiler/rustc_expand/src/mbe/transcribe.rs | 2 +- compiler/rustc_span/src/lib.rs | 22 +++++++--------- compiler/rustc_span/src/span_encoding.rs | 28 ++++++++++----------- 3 files changed, 23 insertions(+), 29 deletions(-) diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 25e961d600901..5aa9242fa1661 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -30,7 +30,7 @@ impl MutVisitor for Marker { // it's some advanced case with macro-generated macros. So if we cache the marked version // of that context once, we'll typically have a 100% cache hit rate after that. let Marker(expn_id, transparency, ref mut cache) = *self; - span.update_ctxt(|ctxt| { + *span = span.map_ctxt(|ctxt| { *cache .entry(ctxt) .or_insert_with(|| ctxt.apply_mark(expn_id.to_expn_id(), transparency)) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7b4506d33cac2..b7ffe6c618af7 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -520,7 +520,7 @@ impl SpanData { pub fn with_hi(&self, hi: BytePos) -> Span { Span::new(self.lo, hi, self.ctxt, self.parent) } - /// Avoid if possible, `Span::update_ctxt` should be preferred. + /// Avoid if possible, `Span::map_ctxt` should be preferred. #[inline] fn with_ctxt(&self, ctxt: SyntaxContext) -> Span { Span::new(self.lo, self.hi, ctxt, self.parent) @@ -577,9 +577,8 @@ impl Span { self.data().with_hi(hi) } #[inline] - pub fn with_ctxt(mut self, ctxt: SyntaxContext) -> Span { - self.update_ctxt(|_| ctxt); - self + pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span { + self.map_ctxt(|_| ctxt) } #[inline] pub fn parent(self) -> Option { @@ -1060,9 +1059,8 @@ impl Span { } #[inline] - pub fn apply_mark(mut self, expn_id: ExpnId, transparency: Transparency) -> Span { - self.update_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)); - self + pub fn apply_mark(self, expn_id: ExpnId, transparency: Transparency) -> Span { + self.map_ctxt(|ctxt| ctxt.apply_mark(expn_id, transparency)) } #[inline] @@ -1110,15 +1108,13 @@ impl Span { } #[inline] - pub fn normalize_to_macros_2_0(mut self) -> Span { - self.update_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()); - self + pub fn normalize_to_macros_2_0(self) -> Span { + self.map_ctxt(|ctxt| ctxt.normalize_to_macros_2_0()) } #[inline] - pub fn normalize_to_macro_rules(mut self) -> Span { - self.update_ctxt(|ctxt| ctxt.normalize_to_macro_rules()); - self + pub fn normalize_to_macro_rules(self) -> Span { + self.map_ctxt(|ctxt| ctxt.normalize_to_macro_rules()) } } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 8227597ac6f92..69d7b4ca8c2b0 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -192,20 +192,20 @@ macro_rules! match_span_kind { if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if $span.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. - let $span1: &mut InlineCtxt = unsafe { transmute(&mut *$span) }; + let $span1: InlineCtxt = unsafe { transmute($span) }; $arm1 } else { // Inline-parent format. - let $span2: &mut InlineParent = unsafe { transmute(&mut *$span) }; + let $span2: InlineParent = unsafe { transmute($span) }; $arm2 } } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { // Partially-interned format. - let $span3: &mut PartiallyInterned = unsafe { transmute(&mut *$span) }; + let $span3: PartiallyInterned = unsafe { transmute($span) }; $arm3 } else { // Interned format. - let $span4: &mut Interned = unsafe { transmute(&mut *$span) }; + let $span4: Interned = unsafe { transmute($span) }; $arm4 } }; @@ -273,9 +273,9 @@ impl Span { /// Internal function to translate between an encoded span and the expanded representation. /// This function must not be used outside the incremental engine. #[inline] - pub fn data_untracked(mut self) -> SpanData { + pub fn data_untracked(self) -> SpanData { match_span_kind! { - &mut self, + self, InlineCtxt(span) => span.data(), InlineParent(span) => span.data(), PartiallyInterned(span) => span.data(), @@ -304,7 +304,7 @@ impl Span { // update doesn't change format. All non-inline or format changing scenarios require accessing // interner and can fall back to `Span::new`. #[inline] - pub fn update_ctxt(&mut self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) { + pub fn map_ctxt(self, update: impl FnOnce(SyntaxContext) -> SyntaxContext) -> Span { let (updated_ctxt32, data); match_span_kind! { self, @@ -313,8 +313,7 @@ impl Span { update(SyntaxContext::from_u32(span.ctxt as u32)).as_u32(); // Any small new context including zero will preserve the format. if updated_ctxt32 <= MAX_CTXT { - span.ctxt = updated_ctxt32 as u16; - return; + return InlineCtxt::span(span.lo, span.len, updated_ctxt32 as u16); } data = span.data(); }, @@ -323,7 +322,7 @@ impl Span { // Only if the new context is zero the format will be preserved. if updated_ctxt32 == 0 { // Do nothing. - return; + return self; } data = span.data(); }, @@ -332,8 +331,7 @@ impl Span { // Any small new context excluding zero will preserve the format. // Zero may change the format to `InlineParent` if parent and len are small enough. if updated_ctxt32 <= MAX_CTXT && updated_ctxt32 != 0 { - span.ctxt = updated_ctxt32 as u16; - return; + return PartiallyInterned::span(span.index, updated_ctxt32 as u16); } data = span.data(); }, @@ -344,15 +342,15 @@ impl Span { } // We could not keep the span in the same inline format, fall back to the complete logic. - *self = data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)); + data.with_ctxt(SyntaxContext::from_u32(updated_ctxt32)) } // Returns either syntactic context, if it can be retrieved without taking the interner lock, // or an index into the interner if it cannot. #[inline] - fn inline_ctxt(mut self) -> Result { + fn inline_ctxt(self) -> Result { match_span_kind! { - &mut self, + self, InlineCtxt(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), InlineParent(_span) => Ok(SyntaxContext::root()), PartiallyInterned(span) => Ok(SyntaxContext::from_u32(span.ctxt as u32)), From 220f3ec99fda594a67c549e3587e0e484ed655ba Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 13 Jun 2024 19:50:44 +0300 Subject: [PATCH 05/15] rustc_span: Remove transmutes from span encoding --- compiler/rustc_span/src/span_encoding.rs | 52 +++++++++++++++++------- 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 69d7b4ca8c2b0..9d5bc5b05125e 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -4,10 +4,10 @@ use crate::SPAN_TRACK; use crate::{BytePos, SpanData}; use rustc_data_structures::fx::FxIndexSet; + // This code is very hot and uses lots of arithmetic, avoid overflow checks for performance. // See https://github.com/rust-lang/rust/pull/119440#issuecomment-1874255727 use rustc_serialize::int_overflow::DebugStrictAdd; -use std::mem::transmute; /// A compressed span. /// @@ -105,15 +105,12 @@ struct InlineParent { #[derive(Clone, Copy)] struct PartiallyInterned { index: u32, - _marker1: u16, ctxt: u16, } #[derive(Clone, Copy)] struct Interned { index: u32, - _marker1: u16, - _marker2: u16, } impl InlineCtxt { @@ -130,7 +127,13 @@ impl InlineCtxt { } #[inline] fn span(lo: u32, len: u16, ctxt: u16) -> Span { - unsafe { transmute(InlineCtxt { lo, len, ctxt }) } + Span { lo_or_index: lo, len_with_tag_or_marker: len, ctxt_or_parent_or_marker: ctxt } + } + #[inline] + fn from_span(span: Span) -> InlineCtxt { + let (lo, len, ctxt) = + (span.lo_or_index, span.len_with_tag_or_marker, span.ctxt_or_parent_or_marker); + InlineCtxt { lo, len, ctxt } } } @@ -147,8 +150,16 @@ impl InlineParent { } } #[inline] - fn span(lo: u32, len_with_tag: u16, parent: u16) -> Span { - unsafe { transmute(InlineParent { lo, len_with_tag, parent }) } + fn span(lo: u32, len: u16, parent: u16) -> Span { + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (lo, PARENT_TAG | len, parent); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> InlineParent { + let (lo, len_with_tag, parent) = + (span.lo_or_index, span.len_with_tag_or_marker, span.ctxt_or_parent_or_marker); + InlineParent { lo, len_with_tag, parent } } } @@ -162,7 +173,13 @@ impl PartiallyInterned { } #[inline] fn span(index: u32, ctxt: u16) -> Span { - unsafe { transmute(PartiallyInterned { index, _marker1: BASE_LEN_INTERNED_MARKER, ctxt }) } + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (index, BASE_LEN_INTERNED_MARKER, ctxt); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> PartiallyInterned { + PartiallyInterned { index: span.lo_or_index, ctxt: span.ctxt_or_parent_or_marker } } } @@ -173,8 +190,13 @@ impl Interned { } #[inline] fn span(index: u32) -> Span { - let _marker1 = BASE_LEN_INTERNED_MARKER; - unsafe { transmute(Interned { index, _marker1, _marker2: CTXT_INTERNED_MARKER }) } + let (lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker) = + (index, BASE_LEN_INTERNED_MARKER, CTXT_INTERNED_MARKER); + Span { lo_or_index, len_with_tag_or_marker, ctxt_or_parent_or_marker } + } + #[inline] + fn from_span(span: Span) -> Interned { + Interned { index: span.lo_or_index } } } @@ -192,20 +214,20 @@ macro_rules! match_span_kind { if $span.len_with_tag_or_marker != BASE_LEN_INTERNED_MARKER { if $span.len_with_tag_or_marker & PARENT_TAG == 0 { // Inline-context format. - let $span1: InlineCtxt = unsafe { transmute($span) }; + let $span1 = InlineCtxt::from_span($span); $arm1 } else { // Inline-parent format. - let $span2: InlineParent = unsafe { transmute($span) }; + let $span2 = InlineParent::from_span($span); $arm2 } } else if $span.ctxt_or_parent_or_marker != CTXT_INTERNED_MARKER { // Partially-interned format. - let $span3: PartiallyInterned = unsafe { transmute($span) }; + let $span3 = PartiallyInterned::from_span($span); $arm3 } else { // Interned format. - let $span4: Interned = unsafe { transmute($span) }; + let $span4 = Interned::from_span($span); $arm4 } }; @@ -245,7 +267,7 @@ impl Span { && let parent32 = parent.local_def_index.as_u32() && parent32 <= MAX_CTXT { - return InlineParent::span(lo.0, PARENT_TAG | len as u16, parent32 as u16); + return InlineParent::span(lo.0, len as u16, parent32 as u16); } } From 7999dbbd3e62dfd1cf65e19ea1949e41935b997c Mon Sep 17 00:00:00 2001 From: DianQK Date: Fri, 14 Jun 2024 08:05:20 +0800 Subject: [PATCH 06/15] Regenerate `requirements.txt` by Python 3.9 --- src/tools/tidy/config/requirements.in | 6 ++-- src/tools/tidy/config/requirements.txt | 47 +++----------------------- 2 files changed, 8 insertions(+), 45 deletions(-) diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index 882e09dae4594..047617c65598f 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -1,10 +1,10 @@ # requirements.in This is the source file for our pinned version requirements # file "requirements.txt" To regenerate that file, pip-tools is required -# (`python -m pip install pip-tools`). Once installed, run: `pip-compile -# --generate-hashes src/tools/tidy/config/requirements.in` +# (`python -m pip install pip-tools==7.4.1`). Once installed, run: `pip-compile +# --generate-hashes --strip-extras src/tools/tidy/config/requirements.in` # # Note: this generation step should be run with the oldest supported python -# version (currently 3.7) to ensure backward compatibility +# version (currently 3.9) to ensure backward compatibility black==23.3.0 ruff==0.0.272 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index 9fd617ad62192..a53c98cac7a06 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -1,8 +1,8 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.9 # by the following command: # -# pip-compile --generate-hashes src/tools/tidy/config/requirements.in +# pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in # black==23.3.0 \ --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \ @@ -35,10 +35,6 @@ click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ --hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48 # via black -importlib-metadata==6.7.0 \ - --hash=sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4 \ - --hash=sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5 - # via click mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 @@ -78,40 +74,7 @@ tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f # via black -typed-ast==1.5.4 \ - --hash=sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2 \ - --hash=sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1 \ - --hash=sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6 \ - --hash=sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62 \ - --hash=sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac \ - --hash=sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d \ - --hash=sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc \ - --hash=sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2 \ - --hash=sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97 \ - --hash=sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35 \ - --hash=sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6 \ - --hash=sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1 \ - --hash=sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4 \ - --hash=sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c \ - --hash=sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e \ - --hash=sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec \ - --hash=sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f \ - --hash=sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72 \ - --hash=sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47 \ - --hash=sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72 \ - --hash=sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe \ - --hash=sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6 \ - --hash=sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3 \ - --hash=sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66 +typing-extensions==4.12.2 \ + --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \ + --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8 # via black -typing-extensions==4.6.3 \ - --hash=sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26 \ - --hash=sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5 - # via - # black - # importlib-metadata - # platformdirs -zipp==3.15.0 \ - --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \ - --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556 - # via importlib-metadata From ab7fc60a7389667f6e7eee952c4e1101f1746b3d Mon Sep 17 00:00:00 2001 From: DianQK Date: Fri, 14 Jun 2024 08:08:57 +0800 Subject: [PATCH 07/15] End support for Python 3.8 in tidy --- src/tools/tidy/src/ext_tool_checks.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index fb626cac3fa05..995ad58cb6219 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -24,9 +24,8 @@ use std::io; use std::path::{Path, PathBuf}; use std::process::Command; -/// Minimum python revision is 3.7 for ruff -const MIN_PY_REV: (u32, u32) = (3, 7); -const MIN_PY_REV_STR: &str = "≥3.7"; +const MIN_PY_REV: (u32, u32) = (3, 9); +const MIN_PY_REV_STR: &str = "≥3.9"; /// Path to find the python executable within a virtual environment #[cfg(target_os = "windows")] @@ -223,17 +222,8 @@ fn get_or_create_venv(venv_path: &Path, src_reqs_path: &Path) -> Result Result<(), Error> { /// Preferred python versions in order. Newest to oldest then current /// development versions - const TRY_PY: &[&str] = &[ - "python3.11", - "python3.10", - "python3.9", - "python3.8", - "python3.7", - "python3", - "python", - "python3.12", - "python3.13", - ]; + const TRY_PY: &[&str] = + &["python3.11", "python3.10", "python3.9", "python3", "python", "python3.12", "python3.13"]; let mut sys_py = None; let mut found = Vec::new(); From 04af37170cc6a608f87b48706d49be3504585f58 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Thu, 13 Jun 2024 20:42:12 +0200 Subject: [PATCH 08/15] Also sort `crt-static` in `--print target-features` output I didn't find `crt-static` at first (for `x86_64-unknown-linux-gnu`), because it was put at the bottom the large and otherwise sorted list. Fully sort the list before we print it. Note that `llvm_target_features` starts out sorted and does not need to be sorted an extra time. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 53b9b530e9bd6..7e0f264a4aedf 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -394,10 +394,15 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll (*feature, desc) }) .collect::>(); + + // Since we add this at the end ... rustc_target_features.extend_from_slice(&[( "crt-static", "Enables C Run-time Libraries to be statically linked", )]); + // ... we need to sort the list again. + rustc_target_features.sort(); + llvm_target_features.retain(|(f, _d)| !known_llvm_target_features.contains(f)); let max_feature_len = llvm_target_features From c906d2e428b9d20d1d73ec587bff75a6d25efed7 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 08:11:16 -0500 Subject: [PATCH 09/15] Enable const evaluation for `f16` and `f128` This excludes casting, which needs more tests. --- .../rustc_const_eval/src/interpret/operator.rs | 10 ++++++++-- compiler/rustc_middle/src/mir/interpret/value.rs | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a6eef9f5662ca..a6924371632b2 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -362,14 +362,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let left = left.to_scalar(); let right = right.to_scalar(); Ok(match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => { + self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?) + } FloatTy::F32 => { self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?) } FloatTy::F64 => { self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?) } - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => { + self.binary_float_op(bin_op, layout, left.to_f128()?, right.to_f128()?) + } }) } _ if left.layout.ty.is_integral() => { @@ -431,8 +435,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let val = val.to_scalar(); // No NaN adjustment here, `-` is a bitwise operation! let res = match (un_op, fty) { + (Neg, FloatTy::F16) => Scalar::from_f16(-val.to_f16()?), (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), + (Neg, FloatTy::F128) => Scalar::from_f128(-val.to_f128()?), _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), }; Ok(ImmTy::from_scalar(res, layout)) diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 70e5ad0635ba1..a84a4c583edd2 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -69,6 +69,13 @@ impl fmt::LowerHex for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Half) -> Self { + Scalar::from_f16(f) + } +} + impl From for Scalar { #[inline(always)] fn from(f: Single) -> Self { @@ -83,6 +90,13 @@ impl From for Scalar { } } +impl From for Scalar { + #[inline(always)] + fn from(f: Quad) -> Self { + Scalar::from_f128(f) + } +} + impl From for Scalar { #[inline(always)] fn from(ptr: ScalarInt) -> Self { From eab5e8e9d95439adb4b63cd631dd24dae90cd9ad Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 08:29:38 -0500 Subject: [PATCH 10/15] Make the unary operator `FloatTy` check exhaustive Add a spot that was missed in . --- .../rustc_const_eval/src/interpret/operator.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index a6924371632b2..2175f051a1910 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -433,13 +433,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } ty::Float(fty) => { let val = val.to_scalar(); + if un_op != Neg { + span_bug!(self.cur_span(), "Invalid float op {:?}", un_op); + } + // No NaN adjustment here, `-` is a bitwise operation! - let res = match (un_op, fty) { - (Neg, FloatTy::F16) => Scalar::from_f16(-val.to_f16()?), - (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), - (Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?), - (Neg, FloatTy::F128) => Scalar::from_f128(-val.to_f128()?), - _ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op), + let res = match fty { + FloatTy::F16 => Scalar::from_f16(-val.to_f16()?), + FloatTy::F32 => Scalar::from_f32(-val.to_f32()?), + FloatTy::F64 => Scalar::from_f64(-val.to_f64()?), + FloatTy::F128 => Scalar::from_f128(-val.to_f128()?), }; Ok(ImmTy::from_scalar(res, layout)) } From 5cb58ad50327774ab8b4705e4249e20785445840 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 13 Jun 2024 13:04:16 -0500 Subject: [PATCH 11/15] Add `f16` and `f128` support to Miri --- src/tools/miri/src/helpers.rs | 8 +- src/tools/miri/tests/pass/float.rs | 149 ++++++++++------------------- 2 files changed, 56 insertions(+), 101 deletions(-) diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 87b53d87ac87e..843aff024958a 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -7,7 +7,7 @@ use std::time::Duration; use rand::RngCore; -use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_apfloat::Float; use rustc_hir::{ def::{DefKind, Namespace}, @@ -1201,12 +1201,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let (val, status) = match fty { - FloatTy::F16 => unimplemented!("f16_f128"), + FloatTy::F16 => + float_to_int_inner::(this, src.to_scalar().to_f16()?, cast_to, round), FloatTy::F32 => float_to_int_inner::(this, src.to_scalar().to_f32()?, cast_to, round), FloatTy::F64 => float_to_int_inner::(this, src.to_scalar().to_f64()?, cast_to, round), - FloatTy::F128 => unimplemented!("f16_f128"), + FloatTy::F128 => + float_to_int_inner::(this, src.to_scalar().to_f128()?, cast_to, round), }; if status.intersects( diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs index 8aea9b3e6f9f1..5464627fa1446 100644 --- a/src/tools/miri/tests/pass/float.rs +++ b/src/tools/miri/tests/pass/float.rs @@ -1,6 +1,8 @@ #![feature(stmt_expr_attributes)] #![feature(float_gamma)] #![feature(core_intrinsics)] +#![feature(f128)] +#![feature(f16)] #![allow(arithmetic_overflow)] use std::fmt::Debug; @@ -41,103 +43,23 @@ trait FloatToInt: Copy { unsafe fn cast_unchecked(self) -> Int; } -impl FloatToInt for f32 { - fn cast(self) -> i8 { - self as _ - } - unsafe fn cast_unchecked(self) -> i8 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> i32 { - self as _ - } - unsafe fn cast_unchecked(self) -> i32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> u32 { - self as _ - } - unsafe fn cast_unchecked(self) -> u32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> i64 { - self as _ - } - unsafe fn cast_unchecked(self) -> i64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f32 { - fn cast(self) -> u64 { - self as _ - } - unsafe fn cast_unchecked(self) -> u64 { - self.to_int_unchecked() - } +macro_rules! float_to_int { + ($fty:ty => $($ity:ty),+ $(,)?) => { + $( + impl FloatToInt<$ity> for $fty { + fn cast(self) -> $ity { + self as _ + } + unsafe fn cast_unchecked(self) -> $ity { + self.to_int_unchecked() + } + } + )* + }; } -impl FloatToInt for f64 { - fn cast(self) -> i8 { - self as _ - } - unsafe fn cast_unchecked(self) -> i8 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i32 { - self as _ - } - unsafe fn cast_unchecked(self) -> i32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u32 { - self as _ - } - unsafe fn cast_unchecked(self) -> u32 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i64 { - self as _ - } - unsafe fn cast_unchecked(self) -> i64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u64 { - self as _ - } - unsafe fn cast_unchecked(self) -> u64 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> i128 { - self as _ - } - unsafe fn cast_unchecked(self) -> i128 { - self.to_int_unchecked() - } -} -impl FloatToInt for f64 { - fn cast(self) -> u128 { - self as _ - } - unsafe fn cast_unchecked(self) -> u128 { - self.to_int_unchecked() - } -} +float_to_int!(f32 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); +float_to_int!(f64 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] @@ -153,18 +75,29 @@ where fn basic() { // basic arithmetic + assert_eq(6.0_f16 * 6.0_f16, 36.0_f16); assert_eq(6.0_f32 * 6.0_f32, 36.0_f32); assert_eq(6.0_f64 * 6.0_f64, 36.0_f64); + assert_eq(6.0_f128 * 6.0_f128, 36.0_f128); + assert_eq(-{ 5.0_f16 }, -5.0_f16); assert_eq(-{ 5.0_f32 }, -5.0_f32); assert_eq(-{ 5.0_f64 }, -5.0_f64); + assert_eq(-{ 5.0_f128 }, -5.0_f128); + // infinities, NaN + // FIXME(f16_f128): add when constants and `is_infinite` are available assert!((5.0_f32 / 0.0).is_infinite()); assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); assert!((5.0_f64 / 0.0).is_infinite()); assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); assert_ne!(f32::NAN, f32::NAN); assert_ne!(f64::NAN, f64::NAN); + // negative zero + let posz = 0.0f16; + let negz = -0.0f16; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); let posz = 0.0f32; let negz = -0.0f32; assert_eq(posz, negz); @@ -173,15 +106,30 @@ fn basic() { let negz = -0.0f64; assert_eq(posz, negz); assert_ne!(posz.to_bits(), negz.to_bits()); + let posz = 0.0f128; + let negz = -0.0f128; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); + // byte-level transmute - let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; - let y: f64 = unsafe { std::mem::transmute(x) }; - assert_eq(y, 42.0_f64); + let x: u16 = unsafe { std::mem::transmute(42.0_f16) }; + let y: f16 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f16); let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); + let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; + let y: f64 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f64); + let x: u128 = unsafe { std::mem::transmute(42.0_f128) }; + let y: f128 = unsafe { std::mem::transmute(x) }; + assert_eq(y, 42.0_f128); // `%` sign behavior, some of this used to be buggy + assert!((black_box(1.0f16) % 1.0).is_sign_positive()); + assert!((black_box(1.0f16) % -1.0).is_sign_positive()); + assert!((black_box(-1.0f16) % 1.0).is_sign_negative()); + assert!((black_box(-1.0f16) % -1.0).is_sign_negative()); assert!((black_box(1.0f32) % 1.0).is_sign_positive()); assert!((black_box(1.0f32) % -1.0).is_sign_positive()); assert!((black_box(-1.0f32) % 1.0).is_sign_negative()); @@ -190,7 +138,12 @@ fn basic() { assert!((black_box(1.0f64) % -1.0).is_sign_positive()); assert!((black_box(-1.0f64) % 1.0).is_sign_negative()); assert!((black_box(-1.0f64) % -1.0).is_sign_negative()); + assert!((black_box(1.0f128) % 1.0).is_sign_positive()); + assert!((black_box(1.0f128) % -1.0).is_sign_positive()); + assert!((black_box(-1.0f128) % 1.0).is_sign_negative()); + assert!((black_box(-1.0f128) % -1.0).is_sign_negative()); + // FIXME(f16_f128): add when `abs` is available assert_eq!((-1.0f32).abs(), 1.0f32); assert_eq!(34.2f64.abs(), 34.2f64); } From e649042316ec3f832cfe120d04068b6e3e6c1791 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Fri, 14 Jun 2024 12:41:07 -0500 Subject: [PATCH 12/15] Remove f16 const eval crash test Const eval negation was added. This test is now covered by Miri tests, and merged into an existing UI test. Fixes --- tests/crashes/124583.rs | 5 ----- tests/ui/numbers-arithmetic/f16-f128-lit.rs | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 tests/crashes/124583.rs diff --git a/tests/crashes/124583.rs b/tests/crashes/124583.rs deleted file mode 100644 index ffd9d7521add2..0000000000000 --- a/tests/crashes/124583.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: rust-lang/rust#124583 - -fn main() { - let _ = -(-0.0f16); -} diff --git a/tests/ui/numbers-arithmetic/f16-f128-lit.rs b/tests/ui/numbers-arithmetic/f16-f128-lit.rs index 762436edb1663..7fd20d91d8248 100644 --- a/tests/ui/numbers-arithmetic/f16-f128-lit.rs +++ b/tests/ui/numbers-arithmetic/f16-f128-lit.rs @@ -1,3 +1,5 @@ +// Make sure negation happens correctly. Also included: +// issue: rust-lang/rust#124583 //@ run-pass #![feature(f16)] @@ -8,9 +10,11 @@ fn main() { assert_eq!((-0.0_f16).to_bits(), 0x8000); assert_eq!(10.0_f16.to_bits(), 0x4900); assert_eq!((-10.0_f16).to_bits(), 0xC900); + assert_eq!((-(-0.0f16)).to_bits(), 0x0000); assert_eq!(0.0_f128.to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000); assert_eq!((-0.0_f128).to_bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000); assert_eq!(10.0_f128.to_bits(), 0x4002_4000_0000_0000_0000_0000_0000_0000); assert_eq!((-10.0_f128).to_bits(), 0xC002_4000_0000_0000_0000_0000_0000_0000); + assert_eq!((-(-0.0f128)).to_bits(), 0x0000_0000_0000_0000_0000_0000_0000_0000); } From 78d4802448307369d81c953c290f5043c004a8fe Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Fri, 14 Jun 2024 18:42:02 +0000 Subject: [PATCH 13/15] Use `std::path::absolute` in bootstrap --- src/bootstrap/src/core/config/config.rs | 4 +- src/bootstrap/src/utils/helpers.rs | 109 ----------------------- src/bootstrap/src/utils/helpers/tests.rs | 21 ----- 3 files changed, 2 insertions(+), 132 deletions(-) diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 36b44d0169c9c..6024896b065bc 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -10,7 +10,7 @@ use std::env; use std::fmt::{self, Display}; use std::fs; use std::io::IsTerminal; -use std::path::{Path, PathBuf}; +use std::path::{absolute, Path, PathBuf}; use std::process::Command; use std::str::FromStr; use std::sync::OnceLock; @@ -1437,7 +1437,7 @@ impl Config { // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. if !config.out.is_absolute() { // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - config.out = crate::utils::helpers::absolute(&config.out); + config.out = absolute(&config.out).expect("can't make empty path absolute"); } config.initial_rustc = if let Some(rustc) = rustc { diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 278359cb08e39..1df3432353581 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -331,115 +331,6 @@ fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { }) } -/// Copied from `std::path::absolute` until it stabilizes. -/// -/// FIXME: this shouldn't exist. -pub(crate) fn absolute(path: &Path) -> PathBuf { - if path.as_os_str().is_empty() { - panic!("can't make empty path absolute"); - } - #[cfg(unix)] - { - t!(absolute_unix(path), format!("could not make path absolute: {}", path.display())) - } - #[cfg(windows)] - { - t!(absolute_windows(path), format!("could not make path absolute: {}", path.display())) - } - #[cfg(not(any(unix, windows)))] - { - println!("WARNING: bootstrap is not supported on non-unix platforms"); - t!(std::fs::canonicalize(t!(std::env::current_dir()))).join(path) - } -} - -#[cfg(unix)] -/// Make a POSIX path absolute without changing its semantics. -fn absolute_unix(path: &Path) -> io::Result { - // This is mostly a wrapper around collecting `Path::components`, with - // exceptions made where this conflicts with the POSIX specification. - // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017 - // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13 - - use std::os::unix::prelude::OsStrExt; - let mut components = path.components(); - let path_os = path.as_os_str().as_bytes(); - - let mut normalized = if path.is_absolute() { - // "If a pathname begins with two successive characters, the - // first component following the leading characters may be - // interpreted in an implementation-defined manner, although more than - // two leading characters shall be treated as a single - // character." - if path_os.starts_with(b"//") && !path_os.starts_with(b"///") { - components.next(); - PathBuf::from("//") - } else { - PathBuf::new() - } - } else { - env::current_dir()? - }; - normalized.extend(components); - - // "Interfaces using pathname resolution may specify additional constraints - // when a pathname that does not name an existing directory contains at - // least one non- character and contains one or more trailing - // characters". - // A trailing is also meaningful if "a symbolic link is - // encountered during pathname resolution". - - if path_os.ends_with(b"/") { - normalized.push(""); - } - - Ok(normalized) -} - -#[cfg(windows)] -fn absolute_windows(path: &std::path::Path) -> std::io::Result { - use std::ffi::OsString; - use std::io::Error; - use std::os::windows::ffi::{OsStrExt, OsStringExt}; - use std::ptr::null_mut; - #[link(name = "kernel32")] - extern "system" { - fn GetFullPathNameW( - lpFileName: *const u16, - nBufferLength: u32, - lpBuffer: *mut u16, - lpFilePart: *mut *const u16, - ) -> u32; - } - - unsafe { - // encode the path as UTF-16 - let path: Vec = path.as_os_str().encode_wide().chain([0]).collect(); - let mut buffer = Vec::new(); - // Loop until either success or failure. - loop { - // Try to get the absolute path - let len = GetFullPathNameW( - path.as_ptr(), - buffer.len().try_into().unwrap(), - buffer.as_mut_ptr(), - null_mut(), - ); - match len as usize { - // Failure - 0 => return Err(Error::last_os_error()), - // Buffer is too small, resize. - len if len > buffer.len() => buffer.resize(len, 0), - // Success! - len => { - buffer.truncate(len); - return Ok(OsString::from_wide(&buffer).into()); - } - } - } - } -} - /// Adapted from /// /// When `clang-cl` is used with instrumentation, we need to add clang's runtime library resource diff --git a/src/bootstrap/src/utils/helpers/tests.rs b/src/bootstrap/src/utils/helpers/tests.rs index 9cfaa3eb67b5c..2ab3952ae5a1d 100644 --- a/src/bootstrap/src/utils/helpers/tests.rs +++ b/src/bootstrap/src/utils/helpers/tests.rs @@ -25,27 +25,6 @@ fn test_make() { } } -#[cfg(unix)] -#[test] -fn test_absolute_unix() { - use crate::utils::helpers::absolute_unix; - - // Test an absolute path - let path = PathBuf::from("/home/user/file.txt"); - assert_eq!(absolute_unix(&path).unwrap(), PathBuf::from("/home/user/file.txt")); - - // Test an absolute path with double leading slashes - let path = PathBuf::from("//root//file.txt"); - assert_eq!(absolute_unix(&path).unwrap(), PathBuf::from("//root/file.txt")); - - // Test a relative path - let path = PathBuf::from("relative/path"); - assert_eq!( - absolute_unix(&path).unwrap(), - std::env::current_dir().unwrap().join("relative/path") - ); -} - #[test] fn test_beta_rev_parsing() { // single digit revision From 416888f05b996f74eb696ed46c4eb3359a616f72 Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Thu, 13 Jun 2024 11:59:22 -0700 Subject: [PATCH 14/15] Polish `std::path::absolute` documentation. These changes bring it closer to other standard library documentation and, in particular, `std::fs::canonicalize`, which it will often be compared with. * Add `# Platform-specific behavior` section, with content moved from Examples section. * Create `# Errors` section. * Phrase error description to allow future platforms to have new syntactic errors, rather than only emptiness. * Add missing commas. * Indent example code 4 spaces. --- library/std/src/fs.rs | 2 +- library/std/src/path.rs | 65 ++++++++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 0dcf554770c5c..2132097fde459 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2302,7 +2302,7 @@ pub fn read_link>(path: P) -> io::Result { /// /// This function currently corresponds to the `realpath` function on Unix /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. -/// Note that, this [may change in the future][changes]. +/// Note that this [may change in the future][changes]. /// /// On Windows, this converts the path to use [extended length path][path] /// syntax, which allows your program to use longer path names, but means you diff --git a/library/std/src/path.rs b/library/std/src/path.rs index adbcdcd2e67e3..7b8caaa268473 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3345,14 +3345,33 @@ impl Error for StripPrefixError { /// Makes the path absolute without accessing the filesystem. /// /// If the path is relative, the current directory is used as the base directory. -/// All intermediate components will be resolved according to platforms-specific -/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not +/// All intermediate components will be resolved according to platform-specific +/// rules, but unlike [`canonicalize`][crate::fs::canonicalize], this does not /// resolve symlinks and may succeed even if the path does not exist. /// /// If the `path` is empty or getting the -/// [current directory][crate::env::current_dir] fails then an error will be +/// [current directory][crate::env::current_dir] fails, then an error will be /// returned. /// +/// # Platform-specific behavior +/// +/// On POSIX platforms, the path is resolved using [POSIX semantics][posix-semantics], +/// except that it stops short of resolving symlinks. This means it will keep `..` +/// components and trailing slashes. +/// +/// On Windows, for verbatim paths, this will simply return the path as given. For other +/// paths, this is currently equivalent to calling +/// [`GetFullPathNameW`][windows-path]. +/// +/// Note that these [may change in the future][changes]. +/// +/// # Errors +/// +/// This function may return an error in the following situations: +/// +/// * If `path` is syntactically invalid; in particular, if it is empty. +/// * If getting the [current directory][crate::env::current_dir] fails. +/// /// # Examples /// /// ## POSIX paths @@ -3360,50 +3379,42 @@ impl Error for StripPrefixError { /// ``` /// # #[cfg(unix)] /// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; +/// use std::path::{self, Path}; /// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with("foo/bar")); +/// // Relative to absolute +/// let absolute = path::absolute("foo/./bar")?; +/// assert!(absolute.ends_with("foo/bar")); /// -/// // Absolute to absolute -/// let absolute = path::absolute("/foo//test/.././bar.rs")?; -/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); -/// Ok(()) +/// // Absolute to absolute +/// let absolute = path::absolute("/foo//test/.././bar.rs")?; +/// assert_eq!(absolute, Path::new("/foo/test/../bar.rs")); +/// Ok(()) /// } /// # #[cfg(not(unix))] /// # fn main() {} /// ``` /// -/// The path is resolved using [POSIX semantics][posix-semantics] except that -/// it stops short of resolving symlinks. This means it will keep `..` -/// components and trailing slashes. -/// /// ## Windows paths /// /// ``` /// # #[cfg(windows)] /// fn main() -> std::io::Result<()> { -/// use std::path::{self, Path}; +/// use std::path::{self, Path}; /// -/// // Relative to absolute -/// let absolute = path::absolute("foo/./bar")?; -/// assert!(absolute.ends_with(r"foo\bar")); +/// // Relative to absolute +/// let absolute = path::absolute("foo/./bar")?; +/// assert!(absolute.ends_with(r"foo\bar")); /// -/// // Absolute to absolute -/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; +/// // Absolute to absolute +/// let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?; /// -/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); -/// Ok(()) +/// assert_eq!(absolute, Path::new(r"C:\foo\bar.rs")); +/// Ok(()) /// } /// # #[cfg(not(windows))] /// # fn main() {} /// ``` /// -/// For verbatim paths this will simply return the path as given. For other -/// paths this is currently equivalent to calling -/// [`GetFullPathNameW`][windows-path]. -/// /// Note that this [may change in the future][changes]. /// /// [changes]: io#platform-specific-behavior From 297c97dbe087a9308eba2348fc86cad10f032ea6 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 15 Jun 2024 09:26:56 +0200 Subject: [PATCH 15/15] .mailmap: Associate both my work and my private email with me --- .mailmap | 1 + 1 file changed, 1 insertion(+) diff --git a/.mailmap b/.mailmap index 0bd16a797ca73..33673244be6d0 100644 --- a/.mailmap +++ b/.mailmap @@ -379,6 +379,7 @@ Markus Westerlind Markus Martin Carton Martin Habovštiak Martin Hafskjold Thoresen +Martin Nordholts Matej Lach Matej Ľach Mateusz Mikuła Mateusz Mikuła