Skip to content

Commit b46ded4

Browse files
committed
EII: generate aliases for implementations
1 parent 3e33e23 commit b46ded4

File tree

6 files changed

+93
-5
lines changed

6 files changed

+93
-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
@@ -2689,4 +2689,12 @@ unsafe extern "C" {
26892689

26902690
pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value);
26912691
pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value);
2692+
2693+
pub(crate) fn LLVMAddAlias2<'ll>(
2694+
M: &'ll Module,
2695+
ValueTy: &Type,
2696+
AddressSpace: c_uint,
2697+
Aliasee: &Value,
2698+
Name: *const c_char,
2699+
) -> &'ll Value;
26922700
}

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::*;
@@ -437,3 +437,14 @@ pub(crate) fn append_module_inline_asm<'ll>(llmod: &'ll Module, asm: &[u8]) {
437437
LLVMAppendModuleInlineAsm(llmod, asm.as_ptr(), asm.len());
438438
}
439439
}
440+
441+
/// Safe wrapper for `LLVMAddAlias2`
442+
pub(crate) fn add_alias<'ll>(
443+
module: &'ll Module,
444+
ty: &Type,
445+
address_space: AddressSpace,
446+
aliasee: &Value,
447+
name: &CStr,
448+
) -> &'ll Value {
449+
unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) }
450+
}

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::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: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ 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, UsedBy};
6+
use rustc_hir::attrs::{AttributeKind, InlineAttr, InstructionSetAttr, Linkage, UsedBy};
77
use rustc_hir::def::DefKind;
88
use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
99
use rustc_hir::{self as hir, Attribute, LangItem, find_attr, lang_items};
1010
use rustc_middle::middle::codegen_fn_attrs::{
1111
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
1212
};
13+
use rustc_middle::mir::mono::Visibility;
1314
use rustc_middle::query::Providers;
1415
use rustc_middle::span_bug;
15-
use rustc_middle::ty::{self as ty, TyCtxt};
16+
use rustc_middle::ty::{self as ty, Instance, TyCtxt};
1617
use rustc_session::lint;
1718
use rustc_session::parse::feature_err;
18-
use rustc_span::{Ident, Span, sym};
19+
use rustc_span::{Ident, Span, Symbol, sym};
1920
use rustc_target::spec::SanitizerSet;
2021

2122
use crate::errors;
@@ -296,6 +297,39 @@ fn process_builtin_attrs(
296297
AttributeKind::Sanitize { span, .. } => {
297298
interesting_spans.sanitize = Some(*span);
298299
}
300+
AttributeKind::EiiImpls(impls) => {
301+
for i in impls {
302+
let extern_item = find_attr!(
303+
tcx.get_all_attrs(i.eii_macro),
304+
AttributeKind::EiiExternTarget(target) => target.eii_extern_target
305+
)
306+
.expect("eii should have declaration macro with extern target attribute");
307+
308+
let symbol_name = tcx.symbol_name(Instance::mono(tcx, extern_item));
309+
310+
// this is to prevent a bug where a single crate defines both the default and explicit implementation
311+
// for an EII. In that case, both of them may be part of the same final object file. I'm not 100% sure
312+
// what happens, either rustc deduplicates the symbol or llvm, or it's random/order-dependent.
313+
// However, the fact that the default one of has weak linkage isn't considered and you sometimes get that
314+
// the default implementation is used while an explicit implementation is given.
315+
if
316+
// if this is a default impl
317+
i.is_default
318+
// iterate over all implementations *in the current crate*
319+
// (this is ok since we generate codegen fn attrs in the local crate)
320+
// if any of them is *not default* then don't emit the alias.
321+
&& tcx.externally_implementable_items(LOCAL_CRATE).get(&i.eii_macro).expect("at least one").1.iter().any(|(_, imp)| !imp.is_default)
322+
{
323+
continue;
324+
}
325+
326+
codegen_fn_attrs.foreign_item_symbol_aliases.push((
327+
Symbol::intern(symbol_name.name),
328+
if i.is_default { Linkage::LinkOnceAny } else { Linkage::External },
329+
Visibility::Default,
330+
));
331+
}
332+
}
299333
_ => {}
300334
}
301335
}

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> {
@@ -38,6 +39,12 @@ pub struct CodegenFnAttrs {
3839
/// using the `#[export_name = "..."]` or `#[link_name = "..."]` attribute
3940
/// depending on if this is a function definition or foreign function.
4041
pub symbol_name: Option<Symbol>,
42+
/// Defids of foreign items somewhere that this function should "satisfy".
43+
/// i.e., if a foreign function has some symbol foo,
44+
/// generate this function under its real name,
45+
/// but *also* under the same name as this foreign function so that the foreign function has an implementation.
46+
// FIXME: make "SymbolName<'tcx>"
47+
pub foreign_item_symbol_aliases: Vec<(Symbol, Linkage, Visibility)>,
4148
/// The `#[link_ordinal = "..."]` attribute, indicating an ordinal an
4249
/// imported function has in the dynamic library. Note that this must not
4350
/// be set when `link_name` is set. This is for foreign items with the
@@ -177,6 +184,7 @@ impl CodegenFnAttrs {
177184
symbol_name: None,
178185
link_ordinal: None,
179186
target_features: vec![],
187+
foreign_item_symbol_aliases: vec![],
180188
safe_target_features: false,
181189
linkage: None,
182190
import_linkage: None,

compiler/rustc_middle/src/mir/mono.rs

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

0 commit comments

Comments
 (0)