diff options
Diffstat (limited to 'compiler/rustc_codegen_llvm/src')
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/abi.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/attributes.rs | 31 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/back/archive.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/consts.rs | 9 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 181 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_codegen_llvm/src/llvm_util.rs | 49 |
7 files changed, 225 insertions, 59 deletions
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index e9b66b54c58..8a11e3e71bc 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -37,7 +37,7 @@ impl ArgAttributeExt for ArgAttribute { where F: FnMut(llvm::Attribute), { - for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg) + for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg, NoUndef) } } diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 7f82ce307d5..2472789601e 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -322,12 +322,33 @@ pub fn from_fn_attrs<'ll, 'tcx>( // The target doesn't care; the subtarget reads our attribute. apply_tune_cpu_attr(cx, llfn); - let mut function_features = codegen_fn_attrs - .target_features + let function_features = + codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>(); + + if let Some(f) = llvm_util::check_tied_features( + cx.tcx.sess, + &function_features.iter().map(|f| (*f, true)).collect(), + ) { + let span = cx + .tcx + .get_attrs(instance.def_id()) + .iter() + .find(|a| a.has_name(rustc_span::sym::target_feature)) + .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span); + let msg = format!( + "the target features {} must all be either enabled or disabled together", + f.join(", ") + ); + let mut err = cx.tcx.sess.struct_span_err(span, &msg); + err.help("add the missing features in a `target_feature` attribute"); + err.emit(); + return; + } + + let mut function_features = function_features .iter() - .flat_map(|f| { - let feature = f.as_str(); - llvm_util::to_llvm_feature(cx.tcx.sess, feature) + .flat_map(|feat| { + llvm_util::to_llvm_feature(cx.tcx.sess, feat) .into_iter() .map(|f| format!("+{}", f)) .collect::<Vec<String>>() diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 8a1dea4d99b..21bd1dae7ac 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -27,7 +27,6 @@ pub struct LlvmArchiveBuilder<'a> { config: ArchiveConfig<'a>, removals: Vec<String>, additions: Vec<Addition>, - should_update_symbols: bool, src_archive: Option<Option<ArchiveRO>>, } @@ -75,7 +74,6 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { config, removals: Vec::new(), additions: Vec::new(), - should_update_symbols: false, src_archive: None, } } @@ -129,12 +127,6 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> { .push(Addition::File { path: file.to_path_buf(), name_in_archive: name.to_owned() }); } - /// Indicate that the next call to `build` should update all symbols in - /// the archive (equivalent to running 'ar s' over it). - fn update_symbols(&mut self) { - self.should_update_symbols = true; - } - /// Combine the provided files, rlibs, and native libraries into a single /// `Archive`. fn build(mut self) { @@ -313,7 +305,6 @@ impl<'a> LlvmArchiveBuilder<'a> { let mut members = Vec::new(); let dst = CString::new(self.config.dst.to_str().unwrap())?; - let should_update_symbols = self.should_update_symbols; unsafe { if let Some(archive) = self.src_archive() { @@ -385,7 +376,7 @@ impl<'a> LlvmArchiveBuilder<'a> { dst.as_ptr(), members.len() as libc::size_t, members.as_ptr() as *const &_, - should_update_symbols, + true, kind, ); let ret = if r.into_result().is_err() { diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index d43c7c60651..6707de93352 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -522,6 +522,9 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { } if attrs.flags.contains(CodegenFnAttrFlags::USED) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)); + // The semantics of #[used] in Rust only require the symbol to make it into the // object file. It is explicitly allowed for the linker to strip the symbol if it // is dead. As such, use llvm.compiler.used instead of llvm.used. @@ -530,6 +533,12 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { // in some versions of the gold linker. self.add_compiler_used_global(g); } + if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) { + // `USED` and `USED_LINKER` can't be used together. + assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED)); + + self.add_used_global(g); + } } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 1266b540aae..da997dd9879 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -21,6 +21,7 @@ use crate::value::Value; use cstr::cstr; use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo; +use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind; use rustc_codegen_ssa::traits::*; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -276,6 +277,12 @@ impl<'ll, 'tcx> TypeMap<'ll, 'tcx> { ) -> String { format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id)) } + + /// Gets the `UniqueTypeId` for the type of a vtable. + fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> UniqueTypeId { + let interner_key = self.unique_id_interner.intern(vtable_type_name); + interner_key + } } /// A description of some recursive type. It can either be already finished (as @@ -351,14 +358,15 @@ impl<'ll, 'tcx> RecursiveTypeDescription<'ll, 'tcx> { // ... then create the member descriptions ... let member_descriptions = member_description_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, unfinished_type); // ... and attach them to the stub to complete it. set_members_of_composite_type( cx, - unfinished_type, member_holding_stub, member_descriptions, None, + type_params, ); MetadataCreationResult::new(metadata_stub, true) } @@ -983,7 +991,17 @@ fn foreign_type_metadata<'ll, 'tcx>( debug!("foreign_type_metadata: {:?}", t); let name = compute_debuginfo_type_name(cx.tcx, t, false); - create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero) + let (size, align) = cx.size_and_align_of(t); + create_struct_stub( + cx, + size, + align, + &name, + unique_type_id, + NO_SCOPE_METADATA, + DIFlags::FlagZero, + None, + ) } fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { @@ -1299,14 +1317,17 @@ fn prepare_struct_metadata<'ll, 'tcx>( }; let containing_scope = get_namespace_for_item(cx, struct_def_id); + let (size, align) = cx.size_and_align_of(struct_type); let struct_metadata_stub = create_struct_stub( cx, - struct_type, + size, + align, &struct_name, unique_type_id, Some(containing_scope), DIFlags::FlagZero, + None, ); create_and_register_recursive_type_forward_declaration( @@ -1398,15 +1419,18 @@ fn prepare_tuple_metadata<'ll, 'tcx>( unique_type_id: UniqueTypeId, containing_scope: Option<&'ll DIScope>, ) -> RecursiveTypeDescription<'ll, 'tcx> { + let (size, align) = cx.size_and_align_of(tuple_type); let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false); let struct_stub = create_struct_stub( cx, - tuple_type, + size, + align, &tuple_name[..], unique_type_id, containing_scope, DIFlags::FlagZero, + None, ); create_and_register_recursive_type_forward_declaration( @@ -1581,13 +1605,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { describe_enum_variant(cx, self.layout, variant_info, self_metadata); let member_descriptions = member_description_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); vec![MemberDescription { name: variant_info.variant_name(), @@ -1648,13 +1673,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { let member_descriptions = member_desc_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); MemberDescription { @@ -1777,13 +1803,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { ); let member_descriptions = member_desc_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); let (size, align) = @@ -1823,13 +1850,14 @@ impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> { let member_descriptions = member_desc_factory.create_member_descriptions(cx); + let type_params = compute_type_parameters(cx, self.enum_type); set_members_of_composite_type( cx, - self.enum_type, variant_type_metadata, member_descriptions, Some(&self.common_members), + type_params, ); let niche_value = calculate_niche_value(i); @@ -1965,13 +1993,18 @@ fn describe_enum_variant<'ll, 'tcx>( .type_map .borrow_mut() .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name); + + let (size, align) = cx.size_and_align_of(layout.ty); + create_struct_stub( cx, - layout.ty, + size, + align, variant_name, unique_type_id, Some(containing_scope), DIFlags::FlagZero, + None, ) }); @@ -2308,22 +2341,27 @@ fn composite_type_metadata<'ll, 'tcx>( member_descriptions: Vec<MemberDescription<'ll>>, containing_scope: Option<&'ll DIScope>, ) -> &'ll DICompositeType { + let (size, align) = cx.size_and_align_of(composite_type); + // Create the (empty) struct metadata node ... let composite_type_metadata = create_struct_stub( cx, - composite_type, + size, + align, composite_type_name, composite_type_unique_id, containing_scope, DIFlags::FlagZero, + None, ); + // ... and immediately create and add the member descriptions. set_members_of_composite_type( cx, - composite_type, composite_type_metadata, member_descriptions, None, + compute_type_parameters(cx, composite_type), ); composite_type_metadata @@ -2331,10 +2369,10 @@ fn composite_type_metadata<'ll, 'tcx>( fn set_members_of_composite_type<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - composite_type: Ty<'tcx>, composite_type_metadata: &'ll DICompositeType, member_descriptions: Vec<MemberDescription<'ll>>, common_members: Option<&Vec<Option<&'ll DIType>>>, + type_params: &'ll DIArray, ) { // In some rare cases LLVM metadata uniquing would lead to an existing type // description being used instead of a new one created in @@ -2361,13 +2399,12 @@ fn set_members_of_composite_type<'ll, 'tcx>( member_metadata.extend(other_members.iter()); } - let type_params = compute_type_parameters(cx, composite_type); unsafe { - let type_array = create_DIArray(DIB(cx), &member_metadata); + let field_array = create_DIArray(DIB(cx), &member_metadata); llvm::LLVMRustDICompositeTypeReplaceArrays( DIB(cx), composite_type_metadata, - Some(type_array), + Some(field_array), Some(type_params), ); } @@ -2420,14 +2457,14 @@ fn compute_type_parameters<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) - /// with `set_members_of_composite_type()`. fn create_struct_stub<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, - struct_type: Ty<'tcx>, - struct_type_name: &str, + size: Size, + align: Align, + type_name: &str, unique_type_id: UniqueTypeId, containing_scope: Option<&'ll DIScope>, flags: DIFlags, + vtable_holder: Option<&'ll DIType>, ) -> &'ll DICompositeType { - let (struct_size, struct_align) = cx.size_and_align_of(struct_type); - let type_map = debug_context(cx).type_map.borrow(); let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id); @@ -2440,17 +2477,17 @@ fn create_struct_stub<'ll, 'tcx>( llvm::LLVMRustDIBuilderCreateStructType( DIB(cx), containing_scope, - struct_type_name.as_ptr().cast(), - struct_type_name.len(), + type_name.as_ptr().cast(), + type_name.len(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, - struct_size.bits(), - struct_align.bits() as u32, + size.bits(), + align.bits() as u32, flags, None, empty_array, 0, - None, + vtable_holder, unique_type_id.as_ptr().cast(), unique_type_id.len(), ) @@ -2556,6 +2593,14 @@ pub fn create_global_var_metadata<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, g } /// Generates LLVM debuginfo for a vtable. +/// +/// The vtable type looks like a struct with a field for each function pointer and super-trait +/// pointer it contains (plus the `size` and `align` fields). +/// +/// Except for `size`, `align`, and `drop_in_place`, the field names don't try to mirror +/// the name of the method they implement. This can be implemented in the future once there +/// is a proper disambiguation scheme for dealing with methods from different traits that have +/// the same name. fn vtable_type_metadata<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>, @@ -2572,16 +2617,81 @@ fn vtable_type_metadata<'ll, 'tcx>( COMMON_VTABLE_ENTRIES }; - // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is - // correct - but we could create a more accurate description, e.g. by describing it - // as a struct where each field has a name that corresponds to the name of the method - // it points to. - // However, this is not entirely straightforward because there might be multiple - // methods with the same name if the vtable is for multiple traits. So for now we keep - // things simple instead of adding some ad-hoc disambiguation scheme. - let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64); + // All function pointers are described as opaque pointers. This could be improved in the future + // by describing them as actual function pointers. + let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit); + let void_pointer_type_debuginfo = type_metadata(cx, void_pointer_ty); + let usize_debuginfo = type_metadata(cx, tcx.types.usize); + let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty); + // If `usize` is not pointer-sized and -aligned then the size and alignment computations + // for the vtable as a whole would be wrong. Let's make sure this holds even on weird + // platforms. + assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align)); + + let vtable_type_name = + compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type); + let unique_type_id = debug_context(cx) + .type_map + .borrow_mut() + .get_unique_type_id_of_vtable_type(&vtable_type_name); + let size = pointer_size * vtable_entries.len() as u64; + + // This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate + // the vtable to the type it is for. + let vtable_holder = type_metadata(cx, ty); + + let vtable_type_metadata = create_struct_stub( + cx, + size, + pointer_align, + &vtable_type_name, + unique_type_id, + NO_SCOPE_METADATA, + DIFlags::FlagArtificial, + Some(vtable_holder), + ); + + // Create a field for each entry in the vtable. + let fields: Vec<_> = vtable_entries + .iter() + .enumerate() + .filter_map(|(index, vtable_entry)| { + let (field_name, field_type) = match vtable_entry { + ty::VtblEntry::MetadataDropInPlace => { + ("drop_in_place".to_string(), void_pointer_type_debuginfo) + } + ty::VtblEntry::Method(_) => { + // Note: This code does not try to give a proper name to each method + // because there might be multiple methods with the same name + // (coming from different traits). + (format!("__method{}", index), void_pointer_type_debuginfo) + } + ty::VtblEntry::TraitVPtr(_) => { + // Note: In the future we could try to set the type of this pointer + // to the type that we generate for the corresponding vtable. + (format!("__super_trait_ptr{}", index), void_pointer_type_debuginfo) + } + ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_debuginfo), + ty::VtblEntry::MetadataSize => ("size".to_string(), usize_debuginfo), + ty::VtblEntry::Vacant => return None, + }; + + Some(MemberDescription { + name: field_name, + type_metadata: field_type, + offset: pointer_size * index as u64, + size: pointer_size, + align: pointer_align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }) + }) + .collect(); - type_metadata(cx, vtable_type) + let type_params = create_DIArray(DIB(cx), &[]); + set_members_of_composite_type(cx, vtable_type_metadata, fields, None, type_params); + vtable_type_metadata } /// Creates debug information for the given vtable, which is for the @@ -2603,11 +2713,12 @@ pub fn create_vtable_metadata<'ll, 'tcx>( return; } - let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref); + let vtable_name = + compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable); let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref); + let linkage_name = ""; unsafe { - let linkage_name = ""; llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 367c86a1dc9..4f62c685568 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -189,6 +189,7 @@ pub enum Attribute { StackProtectReq = 30, StackProtectStrong = 31, StackProtect = 32, + NoUndef = 33, } /// LLVMIntPredicate diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index f91fad2d9c9..727d079d83d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -2,8 +2,8 @@ use crate::back::write::create_informational_target_machine; use crate::{llvm, llvm_util}; use libc::c_int; use libloading::Library; -use rustc_codegen_ssa::target_features::supported_target_features; -use rustc_data_structures::fx::FxHashSet; +use rustc_codegen_ssa::target_features::{supported_target_features, tied_target_features}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::config::PrintRequest; @@ -191,10 +191,30 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> { ("aarch64", "frintts") => vec!["fptoint"], ("aarch64", "fcma") => vec!["complxnum"], ("aarch64", "pmuv3") => vec!["perfmon"], + ("aarch64", "paca") => vec!["pauth"], + ("aarch64", "pacg") => vec!["pauth"], (_, s) => vec![s], } } +// Given a map from target_features to whether they are enabled or disabled, +// ensure only valid combinations are allowed. +pub fn check_tied_features( + sess: &Session, + features: &FxHashMap<&str, bool>, +) -> Option<&'static [&'static str]> { + for tied in tied_target_features(sess) { + // Tied features must be set to the same value, or not set at all + let mut tied_iter = tied.iter(); + let enabled = features.get(tied_iter.next().unwrap()); + + if tied_iter.any(|f| enabled != features.get(f)) { + return Some(tied); + } + } + None +} + pub fn target_features(sess: &Session) -> Vec<Symbol> { let target_machine = create_informational_target_machine(sess); supported_target_features(sess) @@ -395,15 +415,19 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> { Some(_) | None => {} }; + fn strip(s: &str) -> &str { + s.strip_prefix(&['+', '-']).unwrap_or(s) + } + let filter = |s: &str| { if s.is_empty() { return vec![]; } - let feature = if s.starts_with('+') || s.starts_with('-') { - &s[1..] - } else { + let feature = strip(s); + if feature == s { return vec![s.to_string()]; - }; + } + // Rustc-specific feature requests like `+crt-static` or `-crt-static` // are not passed down to LLVM. if RUSTC_SPECIFIC_FEATURES.contains(&feature) { @@ -420,8 +444,17 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> { features.extend(sess.target.features.split(',').flat_map(&filter)); // -Ctarget-features - features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter)); - + let feats: Vec<&str> = sess.opts.cg.target_feature.split(',').collect(); + // LLVM enables based on the last occurence of a feature + if let Some(f) = + check_tied_features(sess, &feats.iter().map(|f| (strip(f), !f.starts_with("-"))).collect()) + { + sess.err(&format!( + "Target features {} must all be enabled or disabled together", + f.join(", ") + )); + } + features.extend(feats.iter().flat_map(|&f| filter(f))); features } |
