Skip to content

Commit 9f0a862

Browse files
committed
Improve generating Custom entry function
This commit is aimed at making compiler generated entry functions (Basically just C `main` right now) more generic so other targets can do similar things for custom entry. This was initially implemented as part of #100316. Currently, this moves the entry function name and Call convention to the target spec. Signed-off-by: Ayush Singh <[email protected]>
1 parent 5b3e909 commit 9f0a862

File tree

7 files changed

+135
-20
lines changed

7 files changed

+135
-20
lines changed

compiler/rustc_codegen_llvm/src/abi.rs

+23-17
Original file line numberDiff line numberDiff line change
@@ -398,23 +398,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
398398
}
399399

400400
fn llvm_cconv(&self) -> llvm::CallConv {
401-
match self.conv {
402-
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
403-
Conv::RustCold => llvm::ColdCallConv,
404-
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
405-
Conv::AvrInterrupt => llvm::AvrInterrupt,
406-
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
407-
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
408-
Conv::Msp430Intr => llvm::Msp430Intr,
409-
Conv::PtxKernel => llvm::PtxKernel,
410-
Conv::X86Fastcall => llvm::X86FastcallCallConv,
411-
Conv::X86Intr => llvm::X86_Intr,
412-
Conv::X86Stdcall => llvm::X86StdcallCallConv,
413-
Conv::X86ThisCall => llvm::X86_ThisCall,
414-
Conv::X86VectorCall => llvm::X86_VectorCall,
415-
Conv::X86_64SysV => llvm::X86_64_SysV,
416-
Conv::X86_64Win64 => llvm::X86_64_Win64,
417-
}
401+
self.conv.into()
418402
}
419403

420404
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
@@ -596,3 +580,25 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
596580
llvm::get_param(self.llfn(), index as c_uint)
597581
}
598582
}
583+
584+
impl From<Conv> for llvm::CallConv {
585+
fn from(conv: Conv) -> Self {
586+
match conv {
587+
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
588+
Conv::RustCold => llvm::ColdCallConv,
589+
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
590+
Conv::AvrInterrupt => llvm::AvrInterrupt,
591+
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
592+
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
593+
Conv::Msp430Intr => llvm::Msp430Intr,
594+
Conv::PtxKernel => llvm::PtxKernel,
595+
Conv::X86Fastcall => llvm::X86FastcallCallConv,
596+
Conv::X86Intr => llvm::X86_Intr,
597+
Conv::X86Stdcall => llvm::X86StdcallCallConv,
598+
Conv::X86ThisCall => llvm::X86_ThisCall,
599+
Conv::X86VectorCall => llvm::X86_VectorCall,
600+
Conv::X86_64SysV => llvm::X86_64_SysV,
601+
Conv::X86_64Win64 => llvm::X86_64_Win64,
602+
}
603+
}
604+
}

compiler/rustc_codegen_llvm/src/context.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,14 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
570570
}
571571

572572
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
573-
if self.get_declared_value("main").is_none() {
574-
Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
573+
let entry_name = self.sess().target.entry_name.as_ref();
574+
if self.get_declared_value(entry_name).is_none() {
575+
Some(self.declare_entry_fn(
576+
entry_name,
577+
self.sess().target.entry_abi.into(),
578+
llvm::UnnamedAddr::Global,
579+
fn_type,
580+
))
575581
} else {
576582
// If the symbol already exists, it is an error: for example, the user wrote
577583
// #[no_mangle] extern "C" fn main(..) {..}

compiler/rustc_codegen_llvm/src/declare.rs

+22
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
9090
declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
9191
}
9292

93+
/// Declare an entry Function
94+
///
95+
/// The ABI of this function can change depending on the target (although for now the same as
96+
/// `declare_cfn`)
97+
///
98+
/// If there’s a value with the same name already declared, the function will
99+
/// update the declaration and return existing Value instead.
100+
pub fn declare_entry_fn(
101+
&self,
102+
name: &str,
103+
callconv: llvm::CallConv,
104+
unnamed: llvm::UnnamedAddr,
105+
fn_type: &'ll Type,
106+
) -> &'ll Value {
107+
let visibility = if self.tcx.sess.target.default_hidden_visibility {
108+
llvm::Visibility::Hidden
109+
} else {
110+
llvm::Visibility::Default
111+
};
112+
declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
113+
}
114+
93115
/// Declare a Rust function.
94116
///
95117
/// If there’s a value with the same name already declared, the function will

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ fn exported_symbols_provider_local<'tcx>(
180180
.collect();
181181

182182
if tcx.entry_fn(()).is_some() {
183-
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, "main"));
183+
let exported_symbol =
184+
ExportedSymbol::NoDefId(SymbolName::new(tcx, tcx.sess.target.entry_name.as_ref()));
184185

185186
symbols.push((
186187
exported_symbol,

compiler/rustc_target/src/abi/call/mod.rs

+28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
33
use crate::spec::{self, HasTargetSpec};
44
use rustc_span::Symbol;
55
use std::fmt;
6+
use std::str::FromStr;
67

78
mod aarch64;
89
mod amdgpu;
@@ -735,6 +736,33 @@ impl<'a, Ty> FnAbi<'a, Ty> {
735736
}
736737
}
737738

739+
impl FromStr for Conv {
740+
type Err = String;
741+
742+
fn from_str(s: &str) -> Result<Self, Self::Err> {
743+
match s {
744+
"C" => Ok(Conv::C),
745+
"Rust" => Ok(Conv::Rust),
746+
"RustCold" => Ok(Conv::Rust),
747+
"ArmAapcs" => Ok(Conv::ArmAapcs),
748+
"CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall),
749+
"Msp430Intr" => Ok(Conv::Msp430Intr),
750+
"PtxKernel" => Ok(Conv::PtxKernel),
751+
"X86Fastcall" => Ok(Conv::X86Fastcall),
752+
"X86Intr" => Ok(Conv::X86Intr),
753+
"X86Stdcall" => Ok(Conv::X86Stdcall),
754+
"X86ThisCall" => Ok(Conv::X86ThisCall),
755+
"X86VectorCall" => Ok(Conv::X86VectorCall),
756+
"X86_64SysV" => Ok(Conv::X86_64SysV),
757+
"X86_64Win64" => Ok(Conv::X86_64Win64),
758+
"AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
759+
"AvrInterrupt" => Ok(Conv::AvrInterrupt),
760+
"AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
761+
_ => Err(format!("'{}' is not a valid value for entry function call convetion.", s)),
762+
}
763+
}
764+
}
765+
738766
// Some types are used a lot. Make sure they don't unintentionally get bigger.
739767
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
740768
mod size_asserts {

compiler/rustc_target/src/json.rs

+25
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,28 @@ impl<A: ToJson> ToJson for Option<A> {
8989
}
9090
}
9191
}
92+
93+
impl ToJson for crate::abi::call::Conv {
94+
fn to_json(&self) -> Json {
95+
let s = match self {
96+
Self::C => "C",
97+
Self::Rust => "Rust",
98+
Self::RustCold => "RustCold",
99+
Self::ArmAapcs => "ArmAapcs",
100+
Self::CCmseNonSecureCall => "CCmseNonSecureCall",
101+
Self::Msp430Intr => "Msp430Intr",
102+
Self::PtxKernel => "PtxKernel",
103+
Self::X86Fastcall => "X86Fastcall",
104+
Self::X86Intr => "X86Intr",
105+
Self::X86Stdcall => "X86Stdcall",
106+
Self::X86ThisCall => "X86ThisCall",
107+
Self::X86VectorCall => "X86VectorCall",
108+
Self::X86_64SysV => "X86_64SysV",
109+
Self::X86_64Win64 => "X86_64Win64",
110+
Self::AmdGpuKernel => "AmdGpuKernel",
111+
Self::AvrInterrupt => "AvrInterrupt",
112+
Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt",
113+
};
114+
Json::String(s.to_owned())
115+
}
116+
}

compiler/rustc_target/src/spec/mod.rs

+27
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
//! the target's settings, though `target-feature` and `link-args` will *add*
3535
//! to the list specified by the target, rather than replace.
3636
37+
use crate::abi::call::Conv;
3738
use crate::abi::Endian;
3839
use crate::json::{Json, ToJson};
3940
use crate::spec::abi::{lookup as lookup_abi, Abi};
@@ -1668,6 +1669,14 @@ pub struct TargetOptions {
16681669
/// Whether the target supports stack canary checks. `true` by default,
16691670
/// since this is most common among tier 1 and tier 2 targets.
16701671
pub supports_stack_protector: bool,
1672+
1673+
// The name of entry function.
1674+
// Default value is "main"
1675+
pub entry_name: StaticCow<str>,
1676+
1677+
// The ABI of entry function.
1678+
// Default value is `Conv::C`, i.e. C call convention
1679+
pub entry_abi: Conv,
16711680
}
16721681

16731682
/// Add arguments for the given flavor and also for its "twin" flavors
@@ -1884,6 +1893,8 @@ impl Default for TargetOptions {
18841893
c_enum_min_bits: 32,
18851894
generate_arange_section: true,
18861895
supports_stack_protector: true,
1896+
entry_name: "main".into(),
1897+
entry_abi: Conv::C,
18871898
}
18881899
}
18891900
}
@@ -2401,6 +2412,18 @@ impl Target {
24012412
}
24022413
}
24032414
} );
2415+
($key_name:ident, Conv) => ( {
2416+
let name = (stringify!($key_name)).replace("_", "-");
2417+
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
2418+
match Conv::from_str(s) {
2419+
Ok(c) => {
2420+
base.$key_name = c;
2421+
Some(Ok(()))
2422+
}
2423+
Err(e) => Some(Err(e))
2424+
}
2425+
})).unwrap_or(Ok(()))
2426+
} );
24042427
}
24052428

24062429
if let Some(j) = obj.remove("target-endian") {
@@ -2520,6 +2543,8 @@ impl Target {
25202543
key!(c_enum_min_bits, u64);
25212544
key!(generate_arange_section, bool);
25222545
key!(supports_stack_protector, bool);
2546+
key!(entry_name);
2547+
key!(entry_abi, Conv)?;
25232548

25242549
if base.is_builtin {
25252550
// This can cause unfortunate ICEs later down the line.
@@ -2770,6 +2795,8 @@ impl ToJson for Target {
27702795
target_option_val!(c_enum_min_bits);
27712796
target_option_val!(generate_arange_section);
27722797
target_option_val!(supports_stack_protector);
2798+
target_option_val!(entry_name);
2799+
target_option_val!(entry_abi);
27732800

27742801
if let Some(abi) = self.default_adjusted_cabi {
27752802
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());

0 commit comments

Comments
 (0)