Skip to content

Commit

Permalink
Improve generating Custom entry function
Browse files Browse the repository at this point in the history
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 rust-lang#100316.

Currently, this moves the entry function name and Call convention to the
target spec.

Signed-off-by: Ayush Singh <ayushsingh1325@gmail.com>
  • Loading branch information
Ayush1325 committed Nov 10, 2022
1 parent 5b3e909 commit 9f0a862
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 20 deletions.
40 changes: 23 additions & 17 deletions compiler/rustc_codegen_llvm/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,23 +398,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
}

fn llvm_cconv(&self) -> llvm::CallConv {
match self.conv {
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
Conv::RustCold => llvm::ColdCallConv,
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
Conv::Msp430Intr => llvm::Msp430Intr,
Conv::PtxKernel => llvm::PtxKernel,
Conv::X86Fastcall => llvm::X86FastcallCallConv,
Conv::X86Intr => llvm::X86_Intr,
Conv::X86Stdcall => llvm::X86StdcallCallConv,
Conv::X86ThisCall => llvm::X86_ThisCall,
Conv::X86VectorCall => llvm::X86_VectorCall,
Conv::X86_64SysV => llvm::X86_64_SysV,
Conv::X86_64Win64 => llvm::X86_64_Win64,
}
self.conv.into()
}

fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
Expand Down Expand Up @@ -596,3 +580,25 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
llvm::get_param(self.llfn(), index as c_uint)
}
}

impl From<Conv> for llvm::CallConv {
fn from(conv: Conv) -> Self {
match conv {
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall => llvm::CCallConv,
Conv::RustCold => llvm::ColdCallConv,
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,
Conv::ArmAapcs => llvm::ArmAapcsCallConv,
Conv::Msp430Intr => llvm::Msp430Intr,
Conv::PtxKernel => llvm::PtxKernel,
Conv::X86Fastcall => llvm::X86FastcallCallConv,
Conv::X86Intr => llvm::X86_Intr,
Conv::X86Stdcall => llvm::X86StdcallCallConv,
Conv::X86ThisCall => llvm::X86_ThisCall,
Conv::X86VectorCall => llvm::X86_VectorCall,
Conv::X86_64SysV => llvm::X86_64_SysV,
Conv::X86_64Win64 => llvm::X86_64_Win64,
}
}
}
10 changes: 8 additions & 2 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,8 +570,14 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}

fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
if self.get_declared_value("main").is_none() {
Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
let entry_name = self.sess().target.entry_name.as_ref();
if self.get_declared_value(entry_name).is_none() {
Some(self.declare_entry_fn(
entry_name,
self.sess().target.entry_abi.into(),
llvm::UnnamedAddr::Global,
fn_type,
))
} else {
// If the symbol already exists, it is an error: for example, the user wrote
// #[no_mangle] extern "C" fn main(..) {..}
Expand Down
22 changes: 22 additions & 0 deletions compiler/rustc_codegen_llvm/src/declare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
}

/// Declare an entry Function
///
/// The ABI of this function can change depending on the target (although for now the same as
/// `declare_cfn`)
///
/// If there’s a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
pub fn declare_entry_fn(
&self,
name: &str,
callconv: llvm::CallConv,
unnamed: llvm::UnnamedAddr,
fn_type: &'ll Type,
) -> &'ll Value {
let visibility = if self.tcx.sess.target.default_hidden_visibility {
llvm::Visibility::Hidden
} else {
llvm::Visibility::Default
};
declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type)
}

/// Declare a Rust function.
///
/// If there’s a value with the same name already declared, the function will
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,8 @@ fn exported_symbols_provider_local<'tcx>(
.collect();

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

symbols.push((
exported_symbol,
Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_target/src/abi/call/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
use crate::spec::{self, HasTargetSpec};
use rustc_span::Symbol;
use std::fmt;
use std::str::FromStr;

mod aarch64;
mod amdgpu;
Expand Down Expand Up @@ -735,6 +736,33 @@ impl<'a, Ty> FnAbi<'a, Ty> {
}
}

impl FromStr for Conv {
type Err = String;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"C" => Ok(Conv::C),
"Rust" => Ok(Conv::Rust),
"RustCold" => Ok(Conv::Rust),
"ArmAapcs" => Ok(Conv::ArmAapcs),
"CCmseNonSecureCall" => Ok(Conv::CCmseNonSecureCall),
"Msp430Intr" => Ok(Conv::Msp430Intr),
"PtxKernel" => Ok(Conv::PtxKernel),
"X86Fastcall" => Ok(Conv::X86Fastcall),
"X86Intr" => Ok(Conv::X86Intr),
"X86Stdcall" => Ok(Conv::X86Stdcall),
"X86ThisCall" => Ok(Conv::X86ThisCall),
"X86VectorCall" => Ok(Conv::X86VectorCall),
"X86_64SysV" => Ok(Conv::X86_64SysV),
"X86_64Win64" => Ok(Conv::X86_64Win64),
"AmdGpuKernel" => Ok(Conv::AmdGpuKernel),
"AvrInterrupt" => Ok(Conv::AvrInterrupt),
"AvrNonBlockingInterrupt" => Ok(Conv::AvrNonBlockingInterrupt),
_ => Err(format!("'{}' is not a valid value for entry function call convetion.", s)),
}
}
}

// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
mod size_asserts {
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_target/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,28 @@ impl<A: ToJson> ToJson for Option<A> {
}
}
}

impl ToJson for crate::abi::call::Conv {
fn to_json(&self) -> Json {
let s = match self {
Self::C => "C",
Self::Rust => "Rust",
Self::RustCold => "RustCold",
Self::ArmAapcs => "ArmAapcs",
Self::CCmseNonSecureCall => "CCmseNonSecureCall",
Self::Msp430Intr => "Msp430Intr",
Self::PtxKernel => "PtxKernel",
Self::X86Fastcall => "X86Fastcall",
Self::X86Intr => "X86Intr",
Self::X86Stdcall => "X86Stdcall",
Self::X86ThisCall => "X86ThisCall",
Self::X86VectorCall => "X86VectorCall",
Self::X86_64SysV => "X86_64SysV",
Self::X86_64Win64 => "X86_64Win64",
Self::AmdGpuKernel => "AmdGpuKernel",
Self::AvrInterrupt => "AvrInterrupt",
Self::AvrNonBlockingInterrupt => "AvrNonBlockingInterrupt",
};
Json::String(s.to_owned())
}
}
27 changes: 27 additions & 0 deletions compiler/rustc_target/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
//! the target's settings, though `target-feature` and `link-args` will *add*
//! to the list specified by the target, rather than replace.

use crate::abi::call::Conv;
use crate::abi::Endian;
use crate::json::{Json, ToJson};
use crate::spec::abi::{lookup as lookup_abi, Abi};
Expand Down Expand Up @@ -1668,6 +1669,14 @@ pub struct TargetOptions {
/// Whether the target supports stack canary checks. `true` by default,
/// since this is most common among tier 1 and tier 2 targets.
pub supports_stack_protector: bool,

// The name of entry function.
// Default value is "main"
pub entry_name: StaticCow<str>,

// The ABI of entry function.
// Default value is `Conv::C`, i.e. C call convention
pub entry_abi: Conv,
}

/// Add arguments for the given flavor and also for its "twin" flavors
Expand Down Expand Up @@ -1884,6 +1893,8 @@ impl Default for TargetOptions {
c_enum_min_bits: 32,
generate_arange_section: true,
supports_stack_protector: true,
entry_name: "main".into(),
entry_abi: Conv::C,
}
}
}
Expand Down Expand Up @@ -2401,6 +2412,18 @@ impl Target {
}
}
} );
($key_name:ident, Conv) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|o| o.as_str().and_then(|s| {
match Conv::from_str(s) {
Ok(c) => {
base.$key_name = c;
Some(Ok(()))
}
Err(e) => Some(Err(e))
}
})).unwrap_or(Ok(()))
} );
}

if let Some(j) = obj.remove("target-endian") {
Expand Down Expand Up @@ -2520,6 +2543,8 @@ impl Target {
key!(c_enum_min_bits, u64);
key!(generate_arange_section, bool);
key!(supports_stack_protector, bool);
key!(entry_name);
key!(entry_abi, Conv)?;

if base.is_builtin {
// This can cause unfortunate ICEs later down the line.
Expand Down Expand Up @@ -2770,6 +2795,8 @@ impl ToJson for Target {
target_option_val!(c_enum_min_bits);
target_option_val!(generate_arange_section);
target_option_val!(supports_stack_protector);
target_option_val!(entry_name);
target_option_val!(entry_abi);

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

0 comments on commit 9f0a862

Please sign in to comment.