Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
1696f53
fix: rust-lang/rust#47446
sassman Oct 9, 2024
529aae6
wasi/fs: Improve stopping condition for <ReadDir as Iterator>::next
osiewicz Nov 18, 2024
ec5f41a
Run TLS destructors for wasm32-wasip1-threads
surban Nov 23, 2024
692c19a
Refactor ReadDir into a state machine
osiewicz Nov 26, 2024
f4ab982
chore: Improve doc comments
osiewicz Nov 26, 2024
9142cae
add `LinkageInfo` to keep track of how we figured out the linkage
folkertdev Aug 8, 2024
bdf64e1
squashed changes to inlining and const eval
folkertdev Jul 19, 2024
d67a5c0
test the new global asm output of naked functions
folkertdev Jul 19, 2024
a93192c
add `InstructionSetAttr::as_str` and make the type `Copy`
folkertdev Jul 20, 2024
49a297a
squashed changes to tests
folkertdev Jul 20, 2024
589ebb8
make naked functions always have external linkage *in LLVM*. If we do…
folkertdev Jul 26, 2024
2e24cdb
squashed changes:
folkertdev Aug 11, 2024
64420b6
skip `predefine_fn` for naked functions
folkertdev Nov 30, 2024
cf738f6
Revert "add `LinkageInfo` to keep track of how we figured out the lin…
folkertdev Nov 30, 2024
868668e
Run `cargo update` and update licenses
clubby789 Nov 25, 2024
4fe15b0
Use UNIX thread_local implementation for WASI.
surban Dec 3, 2024
30847eb
use vendor sources by default on dist tarballs
onur-ozkan Dec 4, 2024
a6aaef1
update `build.vendor` documentation
onur-ozkan Dec 4, 2024
9ca9b41
add a change entry for new default on `build.vendor`
onur-ozkan Dec 4, 2024
e4092bd
Fix compilation for wasm32-wasip1 (without threads).
surban Dec 5, 2024
4f16640
Add libc funcitons only for wasm32-wasip1-threads.
surban Dec 5, 2024
ac815ff
coverage: Prefer to visit nodes whose predecessors have been visited
Zalathar Dec 5, 2024
f3f7c20
coverage: Move `CoverageIdsInfo` into `mir::coverage`
Zalathar Dec 6, 2024
2022ef7
coverage: Use a query to find counters/expressions that must be zero
Zalathar Dec 6, 2024
4d2bfec
coverage: Remove FunctionCoverageCollector
Zalathar Dec 6, 2024
3a35fb6
coverage: Unused functions don't need to store `CoverageIdsInfo`
Zalathar Dec 8, 2024
9eb35a0
fix the `naked-asan` test
folkertdev Dec 1, 2024
2d8a871
Downgrade cc
clubby789 Dec 8, 2024
4f14890
Configure renovatebot
Kobzol Dec 9, 2024
ed8ee39
fix ICE on type error in promoted
RalfJung Dec 7, 2024
a9fc2e2
Add feature gate, not working yet
compiler-errors Nov 16, 2024
7951d19
Apply suggestions from code review
sassman Dec 9, 2024
3511a46
Implement projection and shim for AFIDT
compiler-errors Nov 16, 2024
b02fcc5
Rollup merge of #128004 - folkertdev:naked-fn-asm, r=Amanieu
fmease Dec 9, 2024
35fc15b
Rollup merge of #131558 - sassman:feat/warnin-for-no-mangle-together-…
fmease Dec 9, 2024
d0f329a
Rollup merge of #133122 - compiler-errors:afidt, r=oli-obk
fmease Dec 9, 2024
00a7584
Rollup merge of #133184 - osiewicz:wasm-fix-infinite-loop-in-remove-d…
fmease Dec 9, 2024
18419d0
Rollup merge of #133456 - clubby789:cargo-update, r=ChrisDenton
fmease Dec 9, 2024
2b252ba
Rollup merge of #133472 - rust-wasi-web:master, r=joboet
fmease Dec 9, 2024
0c87c3c
Rollup merge of #133853 - onur-ozkan:use-vendor-directory-on-dist-bui…
fmease Dec 9, 2024
69889fa
Rollup merge of #133946 - Zalathar:ready-first, r=oli-obk
fmease Dec 9, 2024
65e8897
Rollup merge of #134010 - RalfJung:promoted-type-error-ice, r=oli-obk
fmease Dec 9, 2024
ce27319
Rollup merge of #134029 - Zalathar:zero, r=oli-obk
fmease Dec 9, 2024
d5b0698
Rollup merge of #134071 - Kobzol:ci-renovatebot, r=MarcoIeni
fmease Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
squashed changes to tests
correctly emit `.hidden`

this test was added in #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 #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
  • Loading branch information
folkertdev committed Nov 29, 2024
commit 49a297ab211affaf782cc7603bc413cb8e1ab715
14 changes: 3 additions & 11 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,17 +395,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(
to_add.push(MemoryEffects::None.create_attr(cx.llcx));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
// HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions.
// And it is a module-level attribute, so the alternative is pulling naked functions into
// new LLVM modules. Otherwise LLVM's "naked" functions come with endbr prefixes per
// https://github.com/rust-lang/rust/issues/98768
to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
if llvm_util::get_version() < (19, 0, 0) {
// Prior to LLVM 19, branch-target-enforcement was disabled by setting the attribute to
// the string "false". Now it is disabled by absence of the attribute.
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
}
// do nothing; a naked function is converted into an extern function
// and a global assembly block. LLVM's support for naked functions is
// not used.
} else {
// Do not set sanitizer attributes for naked functions.
to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize));
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_codegen_llvm/src/mono_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
Expand Down Expand Up @@ -58,8 +59,15 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> {

let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
llvm::set_linkage(lldecl, base::linkage_to_llvm(linkage));
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
let llvm_linkage =
if attrs.flags.contains(CodegenFnAttrFlags::NAKED) && linkage == Linkage::Internal {
// this is effectively an extern fn, and must have external linkage
llvm::Linkage::ExternalLinkage
} else {
base::linkage_to_llvm(linkage)
};
llvm::set_linkage(lldecl, llvm_linkage);
base::set_link_section(lldecl, attrs);
if (linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR)
&& self.tcx.sess.target.supports_comdat()
Expand Down
20 changes: 8 additions & 12 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
sym::rustc_allocator_zeroed => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
}
sym::naked => {
// this attribute is ignored during codegen, because a function marked as naked is
// turned into a global asm block.
}
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
sym::no_mangle => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE
Expand Down Expand Up @@ -545,6 +542,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
});

// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
// but not for the code generation backend because at that point the naked function will just be
// a declaration, with a definition provided in global assembly.
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
codegen_fn_attrs.inline = InlineAttr::Never;
}

codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| {
if !attr.has_name(sym::optimize) {
return ia;
Expand Down Expand Up @@ -629,14 +633,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}

if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
// naked functions are generated using an extern function and global assembly. To
// make sure that these can be linked together by LLVM, the linkage should be external,
// unless the user explicitly configured something else (in which case any linker errors
// they encounter are their responsibility).
codegen_fn_attrs.linkage = codegen_fn_attrs.linkage.or(Some(Linkage::External));
}

// Weak lang items have the same semantics as "std internal" symbols in the
// sense that they're preserved through all our LTO passes and only
// strippable by the linker.
Expand Down
25 changes: 2 additions & 23 deletions compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,29 +177,8 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
debug!("fn_abi: {:?}", fn_abi);

if cx.tcx().has_attr(instance.def.def_id(), rustc_span::sym::naked) {
let cached_llbbs = IndexVec::new();

let fx: FunctionCx<'_, '_, Bx> = FunctionCx {
instance,
mir,
llfn,
fn_abi,
cx,
personality_slot: None,
cached_llbbs,
unreachable_block: None,
terminate_block: None,
cleanup_kinds: None,
landing_pads: IndexVec::from_elem(None, &mir.basic_blocks),
funclets: IndexVec::from_fn_n(|_| None, mir.basic_blocks.len()),
locals: locals::Locals::empty(),
debug_context: None,
per_local_var_debug_info: None,
caller_location: None,
};

fx.codegen_naked_asm(instance);
if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance);
return;
}

Expand Down
200 changes: 109 additions & 91 deletions compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,99 @@
use crate::common;
use crate::mir::FunctionCx;
use crate::traits::{AsmMethods, BuilderMethods, GlobalAsmOperandRef};
use rustc_middle::bug;
use rustc_middle::mir::InlineAsmOperand;
use rustc_middle::ty;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_attr::InstructionSetAttr;
use rustc_middle::mir::mono::{MonoItem, MonoItemData, Visibility};
use rustc_middle::mir::{Body, InlineAsmOperand};
use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf};
use rustc_middle::ty::{Instance, TyCtxt};

use rustc_span::sym;
use rustc_middle::{bug, ty};
use rustc_target::asm::InlineAsmArch;

impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn codegen_naked_asm(&self, instance: Instance<'tcx>) {
let cx = &self.cx;

let rustc_middle::mir::TerminatorKind::InlineAsm {
asm_macro: _,
template,
ref operands,
options,
line_spans,
targets: _,
unwind: _,
} = self.mir.basic_blocks.iter().next().unwrap().terminator().kind
else {
bug!("#[naked] functions should always terminate with an asm! block")
};

let operands: Vec<_> =
operands.iter().map(|op| self.inline_to_global_operand(op)).collect();

let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance);

let mut template_vec = Vec::new();
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin));
template_vec.extend(template.iter().cloned());
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end));

cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
}
use crate::common;
use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods};

pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
mir: &Body<'tcx>,
instance: Instance<'tcx>,
) {
let rustc_middle::mir::TerminatorKind::InlineAsm {
asm_macro: _,
template,
ref operands,
options,
line_spans,
targets: _,
unwind: _,
} = mir.basic_blocks.iter().next().unwrap().terminator().kind
else {
bug!("#[naked] functions should always terminate with an asm! block")
};

fn inline_to_global_operand(&self, op: &InlineAsmOperand<'tcx>) -> GlobalAsmOperandRef<'tcx> {
match op {
InlineAsmOperand::Const { value } => {
let const_value = self.eval_mir_constant(value);
let string = common::asm_const_to_str(
self.cx.tcx(),
value.span,
const_value,
self.cx.layout_of(value.ty()),
);
GlobalAsmOperandRef::Const { string }
}
InlineAsmOperand::SymFn { value } => {
let instance = match value.ty().kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
_ => bug!("asm sym is not a function"),
};
let operands: Vec<_> =
operands.iter().map(|op| inline_to_global_operand::<Bx>(cx, instance, op)).collect();

GlobalAsmOperandRef::SymFn { instance }
}
InlineAsmOperand::SymStatic { def_id } => {
GlobalAsmOperandRef::SymStatic { def_id: *def_id }
}
InlineAsmOperand::In { .. }
| InlineAsmOperand::Out { .. }
| InlineAsmOperand::InOut { .. }
| InlineAsmOperand::Label { .. } => {
bug!("invalid operand type for naked_asm!")
}
let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap();
let (begin, end) = crate::mir::naked_asm::prefix_and_suffix(cx.tcx(), instance, item_data);

let mut template_vec = Vec::new();
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into()));
template_vec.extend(template.iter().cloned());
template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into()));

cx.codegen_global_asm(&template_vec, &operands, options, line_spans);
}

fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
instance: Instance<'tcx>,
op: &InlineAsmOperand<'tcx>,
) -> GlobalAsmOperandRef<'tcx> {
match op {
InlineAsmOperand::Const { value } => {
let const_value = instance
.instantiate_mir_and_normalize_erasing_regions(
cx.tcx(),
cx.typing_env(),
ty::EarlyBinder::bind(value.const_),
)
.eval(cx.tcx(), cx.typing_env(), value.span)
.expect("erroneous constant missed by mono item collection");

let mono_type = instance.instantiate_mir_and_normalize_erasing_regions(
cx.tcx(),
cx.typing_env(),
ty::EarlyBinder::bind(value.ty()),
);

let string = common::asm_const_to_str(
cx.tcx(),
value.span,
const_value,
cx.layout_of(mono_type),
);

GlobalAsmOperandRef::Const { string }
}
InlineAsmOperand::SymFn { value } => {
let mono_type = instance.instantiate_mir_and_normalize_erasing_regions(
cx.tcx(),
cx.typing_env(),
ty::EarlyBinder::bind(value.ty()),
);

let instance = match mono_type.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
_ => bug!("asm sym is not a function"),
};

GlobalAsmOperandRef::SymFn { instance }
}
InlineAsmOperand::SymStatic { def_id } => {
GlobalAsmOperandRef::SymStatic { def_id: *def_id }
}
InlineAsmOperand::In { .. }
| InlineAsmOperand::Out { .. }
| InlineAsmOperand::InOut { .. }
| InlineAsmOperand::Label { .. } => {
bug!("invalid operand type for naked_asm!")
}
}
}
Expand All @@ -91,7 +116,11 @@ impl AsmBinaryFormat {
}
}

fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (String, String) {
fn prefix_and_suffix<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
item_data: &MonoItemData,
) -> (String, String) {
use std::fmt::Write;

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

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

let opt_section = tcx
.get_attr(instance.def.def_id(), sym::link_section)
.and_then(|attr| attr.value_str())
.map(|attr| attr.as_str().to_string());

let instruction_set =
tcx.get_attr(instance.def.def_id(), sym::instruction_set).and_then(|attr| attr.value_str());
let attrs = tcx.codegen_fn_attrs(instance.def_id());
let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string());

let (arch_prefix, arch_suffix) = if is_arm {
(
match instruction_set {
match attrs.instruction_set {
None => match is_thumb {
true => ".thumb\n.thumb_func",
false => ".arm",
},
Some(sym::a32) => ".arm",
Some(sym::t32) => ".thumb\n.thumb_func",
Some(other) => bug!("invalid instruction set: {other}"),
Some(InstructionSetAttr::ArmA32) => ".arm",
Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func",
},
match is_thumb {
true => ".thumb",
Expand All @@ -137,7 +160,7 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
let mut end = String::new();
match AsmBinaryFormat::from_target(&tcx.sess.target) {
AsmBinaryFormat::Elf => {
let section = opt_section.unwrap_or(format!(".text.{asm_name}"));
let section = link_section.unwrap_or(format!(".text.{asm_name}"));

let progbits = match is_arm {
true => "%progbits",
Expand All @@ -152,11 +175,10 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap();
writeln!(begin, ".balign 4").unwrap();
writeln!(begin, ".globl {asm_name}").unwrap();
writeln!(begin, ".hidden {asm_name}").unwrap();
writeln!(begin, ".type {asm_name}, {function}").unwrap();
if let Some(instruction_set) = instruction_set {
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
if let Visibility::Hidden = item_data.visibility {
writeln!(begin, ".hidden {asm_name}").unwrap();
}
writeln!(begin, ".type {asm_name}, {function}").unwrap();
if !arch_prefix.is_empty() {
writeln!(begin, "{}", arch_prefix).unwrap();
}
Expand All @@ -170,13 +192,12 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
}
}
AsmBinaryFormat::Macho => {
let section = opt_section.unwrap_or("__TEXT,__text".to_string());
let section = link_section.unwrap_or("__TEXT,__text".to_string());
writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap();
writeln!(begin, ".balign 4").unwrap();
writeln!(begin, ".globl {asm_name}").unwrap();
writeln!(begin, ".private_extern {asm_name}").unwrap();
if let Some(instruction_set) = instruction_set {
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
if let Visibility::Hidden = item_data.visibility {
writeln!(begin, ".private_extern {asm_name}").unwrap();
}
writeln!(begin, "{asm_name}:").unwrap();

Expand All @@ -187,17 +208,14 @@ fn prefix_and_suffix<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> (Stri
}
}
AsmBinaryFormat::Coff => {
let section = opt_section.unwrap_or(format!(".text.{asm_name}"));
let section = link_section.unwrap_or(format!(".text.{asm_name}"));
writeln!(begin, ".pushsection {},\"xr\"", section).unwrap();
writeln!(begin, ".balign 4").unwrap();
writeln!(begin, ".globl {asm_name}").unwrap();
writeln!(begin, ".def {asm_name}").unwrap();
writeln!(begin, ".scl 2").unwrap();
writeln!(begin, ".type 32").unwrap();
writeln!(begin, ".endef {asm_name}").unwrap();
if let Some(instruction_set) = instruction_set {
writeln!(begin, "{}", instruction_set.as_str()).unwrap();
}
writeln!(begin, "{asm_name}:").unwrap();

writeln!(end).unwrap();
Expand Down
Loading