Skip to content

Commit efa993a

Browse files
committed
EII: generate aliases for implementations
1 parent 2737608 commit efa993a

File tree

6 files changed

+95
-5
lines changed

6 files changed

+95
-5
lines changed

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2554,4 +2554,12 @@ unsafe extern "C" {
25542554

25552555
pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value);
25562556
pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
2557+
2558+
pub(crate) fn LLVMAddAlias2<'ll>(
2559+
M: &'ll Module,
2560+
ValueTy: &Type,
2561+
AddressSpace: c_uint,
2562+
Aliasee: &Value,
2563+
Name: *const c_char,
2564+
) -> &'ll Value;
25572565
}

compiler/rustc_codegen_llvm/src/llvm/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::ptr;
66
use std::string::FromUtf8Error;
77

88
use libc::c_uint;
9-
use rustc_abi::{Align, Size, WrappingRange};
9+
use rustc_abi::{AddressSpace, Align, Size, WrappingRange};
1010
use rustc_llvm::RustString;
1111

1212
pub(crate) use self::CallConv::*;
@@ -444,3 +444,14 @@ pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
444444
LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
445445
}
446446
}
447+
448+
/// Safe wrapper for `LLVMAddAlias2`
449+
pub(crate) fn add_alias<'ll>(
450+
module: &'ll Module,
451+
ty: &Type,
452+
address_space: AddressSpace,
453+
aliasee: &Value,
454+
name: &CStr,
455+
) -> &'ll Value {
456+
unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) }
457+
}

compiler/rustc_codegen_llvm/src/mono_item.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use std::ffi::CString;
2+
3+
use rustc_abi::AddressSpace;
14
use rustc_codegen_ssa::traits::*;
25
use rustc_hir::attrs::Linkage;
36
use rustc_hir::def::DefKind;
@@ -7,6 +10,7 @@ use rustc_middle::mir::mono::Visibility;
710
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
811
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
912
use rustc_session::config::CrateType;
13+
use rustc_span::Symbol;
1014
use rustc_target::spec::{Arch, RelocModel};
1115
use tracing::debug;
1216

@@ -41,6 +45,9 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
4145
llvm::set_visibility(g, base::visibility_to_llvm(visibility));
4246
self.assume_dso_local(g, false);
4347

48+
let attrs = self.tcx.codegen_instance_attrs(instance.def);
49+
self.add_aliases(g, &attrs.foreign_item_symbol_aliases);
50+
4451
self.instances.borrow_mut().insert(instance, g);
4552
}
4653

@@ -78,11 +85,31 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {
7885

7986
self.assume_dso_local(lldecl, false);
8087

88+
self.add_aliases(lldecl, &attrs.foreign_item_symbol_aliases);
89+
8190
self.instances.borrow_mut().insert(instance, lldecl);
8291
}
8392
}
8493

8594
impl CodegenCx<'_, '_> {
95+
fn add_aliases(&self, aliasee: &llvm::Value, aliases: &[(Symbol, Linkage, Visibility)]) {
96+
let ty = self.get_type_of_global(aliasee);
97+
98+
for (alias, linkage, visibility) in aliases {
99+
tracing::debug!("ALIAS: {alias:?} {linkage:?} {visibility:?}");
100+
let lldecl = llvm::add_alias(
101+
self.llmod,
102+
ty,
103+
AddressSpace::ZERO,
104+
aliasee,
105+
&CString::new(alias.as_str()).unwrap(),
106+
);
107+
108+
llvm::set_visibility(lldecl, base::visibility_to_llvm(*visibility));
109+
llvm::set_linkage(lldecl, base::linkage_to_llvm(*linkage));
110+
}
111+
}
112+
86113
/// Whether a definition or declaration can be assumed to be local to a group of
87114
/// libraries that form a single DSO or executable.
88115
/// Marks the local as DSO if so.

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,22 @@ use std::str::FromStr;
33
use rustc_abi::{Align, ExternAbi};
44
use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
55
use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
6-
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, RtsanSetting, UsedBy};
6+
use rustc_hir::attrs::{
7+
AttributeKind, InlineAttr, InstructionSetAttr, Linkage, RtsanSetting, UsedBy,
8+
};
79
use rustc_hir::def::DefKind;
810
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
911
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
1012
use rustc_middle::middle::codegen_fn_attrs::{
1113
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SanitizerFnAttrs,
1214
};
15+
use rustc_middle::mir::mono::Visibility;
1316
use rustc_middle::query::Providers;
1417
use rustc_middle::span_bug;
15-
use rustc_middle::ty::{self as ty, TyCtxt};
18+
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
1619
use rustc_session::lint;
1720
use rustc_session::parse::feature_err;
18-
use rustc_span::{Ident, Span, sym};
21+
use rustc_span::{Ident, Span, Symbol, sym};
1922
use rustc_target::spec::Os;
2023

2124
use crate::errors;
@@ -310,6 +313,39 @@ fn process_builtin_attrs(
310313
AttributeKind::ObjcSelector { methname, .. } => {
311314
codegen_fn_attrs.objc_selector = Some(*methname);
312315
}
316+
AttributeKind::EiiImpls(impls) => {
317+
for i in impls {
318+
let extern_item = find_attr!(
319+
tcx.get_all_attrs(i.eii_macro),
320+
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
321+
)
322+
.expect("eii should have declaration macro with extern target attribute");
323+
324+
let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item));
325+
326+
// this is to prevent a bug where a single crate defines both the default and explicit implementation
327+
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
328+
// what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent.
329+
// However, the fact that the default one of has weak linkage isn't considered and you sometimes get that
330+
// the default implementation is used while an explicit implementation is given.
331+
if
332+
// if this is a default impl
333+
i.is_default
334+
// iterate over all implementations *in the current crate*
335+
// (this is ok since we generate codegen fn attrs in the local crate)
336+
// if any of them is *not default* then don't emit the alias.
337+
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
338+
{
339+
continue;
340+
}
341+
342+
codegen_fn_attrs.foreign_item_symbol_aliases.push((
343+
Symbol::intern(symbol_name.name),
344+
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
345+
Visibility::Default,
346+
));
347+
}
348+
}
313349
_ => {}
314350
}
315351
}

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
66
use rustc_span::Symbol;
77
use rustc_target::spec::SanitizerSet;
88

9+
use crate::mir::mono::Visibility;
910
use crate::ty::{InstanceKind, TyCtxt};
1011

1112
impl<'tcx> TyCtxt<'tcx> {
@@ -62,6 +63,12 @@ pub struct CodegenFnAttrs {
6263
/// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
6364
/// depending on if this is a function definition or foreign function.
6465
pub symbol_name: Option<Symbol>,
66+
/// Defids of foreign items somewhere that this function should "satisfy".
67+
/// i.e., if a foreign function has some symbol foo,
68+
/// generate this function under its real name,
69+
/// but *also* under the same name as this foreign function so that the foreign function has an implementation.
70+
// FIXME: make "SymbolName<'tcx>"
71+
pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>,
6572
/// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
6673
/// imported function has in the dynamic library. Note that this must not
6774
/// be set when `link_name` is set. This is for foreign items with the
@@ -205,6 +212,7 @@ impl CodegenFnAttrs {
205212
symbol_name: None,
206213
link_ordinal: None,
207214
target_features: vec![],
215+
foreign_item_symbol_aliases: vec![],
208216
safe_target_features: false,
209217
linkage: None,
210218
import_linkage: None,

compiler/rustc_middle/src/mir/mono.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ pub struct MonoItemData {
374374
/// Visibility doesn't have any effect when linkage is internal.
375375
///
376376
/// DSO means dynamic shared object, that is a dynamically linked executable or dylib.
377-
#[derive(Copy, Clone, PartialEq, Debug, HashStable)]
377+
#[derive(Copy, Clone, PartialEq, Debug, HashStable, TyEncodable, TyDecodable)]
378378
pub enum Visibility {
379379
/// Export the symbol from the DSO and apply overrides of the symbol by outside DSOs to within
380380
/// the DSO if the object file format supports this.

0 commit comments

Comments
 (0)