Skip to content

Commit 20012cc

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 7ebfe9e commit 20012cc

File tree

11 files changed

+417
-181
lines changed

11 files changed

+417
-181
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() {
@@ -544,6 +548,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
544548
}
545549
});
546550

551+
// naked function MUST NOT be inlined!
552+
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
553+
codegen_fn_attrs.inline = InlineAttr::Never;
554+
}
555+
547556
codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
548557
if !attr.has_name(sym::optimize) {
549558
return ia;
@@ -628,14 +637,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
628637
}
629638
}
630639

631-
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
632-
// naked functions are generated using an extern function and global assembly. To
633-
// make sure that these can be linked together by LLVM, the linkage should be external,
634-
// unless the user explicitly configured something else (in which case any linker errors
635-
// they encounter are their responsibility).
636-
codegen_fn_attrs.linkage = codegen_fn_attrs.linkage.or(Some(Linkage::External));
637-
}
638-
639640
// Weak lang items have the same semantics as "std internal" symbols in the
640641
// sense that they're preserved through all our LTO passes and only
641642
// strippable by the linker.

compiler/rustc_codegen_ssa/src/mir/mod.rs

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

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

compiler/rustc_codegen_ssa/src/mir/naked_asm.rs

+105-86
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,100 @@
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-
asm_macro: _,
19-
template,
20-
ref operands,
21-
options,
22-
line_spans,
23-
targets: _,
24-
unwind: _,
25-
} = self.mir.basic_blocks.iter().next().unwrap().terminator().kind
26-
else {
27-
bug!("#[naked] functions should always terminate with an asm! block")
28-
};
29-
30-
let operands: Vec<_> =
31-
operands.iter().map(|op| self.inline_to_global_operand(op)).collect();
32-
33-
let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance);
34-
35-
let mut template_vec = Vec::new();
36-
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin));
37-
template_vec.extend(template.iter().cloned());
38-
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end));
39-
40-
cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
41-
}
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+
asm_macro: _,
20+
template,
21+
ref operands,
22+
options,
23+
line_spans,
24+
targets: _,
25+
unwind: _,
26+
} = mir.basic_blocks.iter().next().unwrap().terminator().kind
27+
else {
28+
bug!("#[naked] functions should always terminate with an asm! block")
29+
};
4230

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

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

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

97127
let target = &tcx.sess.target;
@@ -105,24 +135,18 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
105135

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

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

116141
let (arch_prefix, arch_suffix) = if is_arm {
117142
(
118-
match instruction_set {
143+
match attrs.instruction_set {
119144
None => match is_thumb {
120145
true => ".thumb\n.thumb_func",
121146
false => ".arm",
122147
},
123-
Some(sym::a32) => ".arm",
124-
Some(sym::t32) => ".thumb\n.thumb_func",
125-
Some(other) => bug!("invalid instruction set: {other}"),
148+
Some(InstructionSetAttr::ArmA32) => ".arm",
149+
Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func",
126150
},
127151
match is_thumb {
128152
true => ".thumb",
@@ -137,7 +161,7 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
137161
let mut end = String::new();
138162
match AsmBinaryFormat::from_target(&tcx.sess.target) {
139163
AsmBinaryFormat::Elf => {
140-
let section = opt_section.unwrap_or(format!(".text.{asm_name}"));
164+
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
141165

142166
let progbits = match is_arm {
143167
true => "%progbits",
@@ -152,11 +176,10 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
152176
writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
153177
writeln!(begin, ".balign 4").unwrap();
154178
writeln!(begin, ".globl {asm_name}").unwrap();
155-
writeln!(begin, ".hidden {asm_name}").unwrap();
156-
writeln!(begin, ".type {asm_name}, {function}").unwrap();
157-
if let Some(instruction_set) = instruction_set {
158-
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
179+
if let Visibility::Hidden = item_data.visibility {
180+
writeln!(begin, ".hidden {asm_name}").unwrap();
159181
}
182+
writeln!(begin, ".type {asm_name}, {function}").unwrap();
160183
if !arch_prefix.is_empty() {
161184
writeln!(begin, "{}", arch_prefix).unwrap();
162185
}
@@ -170,13 +193,12 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
170193
}
171194
}
172195
AsmBinaryFormat::Macho => {
173-
let section = opt_section.unwrap_or("__TEXT,__text".to_string());
196+
let section = link_section.unwrap_or("__TEXT,__text".to_string());
174197
writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
175198
writeln!(begin, ".balign 4").unwrap();
176199
writeln!(begin, ".globl {asm_name}").unwrap();
177-
writeln!(begin, ".private_extern {asm_name}").unwrap();
178-
if let Some(instruction_set) = instruction_set {
179-
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
200+
if let Visibility::Hidden = item_data.visibility {
201+
writeln!(begin, ".private_extern {asm_name}").unwrap();
180202
}
181203
writeln!(begin, "{asm_name}:").unwrap();
182204

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

203222
writeln!(end).unwrap();

compiler/rustc_middle/src/mir/mono.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_target::spec::SymbolVisibility;
1919
use tracing::debug;
2020

2121
use crate::dep_graph::{DepNode, WorkProduct, WorkProductId};
22+
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
2223
use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt};
2324

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

0 commit comments

Comments
 (0)