Skip to content

Commit 509e266

Browse files
committed
squashed changes to tests
correctly emit `.hidden` this test was added in rust-lang#105193 but actually NO_COVERAGE is no longer a thing in the compiler. Sadly, the link to the issue is broken, so I don't know what the problem was originally, but I don't think this is relevant any more with the global asm approach rename test file because it now specifically checks for directives only used by non-macos, non-windows x86_64 add codegen tests for 4 interesting platforms add codegen test for the `#[instruction_set]` attribute add test for `#[link_section]` use `tcx.codegen_fn_attrs` to get attribute info Fix rust-lang#124375 inline const monomorphization/evaluation getting rid of FunctionCx mark naked functions as `InstantiatedMode::GloballyShared` this makes sure that the function prototype is defined correctly, and we don't see LLVM complaining about a global value with invalid linkage monomorphize type given to `SymFn` remove hack that always emits `.globl` monomorphize type given to `Const` remove `linkage_directive` make naked functions always have external linkage mark naked functions as `#[inline(never)]` add test file for functional generics/const/impl/trait usage of naked functions
1 parent 778553f commit 509e266

File tree

11 files changed

+416
-173
lines changed

11 files changed

+416
-173
lines changed

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
113113
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
114114
}
115115
sym::naked => {
116-
// this attribute is ignored during codegen, because a function marked as naked is
117-
// turned into a global asm block.
116+
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
117+
118+
// naked functions are generated as an extern function, and a global asm block that
119+
// contains the naked function's body. In order to link these together, the linkage
120+
// of the extern function must be external.
121+
codegen_fn_attrs.linkage = Some(Linkage::External);
118122
}
119123
sym::no_mangle => {
120124
if tcx.opt_item_name(did.to_def_id()).is_some() {
@@ -562,6 +566,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
562566
}
563567
});
564568

569+
// naked function MUST NOT be inlined!
570+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
571+
codegen_fn_attrs.inline = InlineAttr::Never;
572+
}
573+
565574
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
566575
if !attr.has_name(sym::optimize) {
567576
return ia;
@@ -649,14 +658,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
649658
}
650659
}
651660

652-
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
653-
// naked functions are generated using an extern function and global assembly. To
654-
// make sure that these can be linked together by LLVM, the linkage should be external,
655-
// unless the user explicitly configured something else (in which case any linker errors
656-
// they encounter are their responsibility).
657-
codegen_fn_attrs.linkage = codegen_fn_attrs.linkage.or(Some(Linkage::External));
658-
}
659-
660661
// Weak lang items have the same semantics as "std internal" symbols in the
661662
// sense that they're preserved through all our LTO passes and only
662663
// strippable by the linker.

compiler/rustc_codegen_ssa/src/mir/mod.rs

+2-23
Original file line numberDiff line numberDiff line change
@@ -171,29 +171,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
171171
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
172172
debug!("fn_abi: {:?}", fn_abi);
173173

174-
if cx.tcx().has_attr(instance.def.def_id(), rustc_span::sym::naked) {
175-
let cached_llbbs = IndexVec::new();
176-
177-
let fx: FunctionCx<'_, '_, Bx> = FunctionCx {
178-
instance,
179-
mir,
180-
llfn,
181-
fn_abi,
182-
cx,
183-
personality_slot: None,
184-
cached_llbbs,
185-
unreachable_block: None,
186-
terminate_block: None,
187-
cleanup_kinds: None,
188-
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
189-
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
190-
locals: locals::Locals::empty(),
191-
debug_context: None,
192-
per_local_var_debug_info: None,
193-
caller_location: None,
194-
};
195-
196-
fx.codegen_naked_asm(instance);
174+
if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
175+
crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
197176
return;
198177
}
199178

compiler/rustc_codegen_ssa/src/mir/naked_asm.rs

+104-85
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,99 @@
11
use crate::common;
2-
use crate::mir::FunctionCx;
3-
use crate::traits::{AsmMethods, BuilderMethods, GlobalAsmOperandRef};
2+
use crate::traits::{AsmMethods, BuilderMethods, GlobalAsmOperandRef, MiscMethods};
3+
use rustc_attr::InstructionSetAttr;
44
use rustc_middle::bug;
5+
use rustc_middle::mir::mono::{MonoItem, MonoItemData, Visibility};
6+
use rustc_middle::mir::Body;
57
use rustc_middle::mir::InlineAsmOperand;
68
use rustc_middle::ty;
79
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
810
use rustc_middle::ty::{Instance, TyCtxt};
9-
10-
use rustc_span::sym;
1111
use rustc_target::asm::InlineAsmArch;
1212

13-
impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
14-
pub fn codegen_naked_asm(&self, instance: Instance<'tcx>) {
15-
let cx = &self.cx;
16-
17-
let rustc_middle::mir::TerminatorKind::InlineAsm {
18-
template,
19-
ref operands,
20-
options,
21-
line_spans,
22-
targets: _,
23-
unwind: _,
24-
} = self.mir.basic_blocks.iter().next().unwrap().terminator().kind
25-
else {
26-
bug!("#[naked] functions should always terminate with an asm! block")
27-
};
28-
29-
let operands: Vec<_> =
30-
operands.iter().map(|op| self.inline_to_global_operand(op)).collect();
31-
32-
let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance);
33-
34-
let mut template_vec = Vec::new();
35-
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin));
36-
template_vec.extend(template.iter().cloned());
37-
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end));
38-
39-
cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
40-
}
13+
pub fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
14+
cx: &'a Bx::CodegenCx,
15+
mir: &Body<'tcx>,
16+
instance: Instance<'tcx>,
17+
) {
18+
let rustc_middle::mir::TerminatorKind::InlineAsm {
19+
template,
20+
ref operands,
21+
options,
22+
line_spans,
23+
targets: _,
24+
unwind: _,
25+
} = mir.basic_blocks.iter().next().unwrap().terminator().kind
26+
else {
27+
bug!("#[naked] functions should always terminate with an asm! block")
28+
};
4129

42-
fn inline_to_global_operand(&self, op: &InlineAsmOperand<'tcx>) -> GlobalAsmOperandRef<'tcx> {
43-
match op {
44-
InlineAsmOperand::Const { value } => {
45-
let const_value = self.eval_mir_constant(value);
46-
let string = common::asm_const_to_str(
47-
self.cx.tcx(),
48-
value.span,
49-
const_value,
50-
self.cx.layout_of(value.ty()),
51-
);
52-
GlobalAsmOperandRef::Const { string }
53-
}
54-
InlineAsmOperand::SymFn { value } => {
55-
let instance = match value.ty().kind() {
56-
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
57-
_ => bug!("asm sym is not a function"),
58-
};
30+
let operands: Vec<_> =
31+
operands.iter().map(|op| inline_to_global_operand::<Bx>(cx, instance, op)).collect();
5932

60-
GlobalAsmOperandRef::SymFn { instance }
61-
}
62-
InlineAsmOperand::SymStatic { def_id } => {
63-
GlobalAsmOperandRef::SymStatic { def_id: *def_id }
64-
}
65-
InlineAsmOperand::In { .. }
66-
| InlineAsmOperand::Out { .. }
67-
| InlineAsmOperand::InOut { .. }
68-
| InlineAsmOperand::Label { .. } => {
69-
bug!("invalid operand type for naked_asm!")
70-
}
33+
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
34+
let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance, item_data);
35+
36+
let mut template_vec = Vec::new();
37+
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
38+
template_vec.extend(template.iter().cloned());
39+
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into()));
40+
41+
cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
42+
}
43+
44+
fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
45+
cx: &'a Bx::CodegenCx,
46+
instance: Instance<'tcx>,
47+
op: &InlineAsmOperand<'tcx>,
48+
) -> GlobalAsmOperandRef<'tcx> {
49+
match op {
50+
InlineAsmOperand::Const { value } => {
51+
let const_value = instance
52+
.instantiate_mir_and_normalize_erasing_regions(
53+
cx.tcx(),
54+
ty::ParamEnv::reveal_all(),
55+
ty::EarlyBinder::bind(value.const_),
56+
)
57+
.eval(cx.tcx(), ty::ParamEnv::reveal_all(), value.span)
58+
.expect("erroneous constant missed by mono item collection");
59+
60+
let mono_type = instance.instantiate_mir_and_normalize_erasing_regions(
61+
cx.tcx(),
62+
ty::ParamEnv::reveal_all(),
63+
ty::EarlyBinder::bind(value.ty()),
64+
);
65+
66+
let string = common::asm_const_to_str(
67+
cx.tcx(),
68+
value.span,
69+
const_value,
70+
cx.layout_of(mono_type),
71+
);
72+
73+
GlobalAsmOperandRef::Const { string }
74+
}
75+
InlineAsmOperand::SymFn { value } => {
76+
let mono_type = instance.instantiate_mir_and_normalize_erasing_regions(
77+
cx.tcx(),
78+
ty::ParamEnv::reveal_all(),
79+
ty::EarlyBinder::bind(value.ty()),
80+
);
81+
82+
let instance = match mono_type.kind() {
83+
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
84+
_ => bug!("asm sym is not a function"),
85+
};
86+
87+
GlobalAsmOperandRef::SymFn { instance }
88+
}
89+
InlineAsmOperand::SymStatic { def_id } => {
90+
GlobalAsmOperandRef::SymStatic { def_id: *def_id }
91+
}
92+
InlineAsmOperand::In { .. }
93+
| InlineAsmOperand::Out { .. }
94+
| InlineAsmOperand::InOut { .. }
95+
| InlineAsmOperand::Label { .. } => {
96+
bug!("invalid operand type for naked_asm!")
7197
}
7298
}
7399
}
@@ -90,7 +116,11 @@ impl AsmBinaryFormat {
90116
}
91117
}
92118

93-
fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (String, String) {
119+
fn prefix_and_suffix<'tcx>(
120+
tcx: TyCtxt<'tcx>,
121+
instance: Instance<'tcx>,
122+
item_data: &MonoItemData,
123+
) -> (String, String) {
94124
use std::fmt::Write;
95125

96126
let target = &tcx.sess.target;
@@ -104,24 +134,18 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
104134

105135
let asm_name = format!("{}{}", if mangle { "_" } else { "" }, tcx.symbol_name(instance).name);
106136

107-
let opt_section = tcx
108-
.get_attr(instance.def.def_id(), sym::link_section)
109-
.and_then(|attr| attr.value_str())
110-
.map(|attr| attr.as_str().to_string());
111-
112-
let instruction_set =
113-
tcx.get_attr(instance.def.def_id(), sym::instruction_set).and_then(|attr| attr.value_str());
137+
let attrs = tcx.codegen_fn_attrs(instance.def_id());
138+
let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());
114139

115140
let (arch_prefix, arch_suffix) = if is_arm {
116141
(
117-
match instruction_set {
142+
match attrs.instruction_set {
118143
None => match is_thumb {
119144
true => ".thumb\n.thumb_func",
120145
false => ".arm",
121146
},
122-
Some(sym::a32) => ".arm",
123-
Some(sym::t32) => ".thumb\n.thumb_func",
124-
Some(other) => bug!("invalid instruction set: {other}"),
147+
Some(InstructionSetAttr::ArmA32) => ".arm",
148+
Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func",
125149
},
126150
match is_thumb {
127151
true => ".thumb",
@@ -136,7 +160,7 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
136160
let mut end = String::new();
137161
match AsmBinaryFormat::from_target(&tcx.sess.target) {
138162
AsmBinaryFormat::Elf => {
139-
let section = opt_section.unwrap_or(format!(".text.{asm_name}"));
163+
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
140164

141165
let progbits = match is_arm {
142166
true => "%progbits",
@@ -151,11 +175,10 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
151175
writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
152176
writeln!(begin, ".balign 4").unwrap();
153177
writeln!(begin, ".globl {asm_name}").unwrap();
154-
writeln!(begin, ".hidden {asm_name}").unwrap();
155-
writeln!(begin, ".type {asm_name}, {function}").unwrap();
156-
if let Some(instruction_set) = instruction_set {
157-
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
178+
if let Visibility::Hidden = item_data.visibility {
179+
writeln!(begin, ".hidden {asm_name}").unwrap();
158180
}
181+
writeln!(begin, ".type {asm_name}, {function}").unwrap();
159182
if !arch_prefix.is_empty() {
160183
writeln!(begin, "{}", arch_prefix).unwrap();
161184
}
@@ -169,13 +192,12 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
169192
}
170193
}
171194
AsmBinaryFormat::Macho => {
172-
let section = opt_section.unwrap_or("__TEXT,__text".to_string());
195+
let section = link_section.unwrap_or("__TEXT,__text".to_string());
173196
writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
174197
writeln!(begin, ".balign 4").unwrap();
175198
writeln!(begin, ".globl {asm_name}").unwrap();
176-
writeln!(begin, ".private_extern {asm_name}").unwrap();
177-
if let Some(instruction_set) = instruction_set {
178-
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
199+
if let Visibility::Hidden = item_data.visibility {
200+
writeln!(begin, ".private_extern {asm_name}").unwrap();
179201
}
180202
writeln!(begin, "{asm_name}:").unwrap();
181203

@@ -186,17 +208,14 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
186208
}
187209
}
188210
AsmBinaryFormat::Coff => {
189-
let section = opt_section.unwrap_or(format!(".text.{asm_name}"));
211+
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
190212
writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
191213
writeln!(begin, ".balign 4").unwrap();
192214
writeln!(begin, ".globl {asm_name}").unwrap();
193215
writeln!(begin, ".def {asm_name}").unwrap();
194216
writeln!(begin, ".scl 2").unwrap();
195217
writeln!(begin, ".type 32").unwrap();
196218
writeln!(begin, ".endef {asm_name}").unwrap();
197-
if let Some(instruction_set) = instruction_set {
198-
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
199-
}
200219
writeln!(begin, "{asm_name}:").unwrap();
201220

202221
writeln!(end).unwrap();

compiler/rustc_middle/src/mir/mono.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_span::Span;
1818
use tracing::debug;
1919

2020
use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
21+
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2122
use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt};
2223

2324
/// Describes how a monomorphization will be instantiated in object files.
@@ -118,7 +119,9 @@ impl<'tcx> MonoItem<'tcx> {
118119
let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id);
119120
// If this function isn't inlined or otherwise has an extern
120121
// indicator, then we'll be creating a globally shared version.
121-
if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator()
122+
let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id());
123+
if codegen_fn_attrs.contains_extern_indicator()
124+
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
122125
|| !instance.def.generates_cgu_internal_copy(tcx)
123126
|| Some(instance.def_id()) == entry_def_id
124127
{

0 commit comments

Comments
 (0)