diff --git a/Cargo.lock b/Cargo.lock index 110d17142bb3f..370f9368efd44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3512,7 +3512,6 @@ dependencies = [ "rustc_errors", "rustc_fluent_macro", "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 fdd47821b515b..ac991e2e03a7e 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,12 +1,10 @@ use gccjit::{LValue, RValue, ToRValue, Type}; use rustc_abi as abi; use rustc_abi::HasDataLayout; -use rustc_abi::Primitive::Pointer; use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, + BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, }; -use rustc_middle::mir::Mutability; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; +use rustc_middle::mir::interpret::ConstAllocation; use rustc_middle::ty::layout::LayoutOf; use crate::context::CodegenCx; @@ -42,6 +40,22 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { // SIMD builtins require a constant value. self.bitcast_if_needed(value, typ) } + + pub fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> RValue<'gcc> { + // We ignore the alignment for the purpose of deduping RValues + // The alignment is not handled / used in any way by `const_alloc_to_gcc`, + // so it is OK to overwrite it here. + let mut mock_alloc = alloc.inner().clone(); + mock_alloc.align = rustc_abi::Align::MAX; + // Check if the rvalue is already in the cache - if so, just return it directly. + if let Some(res) = self.const_cache.borrow().get(&mock_alloc) { + return *res; + } + // Rvalue not in the cache - convert and add it. + let res = crate::consts::const_alloc_to_gcc_uncached(self, alloc); + self.const_cache.borrow_mut().insert(mock_alloc, res); + res + } } pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { @@ -110,7 +124,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,107 +243,32 @@ 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. - // TODO(antoyo): perhaps only use bitcast for pointers? - self.context.new_cast(None, value, ty) - } else { - // TODO(bjorn3): assert size is correct - self.const_bitcast(value, ty) - } - } - Scalar::Ptr(ptr, _size) => { - let (prov, offset) = ptr.into_parts(); // we know the `offset` is relative - 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 { - assert_eq!(offset.bytes(), 0); - let val = self.const_usize(alloc.inner().align.bytes()); - return if matches!(layout.primitive(), Pointer(_)) { - self.context.new_cast(None, val, ty) - } else { - self.const_bitcast(val, ty) - }; - } - - let init = self.const_data_from_alloc(alloc); - let alloc = alloc.inner(); - let value = match alloc.mutability { - Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None), - _ => self.static_addr_of(init, alloc.align, None), - }; - if !self.sess().fewer_names() { - // TODO(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(); - let init = self.const_data_from_alloc(alloc); - self.static_addr_of(init, alloc.inner().align, None) - } - 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_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - // We ignore the alignment for the purpose of deduping RValues - // The alignment is not handled / used in any way by `const_alloc_to_gcc`, - // so it is OK to overwrite it here. - let mut mock_alloc = alloc.inner().clone(); - mock_alloc.align = rustc_abi::Align::MAX; - // Check if the rvalue is already in the cache - if so, just return it directly. - if let Some(res) = self.const_cache.borrow().get(&mock_alloc) { - return *res; - } - // Rvalue not in the cache - convert and add it. - let res = crate::consts::const_alloc_to_gcc_uncached(self, alloc); - self.const_cache.borrow_mut().insert(mock_alloc, res); - res - } - 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_const(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value { + self.static_addr_of(alloc, kind) + } + + fn static_addr_of_mut(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value { + let cv = self.const_data_from_alloc(alloc); + self.static_addr_of_mut(cv, alloc.inner().align, kind) + } } pub trait SignType<'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index b43f9b24c6a31..513d31bcec9ff 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -35,7 +35,9 @@ fn set_global_alignment<'gcc, 'tcx>( } impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { - fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> { + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> RValue<'gcc> { + let align = alloc.inner().align; + let cv = self.const_data_from_alloc(alloc); 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; @@ -150,6 +152,17 @@ impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { self.add_used_global(global.to_rvalue()); } } + + fn get_value_name(&self, _val: Self::Value) -> &[u8] { + // TODO(antoyo) + &[] + } + fn set_value_name(&self, _val: Self::Value, _name: &[u8]) { + // TODO(antoyo) + } + fn get_static(&self, def_id: DefId) -> Self::Value { + self.get_static(def_id).get_address(None) + } } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 15a0206607e12..86d31c46f2a56 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; 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 88efc8ac96b57..4621339122f9b 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -25,7 +25,6 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } 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 ae5add59322fe..1b528ecfafd00 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -5,15 +5,11 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::HasDataLayout; -use rustc_abi::Primitive::Pointer; -use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hashes::Hash128; use rustc_hir::def_id::DefId; use rustc_middle::bug; -use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar}; +use rustc_middle::mir::interpret::ConstAllocation; use rustc_middle::ty::TyCtxt; use rustc_session::cstore::DllImport; use tracing::debug; @@ -121,7 +117,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) } } @@ -255,100 +251,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.into_parts(); - 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 { - assert_eq!(offset.bytes(), 0); - let llval = self.const_usize(alloc.inner().align.bytes()); - 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, /*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.hash_stable(&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, /*static*/ false); - let value = self.static_addr_of_impl(init, alloc.inner().align, None); - value - } - 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) - } - }; - 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_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { - const_alloc_to_llvm(self, alloc, /*static*/ false) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { unsafe { llvm::LLVMConstInBoundsGEP2( @@ -359,6 +261,29 @@ 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_const(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value { + let cv = const_alloc_to_llvm(self, alloc, /*static*/ false); + self.static_addr_of_const(cv, alloc.inner().align, kind) + } + + fn static_addr_of_mut(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value { + let cv = const_alloc_to_llvm(self, alloc, /*static*/ false); + self.static_addr_of_mut(cv, alloc.inner().align, kind) + } } /// 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 a4492d76c3c59..2718cbb561d98 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -214,14 +214,6 @@ 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. @@ -252,7 +244,7 @@ impl<'ll> CodegenCx<'ll, '_> { /// 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( + pub(crate) fn static_addr_of_const( &self, cv: &'ll Value, align: Align, @@ -559,9 +551,10 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { /// /// 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, cv: &'ll Value, align: Align, kind: Option<&str>) -> &'ll Value { - let gv = self.static_addr_of_impl(cv, align, kind); - // static_addr_of_impl returns the bare global variable, which might not be in the default + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value { + let cv = const_alloc_to_llvm(self, alloc, /*static*/ false); + let gv = self.static_addr_of_const(cv, alloc.inner().align, kind); + // static_addr_of_const 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()) } @@ -569,4 +562,14 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { fn codegen_static(&mut self, def_id: DefId) { self.codegen_static_item(def_id) } + + fn get_value_name(&self, val: Self::Value) -> &[u8] { + llvm::get_value_name(val) + } + fn set_value_name(&self, val: Self::Value, name: &[u8]) { + llvm::set_value_name(val, name) + } + 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 62d38d463aba7..1a335b02a9202 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::bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self}; diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 453eca2bbe173..d868865edf3a8 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 { - unsafe { 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) } } @@ -203,6 +198,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 { + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) } + } + fn type_kind(&self, ty: &'ll Type) -> TypeKind { unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } } diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 3a11ce6befb36..359a4867fab5c 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -114,9 +114,7 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref)); let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); - let vtable_const = cx.const_data_from_alloc(vtable_allocation); - let align = cx.data_layout().pointer_align.abi; - let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); + let vtable = cx.static_addr_of(vtable_allocation, Some("vtable")); cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); cx.create_vtable_debuginfo(ty, trait_ref, vtable); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index da615cc9a003d..c80b50ce64b59 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -237,8 +237,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // Neither a scalar nor scalar pair. Load from a place // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the // same `ConstAllocation`? - let init = bx.const_data_from_alloc(alloc); - let base_addr = bx.static_addr_of(init, alloc_align, None); + let base_addr = bx.static_addr_of(alloc, None); let llval = bx.const_ptr_byte_offset(base_addr, offset); bx.load_operand(PlaceRef::new_sized(llval, layout)) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 937063c24a63d..f9aba0234013c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -132,7 +132,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 d83a04d814be3..6f4804dfef3f6 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -1,9 +1,21 @@ -use rustc_abi as abi; -use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; +use rustc_abi::{self as abi, HasDataLayout, Primitive}; +use rustc_ast::Mutability; +use rustc_data_structures::stable_hasher::{HashStable, 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). @@ -37,9 +49,97 @@ 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 const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> 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. + fn static_addr_of_const(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value; - fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; + /// Same as `static_addr_of_const`, but does not mark the static as immutable + fn static_addr_of_mut(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value; + + fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: 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 llval = self.const_uint_big(self.type_ix(bitsize), data); + if matches!(layout.primitive(), Primitive::Pointer(_)) { + self.const_int_to_ptr(llval, llty) + } else { + self.const_bitcast(llval, llty) + } + } + Scalar::Ptr(ptr, _size) => { + let (prov, offset) = ptr.into_parts(); + 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 { + assert_eq!(offset.bytes(), 0); + let llval = self.const_usize(alloc.inner().align.bytes()); + return if matches!(layout.primitive(), Primitive::Pointer(_)) { + self.const_int_to_ptr(llval, llty) + } else { + self.const_bitcast(llval, llty) + }; + } else { + let value = match alloc.inner().mutability { + Mutability::Mut => self.static_addr_of_mut(alloc, None), + _ => self.static_addr_of_const(alloc, None), + }; + if !self.tcx().sess.fewer_names() + && self.get_value_name(value).is_empty() + { + let hash = self.tcx().with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + alloc.inner().hash_stable(&mut hcx, &mut hasher); + hasher.finish::() + }); + self.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(); + self.static_addr_of_const(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) + } + }; + 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, llty) + } else { + self.const_bitcast(val, llty) + } + } + } + } 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 6d1ac717c0b8f..69f0732f84c1c 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 0e1e445c72f35..c56b0b707de1b 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -1,11 +1,14 @@ -use rustc_abi::Align; use rustc_hir::def_id::DefId; +use rustc_middle::mir::interpret::ConstAllocation; use super::BackendTypes; pub trait StaticCodegenMethods: BackendTypes { - fn static_addr_of(&self, cv: Self::Value, align: Align, kind: Option<&str>) -> Self::Value; + fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value; + fn get_value_name(&self, val: Self::Value) -> &[u8]; + fn set_value_name(&self, val: Self::Value, name: &[u8]); fn codegen_static(&mut self, def_id: DefId); + 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 dcd9e25b2c952..d794883f244ce 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.