diff --git a/Cargo.lock b/Cargo.lock index 8938c49449711..d742b67ffaf1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3770,7 +3770,6 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_fs_util", - "rustc_hashes", "rustc_hir", "rustc_index", "rustc_llvm", diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index dd0064d34bc4a..fd68b86e6c24d 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,11 +1,8 @@ use gccjit::{LValue, RValue, ToRValue, Type}; -use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, HasDataLayout}; -use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, -}; -use rustc_middle::mir::Mutability; -use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; +use rustc_abi as abi; +use rustc_abi::HasDataLayout; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods}; +use rustc_middle::mir::interpret::ConstAllocation; use rustc_middle::ty::layout::LayoutOf; use crate::consts::const_alloc_to_gcc; @@ -114,7 +111,7 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { typ.get_pointee().is_some() } -impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } @@ -229,99 +226,67 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { None } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> { - let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; - match cv { - Scalar::Int(int) => { - let data = int.to_bits(layout.size(self)); - let value = self.const_uint_big(self.type_ix(bitsize), data); - let bytesize = layout.size(self).bytes(); - if bitsize > 1 && ty.is_integral() && bytesize as u32 == ty.get_size() { - // NOTE: since the intrinsic _xabort is called with a bitcast, which - // is non-const, but expects a constant, do a normal cast instead of a bitcast. - // FIXME(antoyo): fix bitcast to work in constant contexts. - // FIXME(antoyo): perhaps only use bitcast for pointers? - self.context.new_cast(None, value, ty) - } else { - // FIXME(bjorn3): assert size is correct - self.const_bitcast(value, ty) - } - } - Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.prov_and_relative_offset(); - let alloc_id = prov.alloc_id(); - let base_addr = match self.tcx.global_alloc(alloc_id) { - GlobalAlloc::Memory(alloc) => { - // For ZSTs directly codegen an aligned pointer. - // This avoids generating a zero-sized constant value and actually needing a - // real address at runtime. - if alloc.inner().len() == 0 { - let val = alloc.inner().align.bytes().wrapping_add(offset.bytes()); - let val = self.const_usize(self.tcx.truncate_to_target_usize(val)); - return if matches!(layout.primitive(), Pointer(_)) { - self.context.new_cast(None, val, ty) - } else { - self.const_bitcast(val, ty) - }; - } - - let value = match alloc.inner().mutability { - Mutability::Mut => self.static_addr_of_mut( - const_alloc_to_gcc(self, alloc), - alloc.inner().align, - None, - ), - _ => self.static_addr_of(alloc, None), - }; - if !self.sess().fewer_names() { - // FIXME(antoyo): set value name. - } - value - } - GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), - GlobalAlloc::VTable(ty, dyn_ty) => { - let alloc = self - .tcx - .global_alloc(self.tcx.vtable_allocation(( - ty, - dyn_ty.principal().map(|principal| { - self.tcx.instantiate_bound_regions_with_erased(principal) - }), - ))) - .unwrap_memory(); - self.static_addr_of(alloc, None) - } - GlobalAlloc::TypeId { .. } => { - let val = self.const_usize(offset.bytes()); - // This is still a variable of pointer type, even though we only use the provenance - // of that pointer in CTFE and Miri. But to make LLVM's type system happy, - // we need an int-to-ptr cast here (it doesn't matter at all which provenance that picks). - return self.context.new_cast(None, val, ty); - } - GlobalAlloc::Static(def_id) => { - assert!(self.tcx.is_static(def_id)); - self.get_static(def_id).get_address(None) - } - }; - let ptr_type = base_addr.get_type(); - let base_addr = self.context.new_cast(None, base_addr, self.usize_type); - let offset = - self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64); - let ptr = self.context.new_cast(None, base_addr + offset, ptr_type); - if !matches!(layout.primitive(), Pointer(_)) { - self.const_bitcast(ptr.dereference(None).to_rvalue(), ty) - } else { - self.context.new_cast(None, ptr, ty) - } - } - } - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { self.context .new_array_access(None, base_addr, self.const_usize(offset.bytes())) .get_address(None) } + fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + self.const_bitcast(val, ty) + } + fn const_pointercast(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + self.context.new_cast(None, val, ty) + } + fn const_int_to_ptr(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + self.context.new_cast(None, val, ty) + } + fn const_ptr_to_int(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + self.context.new_cast(None, val, ty) + } + + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> RValue<'gcc> { + let cv = const_alloc_to_gcc(self, alloc); + let align = alloc.inner().align; + + if alloc.inner().mutability.is_not() + && let Some(variable) = self.const_globals.borrow().get(&cv) + { + if let Some(global_variable) = self.global_lvalues.borrow().get(variable) { + let alignment = align.bits() as i32; + if alignment > global_variable.get_alignment() { + global_variable.set_alignment(alignment); + } + } + return *variable; + } + let global_value = match kind { + Some(kind) if !self.tcx.sess.fewer_names() => { + let name = self.generate_local_symbol_name(kind); + // FIXME(antoyo): check if it's okay that no link_section is set. + + let typ = self.val_ty(cv).get_aligned(align.bytes()); + self.declare_private_global(&name[..], typ) + } + _ => { + let typ = self.val_ty(cv).get_aligned(align.bytes()); + self.declare_unnamed_global(typ) + } + }; + global_value.global_set_initializer_rvalue(cv); + // FIXME(antoyo): set unnamed address. + let rvalue = global_value.get_address(None); + self.global_lvalues.borrow_mut().insert(rvalue, global_value); + if alloc.inner().mutability.is_not() { + #[cfg(feature = "master")] + self.global_lvalues + .borrow() + .get(&rvalue) + .expect("`static_addr_of_mut` did not add the global to `self.global_lvalues`") + .global_set_readonly(); + self.const_globals.borrow_mut().insert(cv, rvalue); + } + rvalue + } } pub trait SignType<'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 42ff930968501..c705bc30ecf83 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -56,30 +56,6 @@ fn set_global_alignment<'gcc, 'tcx>( } impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { - fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> RValue<'gcc> { - let cv = const_alloc_to_gcc(self, alloc); - let align = alloc.inner().align; - - if let Some(variable) = self.const_globals.borrow().get(&cv) { - if let Some(global_variable) = self.global_lvalues.borrow().get(variable) { - let alignment = align.bits() as i32; - if alignment > global_variable.get_alignment() { - global_variable.set_alignment(alignment); - } - } - return *variable; - } - let global_value = self.static_addr_of_mut(cv, align, kind); - #[cfg(feature = "master")] - self.global_lvalues - .borrow() - .get(&global_value) - .expect("`static_addr_of_mut` did not add the global to `self.global_lvalues`") - .global_set_readonly(); - self.const_globals.borrow_mut().insert(cv, global_value); - global_value - } - fn codegen_static(&mut self, def_id: DefId) { let attrs = self.tcx.codegen_fn_attrs(def_id); @@ -175,6 +151,13 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { self.add_used_global(global.to_rvalue()); } } + + fn set_value_name(&self, _val: Self::Value, _gen_name: impl FnOnce() -> String) { + // FIXME(antoyo) + } + fn get_static(&self, def_id: DefId) -> Self::Value { + self.get_static(def_id).get_address(None) + } } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -189,32 +172,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { function.add_attribute(FnAttribute::Used); } - pub fn static_addr_of_mut( - &self, - cv: RValue<'gcc>, - align: Align, - kind: Option<&str>, - ) -> RValue<'gcc> { - let global = match kind { - Some(kind) if !self.tcx.sess.fewer_names() => { - let name = self.generate_local_symbol_name(kind); - // FIXME(antoyo): check if it's okay that no link_section is set. - - let typ = self.val_ty(cv).get_aligned(align.bytes()); - self.declare_private_global(&name[..], typ) - } - _ => { - let typ = self.val_ty(cv).get_aligned(align.bytes()); - self.declare_unnamed_global(typ) - } - }; - global.global_set_initializer_rvalue(cv); - // FIXME(antoyo): set unnamed address. - let rvalue = global.get_address(None); - self.global_lvalues.borrow_mut().insert(rvalue, global); - rvalue - } - pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> { let instance = Instance::mono(self.tcx, def_id); let DefKind::Static { nested, .. } = self.tcx.def_kind(def_id) else { bug!() }; diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 5252f93a92ebe..5c54004ace1d9 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -17,22 +17,6 @@ use crate::context::{CodegenCx, new_array_type}; use crate::type_of::LayoutGccExt; impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { - pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> { - // gcc only supports 1, 2, 4 or 8-byte integers. - // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa - // sometimes use 96-bit numbers and the following code will give an integer of a different - // size. - let bytes = (num_bits / 8).next_power_of_two() as i32; - match bytes { - 1 => self.i8_type, - 2 => self.i16_type, - 4 => self.i32_type, - 8 => self.i64_type, - 16 => self.i128_type, - _ => panic!("unexpected num_bits: {}", num_bits), - } - } - pub fn type_void(&self) -> Type<'gcc> { self.context.new_type::<()>() } @@ -148,6 +132,22 @@ impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> { self.isize_type } + fn type_ix(&self, num_bits: u64) -> Type<'gcc> { + // gcc only supports 1, 2, 4 or 8-byte integers. + // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa + // sometimes use 96-bit numbers and the following code will give an integer of a different + // size. + let bytes = (num_bits / 8).next_power_of_two() as i32; + match bytes { + 1 => self.i8_type, + 2 => self.i16_type, + 4 => self.i32_type, + 8 => self.i64_type, + 16 => self.i128_type, + _ => panic!("unexpected num_bits: {}", num_bits), + } + } + fn type_f16(&self) -> Type<'gcc> { #[cfg(feature = "master")] if self.supports_f16_type { diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 0ffff2d331b1d..acd4d324ffa96 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -24,7 +24,6 @@ rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fs_util = { path = "../rustc_fs_util" } -rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_llvm = { path = "../rustc_llvm" } diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 5c5e9ed7e082c..5bdb8bf59b58e 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -3,16 +3,13 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; -use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, HasDataLayout as _}; -use rustc_ast::Mutability; +use rustc_abi as abi; +use rustc_abi::HasDataLayout; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::stable_hash::{StableHash, StableHasher}; -use rustc_hashes::Hash128; use rustc_hir::def_id::DefId; use rustc_middle::bug; -use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; +use rustc_middle::mir::interpret::ConstAllocation; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::DllImport; use tracing::debug; @@ -130,7 +127,7 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { } } -impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn const_null(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMConstNull(t) } } @@ -268,101 +265,6 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { }) } - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) -> &'ll Value { - let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; - match cv { - Scalar::Int(int) => { - let data = int.to_bits(layout.size(self)); - let llval = self.const_uint_big(self.type_ix(bitsize), data); - if matches!(layout.primitive(), Pointer(_)) { - unsafe { llvm::LLVMConstIntToPtr(llval, llty) } - } else { - self.const_bitcast(llval, llty) - } - } - Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.prov_and_relative_offset(); - let global_alloc = self.tcx.global_alloc(prov.alloc_id()); - let base_addr = match global_alloc { - GlobalAlloc::Memory(alloc) => { - // For ZSTs directly codegen an aligned pointer. - // This avoids generating a zero-sized constant value and actually needing a - // real address at runtime. - if alloc.inner().len() == 0 { - let val = alloc.inner().align.bytes().wrapping_add(offset.bytes()); - let llval = self.const_usize(self.tcx.truncate_to_target_usize(val)); - return if matches!(layout.primitive(), Pointer(_)) { - unsafe { llvm::LLVMConstIntToPtr(llval, llty) } - } else { - self.const_bitcast(llval, llty) - }; - } else { - let init = - const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); - let alloc = alloc.inner(); - let value = match alloc.mutability { - Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of_impl(init, alloc.align, None), - }; - if !self.sess().fewer_names() && llvm::get_value_name(value).is_empty() - { - let hash = self.tcx.with_stable_hashing_context(|mut hcx| { - let mut hasher = StableHasher::new(); - alloc.stable_hash(&mut hcx, &mut hasher); - hasher.finish::() - }); - llvm::set_value_name( - value, - format!("alloc_{hash:032x}").as_bytes(), - ); - } - value - } - } - GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), - GlobalAlloc::VTable(ty, dyn_ty) => { - let alloc = self - .tcx - .global_alloc(self.tcx.vtable_allocation(( - ty, - dyn_ty.principal().map(|principal| { - self.tcx.instantiate_bound_regions_with_erased(principal) - }), - ))) - .unwrap_memory(); - let init = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); - self.static_addr_of_impl(init, alloc.inner().align, None) - } - GlobalAlloc::Static(def_id) => { - assert!(self.tcx.is_static(def_id)); - assert!(!self.tcx.is_thread_local_static(def_id)); - self.get_static(def_id) - } - GlobalAlloc::TypeId { .. } => { - // Drop the provenance, the offset contains the bytes of the hash - let llval = self.const_usize(offset.bytes()); - return unsafe { llvm::LLVMConstIntToPtr(llval, llty) }; - } - }; - let base_addr_space = global_alloc.address_space(self); - let llval = unsafe { - llvm::LLVMConstInBoundsGEP2( - self.type_i8(), - // Cast to the required address space if necessary - self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)), - &self.const_usize(offset.bytes()), - 1, - ) - }; - if !matches!(layout.primitive(), Pointer(_)) { - unsafe { llvm::LLVMConstPtrToInt(llval, llty) } - } else { - self.const_bitcast(llval, llty) - } - } - } - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { unsafe { llvm::LLVMConstInBoundsGEP2( @@ -373,6 +275,24 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { ) } } + + fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + unsafe { llvm::LLVMConstBitCast(val, ty) } + } + fn const_pointercast(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + unsafe { llvm::LLVMConstPointerCast(val, ty) } + } + fn const_int_to_ptr(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + unsafe { llvm::LLVMConstIntToPtr(val, ty) } + } + fn const_ptr_to_int(&self, val: Self::Value, ty: Self::Type) -> Self::Value { + unsafe { llvm::LLVMConstPtrToInt(val, ty) } + } + + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value { + let cv = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); + self.static_addr_of(cv, alloc.inner().align, kind, alloc.inner().mutability) + } } /// Get the [LLVM type][Type] of a [`Value`]. diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 3514fb145612a..e745a11ffaea8 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -1,6 +1,7 @@ use std::ops::Range; use rustc_abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange}; +use rustc_ast::Mutability; use rustc_codegen_ssa::common; use rustc_codegen_ssa::traits::*; use rustc_hir::LangItem; @@ -221,24 +222,30 @@ fn check_and_apply_linkage<'ll, 'tcx>( } impl<'ll> CodegenCx<'ll, '_> { - pub(crate) fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { - unsafe { llvm::LLVMConstBitCast(val, ty) } - } - - pub(crate) fn const_pointercast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { - unsafe { llvm::LLVMConstPointerCast(val, ty) } - } - /// Create a global variable. /// /// The returned global variable is a pointer in the default address space for globals. /// Fails if a symbol with the given name already exists. - pub(crate) fn static_addr_of_mut( + pub(crate) fn static_addr_of( &self, cv: &'ll Value, align: Align, kind: Option<&str>, + mutability: Mutability, ) -> &'ll Value { + if let Mutability::Not = mutability + && let Some(&gv) = self.const_globals.borrow().get(&cv) + { + unsafe { + // Upgrade the alignment in cases where the same constant is used with different + // alignment requirements + let llalign = align.bytes() as u32; + if llalign > llvm::LLVMGetAlignment(gv) { + llvm::LLVMSetAlignment(gv, llalign); + } + } + return gv; + } let gv = match kind { Some(kind) if !self.tcx.sess.fewer_names() => { let name = self.generate_local_symbol_name(kind); @@ -255,33 +262,11 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_initializer(gv, cv); set_global_alignment(self, gv, align); llvm::set_unnamed_address(gv, llvm::UnnamedAddr::Global); - gv - } + if let Mutability::Not = mutability { + llvm::set_global_constant(gv, true); - /// Create a global constant. - /// - /// The returned global variable is a pointer in the default address space for globals. - pub(crate) fn static_addr_of_impl( - &self, - cv: &'ll Value, - align: Align, - kind: Option<&str>, - ) -> &'ll Value { - if let Some(&gv) = self.const_globals.borrow().get(&cv) { - unsafe { - // Upgrade the alignment in cases where the same constant is used with different - // alignment requirements - let llalign = align.bytes() as u32; - if llalign > llvm::LLVMGetAlignment(gv) { - llvm::LLVMSetAlignment(gv, llalign); - } - } - return gv; + self.const_globals.borrow_mut().insert(cv, gv); } - let gv = self.static_addr_of_mut(cv, align, kind); - llvm::set_global_constant(gv, true); - - self.const_globals.borrow_mut().insert(cv, gv); gv } @@ -768,22 +753,16 @@ impl<'ll> CodegenCx<'ll, '_> { } impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { - /// Get a pointer to a global variable. - /// - /// The pointer will always be in the default address space. If global variables default to a - /// different address space, an addrspacecast is inserted. - fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value { - // FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the - // same `ConstAllocation`? - let cv = const_alloc_to_llvm(self, alloc.inner(), /*static*/ false); - - let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind); - // static_addr_of_impl returns the bare global variable, which might not be in the default - // address space. Cast to the default address space if necessary. - self.const_pointercast(gv, self.type_ptr()) - } - fn codegen_static(&mut self, def_id: DefId) { self.codegen_static_item(def_id) } + + fn set_value_name(&self, val: Self::Value, gen_name: impl FnOnce() -> String) { + if !self.sess().fewer_names() && llvm::get_value_name(val).is_empty() { + llvm::set_value_name(val, gen_name().as_bytes()) + } + } + fn get_static(&self, def_id: DefId) -> Self::Value { + self.get_static(def_id) + } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index a3299af35ac21..753d17cff9db0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -4,7 +4,7 @@ use libc::c_uint; use rustc_abi::{Size, TagEncoding, VariantIdx, Variants}; use rustc_codegen_ssa::debuginfo::type_names::compute_debuginfo_type_name; use rustc_codegen_ssa::debuginfo::{tag_base_type, wants_c_like_enum_debuginfo}; -use rustc_codegen_ssa::traits::{ConstCodegenMethods, MiscCodegenMethods}; +use rustc_codegen_ssa::traits::{BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, ty}; use smallvec::smallvec; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 796f3d9ef60ba..60d15a4103cc5 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -59,11 +59,6 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } } - ///x Creates an integer type with the given number of bits, e.g., i24 - pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { - llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) - } - pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } @@ -234,6 +229,10 @@ impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, FALSE) } } + fn type_ix(&self, num_bits: u64) -> &'ll Type { + llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) + } + fn type_kind(&self, ty: &'ll Type) -> TypeKind { llvm::LLVMGetTypeKind(ty).to_rust().to_generic() } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index ebc993f14ea03..a3111c4187366 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -140,7 +140,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Self::alloca(bx, ptr_layout) } - pub fn len>(&self, cx: &Cx) -> V { + pub fn len>(&self, cx: &Cx) -> V { if let FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 22784a8868ab5..19fba16b68922 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -1,9 +1,20 @@ -use rustc_abi as abi; -use rustc_middle::mir::interpret::Scalar; +use rustc_abi::{self as abi, HasDataLayout, Primitive}; +use rustc_data_structures::stable_hash::{StableHash as _, StableHasher}; +use rustc_hashes::Hash128; +use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; +use rustc_middle::ty::layout::HasTyCtxt; -use super::BackendTypes; +use super::BaseTypeCodegenMethods; +use crate::traits::{MiscCodegenMethods, StaticCodegenMethods}; -pub trait ConstCodegenMethods: BackendTypes { +pub trait ConstCodegenMethods<'tcx>: + BaseTypeCodegenMethods + + HasDataLayout + + HasTyCtxt<'tcx> + + MiscCodegenMethods<'tcx> + + StaticCodegenMethods + + Sized +{ // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; /// Generate an uninitialized value (matching uninitialized memory in MIR). @@ -38,7 +49,100 @@ pub trait ConstCodegenMethods: BackendTypes { fn const_to_opt_uint(&self, v: Self::Value) -> Option; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; + fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_pointercast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_int_to_ptr(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + fn const_ptr_to_int(&self, val: Self::Value, ty: Self::Type) -> Self::Value; + + /// Create a global constant. + /// + /// The returned global variable is a pointer in the default address space for globals. + /// Immutable allocations are deduplicated. + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value; + + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Self::Type) -> Self::Value { + let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; + match cv { + Scalar::Int(int) => { + let data = int.to_bits(layout.size(self)); + let val = self.const_uint_big(self.type_ix(bitsize), data); + if matches!(layout.primitive(), Primitive::Pointer(_)) { + self.const_int_to_ptr(val, ty) + } else { + self.const_bitcast(val, ty) + } + } + Scalar::Ptr(ptr, _size) => { + let (prov, offset) = ptr.prov_and_relative_offset(); + let global_alloc = self.tcx().global_alloc(prov.alloc_id()); + let base_addr = match global_alloc { + GlobalAlloc::Memory(alloc) => { + // For ZSTs directly codegen an aligned pointer. + // This avoids generating a zero-sized constant value and actually needing a + // real address at runtime. + if alloc.inner().len() == 0 { + let val = alloc.inner().align.bytes().wrapping_add(offset.bytes()); + let val = self.const_usize(val); + return if matches!(layout.primitive(), Primitive::Pointer(_)) { + self.const_int_to_ptr(val, ty) + } else { + self.const_bitcast(val, ty) + }; + } else { + let value = self.static_addr_of(alloc, None); + self.set_value_name(value, || { + let hash = self.tcx().with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + alloc.inner().stable_hash(&mut hcx, &mut hasher); + hasher.finish::() + }); + format!("alloc_{hash:032x}") + }); + + value + } + } + GlobalAlloc::Function { instance, .. } => self.get_fn_addr(instance), + GlobalAlloc::VTable(ty, dyn_ty) => { + let alloc = self + .tcx() + .global_alloc(self.tcx().vtable_allocation(( + ty, + dyn_ty.principal().map(|principal| { + self.tcx().instantiate_bound_regions_with_erased(principal) + }), + ))) + .unwrap_memory(); + self.static_addr_of(alloc, None) + } + GlobalAlloc::Static(def_id) => { + assert!(self.tcx().is_static(def_id)); + assert!(!self.tcx().is_thread_local_static(def_id)); + self.get_static(def_id) + } + GlobalAlloc::TypeId { .. } => { + // Drop the provenance, the offset contains the bytes of the hash + let val = self.const_usize(offset.bytes()); + // This is still a variable of pointer type, even though we only use the provenance + // of that pointer in CTFE and Miri. But to make the backend's type system happy, + // we need an int-to-ptr cast here (it doesn't matter at all which provenance that picks). + return self.const_int_to_ptr(val, ty); + } + }; + let base_addr_space = global_alloc.address_space(self); + + // Cast to the required address space if necessary + let val = self.const_pointercast(base_addr, self.type_ptr_ext(base_addr_space)); + let val = self.const_ptr_byte_offset(val, offset); + + if !matches!(layout.primitive(), Primitive::Pointer(_)) { + self.const_ptr_to_int(val, ty) + } else { + self.const_bitcast(val, ty) + } + } + } + } fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index f46d07ea5008e..3694fd4f4ea17 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -55,7 +55,7 @@ pub trait CodegenObject = Copy + fmt::Debug; pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + TypeCodegenMethods<'tcx> - + ConstCodegenMethods + + ConstCodegenMethods<'tcx> + StaticCodegenMethods + DebugInfoCodegenMethods<'tcx> + AsmCodegenMethods<'tcx> diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs index c726213025350..79a019866be20 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -1,11 +1,16 @@ use rustc_hir::def_id::DefId; -use rustc_middle::mir::interpret::ConstAllocation; use super::BackendTypes; pub trait StaticCodegenMethods: BackendTypes { - fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value; + /// Set a debuginfo name. The name closure is only invoked if a name actually needs to be + /// registered, so you can do expensive name calculations in it. + fn set_value_name(&self, val: Self::Value, gen_name: impl FnOnce() -> String); fn codegen_static(&mut self, def_id: DefId); + + /// Prefer calling [StaticBuilderMethods::get_static] as that also performs + /// addrspace casts and runtime lookups for thread local statics. + fn get_static(&self, def_id: DefId) -> Self::Value; } pub trait StaticBuilderMethods: BackendTypes { diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 45ea8384b2d46..81fd348bcf737 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -27,6 +27,8 @@ pub trait BaseTypeCodegenMethods: BackendTypes { fn type_kind(&self, ty: Self::Type) -> TypeKind; fn type_ptr(&self) -> Self::Type; fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type; + /// Creates an integer type with the given number of bits, e.g., i24 + fn type_ix(&self, num_bits: u64) -> Self::Type; fn element_type(&self, ty: Self::Type) -> Self::Type; /// Returns the number of elements in `self` if it is an LLVM vector type.