Rollup merge of #104001 - Ayush1325:custom-entry, r=bjorn3
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 https://github.com/rust-lang/rust/pull/100316. Currently, this moves the entry function name and Call convention to the target spec. Signed-off-by: Ayush Singh <ayushsingh1325@gmail.com>
This commit is contained in:
commit
aeeac5dd0c
@ -22,7 +22,19 @@ fn clif_sig_from_fn_abi<'tcx>(
|
|||||||
default_call_conv: CallConv,
|
default_call_conv: CallConv,
|
||||||
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
|
||||||
) -> Signature {
|
) -> Signature {
|
||||||
let call_conv = match fn_abi.conv {
|
let call_conv = conv_to_call_conv(fn_abi.conv, default_call_conv);
|
||||||
|
|
||||||
|
let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
|
||||||
|
|
||||||
|
let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
|
||||||
|
// Sometimes the first param is an pointer to the place where the return value needs to be stored.
|
||||||
|
let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect();
|
||||||
|
|
||||||
|
Signature { params, returns, call_conv }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallConv {
|
||||||
|
match c {
|
||||||
Conv::Rust | Conv::C => default_call_conv,
|
Conv::Rust | Conv::C => default_call_conv,
|
||||||
Conv::RustCold => CallConv::Cold,
|
Conv::RustCold => CallConv::Cold,
|
||||||
Conv::X86_64SysV => CallConv::SystemV,
|
Conv::X86_64SysV => CallConv::SystemV,
|
||||||
@ -38,15 +50,8 @@ fn clif_sig_from_fn_abi<'tcx>(
|
|||||||
| Conv::X86VectorCall
|
| Conv::X86VectorCall
|
||||||
| Conv::AmdGpuKernel
|
| Conv::AmdGpuKernel
|
||||||
| Conv::AvrInterrupt
|
| Conv::AvrInterrupt
|
||||||
| Conv::AvrNonBlockingInterrupt => todo!("{:?}", fn_abi.conv),
|
| Conv::AvrNonBlockingInterrupt => todo!("{:?}", c),
|
||||||
};
|
}
|
||||||
let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
|
|
||||||
|
|
||||||
let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
|
|
||||||
// Sometimes the first param is an pointer to the place where the return value needs to be stored.
|
|
||||||
let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect();
|
|
||||||
|
|
||||||
Signature { params, returns, call_conv }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_function_sig<'tcx>(
|
pub(crate) fn get_function_sig<'tcx>(
|
||||||
|
@ -63,10 +63,14 @@ pub(crate) fn maybe_create_entry_wrapper(
|
|||||||
AbiParam::new(m.target_config().pointer_type()),
|
AbiParam::new(m.target_config().pointer_type()),
|
||||||
],
|
],
|
||||||
returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
|
returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
|
||||||
call_conv: CallConv::triple_default(m.isa().triple()),
|
call_conv: crate::conv_to_call_conv(
|
||||||
|
tcx.sess.target.options.entry_abi,
|
||||||
|
CallConv::triple_default(m.isa().triple()),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
let cmain_func_id = m.declare_function("main", Linkage::Export, &cmain_sig).unwrap();
|
let entry_name = tcx.sess.target.options.entry_name.as_ref();
|
||||||
|
let cmain_func_id = m.declare_function(entry_name, Linkage::Export, &cmain_sig).unwrap();
|
||||||
|
|
||||||
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
|
||||||
|
|
||||||
|
@ -425,8 +425,9 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
||||||
if self.get_declared_value("main").is_none() {
|
let entry_name = self.sess().target.entry_name.as_ref();
|
||||||
Some(self.declare_cfn("main", fn_type))
|
if self.get_declared_value(entry_name).is_none() {
|
||||||
|
Some(self.declare_entry_fn(entry_name, fn_type, ()))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If the symbol already exists, it is an error: for example, the user wrote
|
// If the symbol already exists, it is an error: for example, the user wrote
|
||||||
|
@ -65,13 +65,13 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
|||||||
global
|
global
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> {
|
pub fn declare_entry_fn(&self, name: &str, _fn_type: Type<'gcc>, callconv: () /*llvm::CCallConv*/) -> RValue<'gcc> {
|
||||||
// TODO(antoyo): use the fn_type parameter.
|
// TODO(antoyo): use the fn_type parameter.
|
||||||
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
|
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
|
||||||
let return_type = self.type_i32();
|
let return_type = self.type_i32();
|
||||||
let variadic = false;
|
let variadic = false;
|
||||||
self.linkage.set(FunctionType::Exported);
|
self.linkage.set(FunctionType::Exported);
|
||||||
let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
|
let func = declare_raw_fn(self, name, callconv, return_type, &[self.type_i32(), const_string], variadic);
|
||||||
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
|
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
|
||||||
// for the main function.
|
// for the main function.
|
||||||
*self.current_func.borrow_mut() = Some(func);
|
*self.current_func.borrow_mut() = Some(func);
|
||||||
|
@ -398,23 +398,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn llvm_cconv(&self) -> llvm::CallConv {
|
fn llvm_cconv(&self) -> llvm::CallConv {
|
||||||
match self.conv {
|
self.conv.into()
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
|
fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
|
||||||
@ -596,3 +580,25 @@ impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> {
|
|||||||
llvm::get_param(self.llfn(), index as c_uint)
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -576,8 +576,14 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
|
||||||
if self.get_declared_value("main").is_none() {
|
let entry_name = self.sess().target.entry_name.as_ref();
|
||||||
Some(self.declare_cfn("main", llvm::UnnamedAddr::Global, fn_type))
|
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 {
|
} else {
|
||||||
// If the symbol already exists, it is an error: for example, the user wrote
|
// If the symbol already exists, it is an error: for example, the user wrote
|
||||||
// #[no_mangle] extern "C" fn main(..) {..}
|
// #[no_mangle] extern "C" fn main(..) {..}
|
||||||
|
@ -90,6 +90,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
|
|||||||
declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type)
|
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.
|
/// Declare a Rust function.
|
||||||
///
|
///
|
||||||
/// If there’s a value with the same name already declared, the function will
|
/// If there’s a value with the same name already declared, the function will
|
||||||
|
@ -180,7 +180,8 @@ fn exported_symbols_provider_local<'tcx>(
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if tcx.entry_fn(()).is_some() {
|
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((
|
symbols.push((
|
||||||
exported_symbol,
|
exported_symbol,
|
||||||
|
@ -3,6 +3,7 @@ use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
|
|||||||
use crate::spec::{self, HasTargetSpec};
|
use crate::spec::{self, HasTargetSpec};
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
mod aarch64;
|
mod aarch64;
|
||||||
mod amdgpu;
|
mod amdgpu;
|
||||||
@ -737,6 +738,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.
|
// Some types are used a lot. Make sure they don't unintentionally get bigger.
|
||||||
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
|
||||||
mod size_asserts {
|
mod size_asserts {
|
||||||
|
@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
//! the target's settings, though `target-feature` and `link-args` will *add*
|
//! the target's settings, though `target-feature` and `link-args` will *add*
|
||||||
//! to the list specified by the target, rather than replace.
|
//! to the list specified by the target, rather than replace.
|
||||||
|
|
||||||
|
use crate::abi::call::Conv;
|
||||||
use crate::abi::Endian;
|
use crate::abi::Endian;
|
||||||
use crate::json::{Json, ToJson};
|
use crate::json::{Json, ToJson};
|
||||||
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
||||||
@ -1668,6 +1669,14 @@ pub struct TargetOptions {
|
|||||||
/// Whether the target supports stack canary checks. `true` by default,
|
/// Whether the target supports stack canary checks. `true` by default,
|
||||||
/// since this is most common among tier 1 and tier 2 targets.
|
/// since this is most common among tier 1 and tier 2 targets.
|
||||||
pub supports_stack_protector: bool,
|
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
|
/// Add arguments for the given flavor and also for its "twin" flavors
|
||||||
@ -1884,6 +1893,8 @@ impl Default for TargetOptions {
|
|||||||
c_enum_min_bits: 32,
|
c_enum_min_bits: 32,
|
||||||
generate_arange_section: true,
|
generate_arange_section: true,
|
||||||
supports_stack_protector: true,
|
supports_stack_protector: true,
|
||||||
|
entry_name: "main".into(),
|
||||||
|
entry_abi: Conv::C,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2404,6 +2415,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") {
|
if let Some(j) = obj.remove("target-endian") {
|
||||||
@ -2523,6 +2546,8 @@ impl Target {
|
|||||||
key!(c_enum_min_bits, u64);
|
key!(c_enum_min_bits, u64);
|
||||||
key!(generate_arange_section, bool);
|
key!(generate_arange_section, bool);
|
||||||
key!(supports_stack_protector, bool);
|
key!(supports_stack_protector, bool);
|
||||||
|
key!(entry_name);
|
||||||
|
key!(entry_abi, Conv)?;
|
||||||
|
|
||||||
if base.is_builtin {
|
if base.is_builtin {
|
||||||
// This can cause unfortunate ICEs later down the line.
|
// This can cause unfortunate ICEs later down the line.
|
||||||
@ -2773,6 +2798,8 @@ impl ToJson for Target {
|
|||||||
target_option_val!(c_enum_min_bits);
|
target_option_val!(c_enum_min_bits);
|
||||||
target_option_val!(generate_arange_section);
|
target_option_val!(generate_arange_section);
|
||||||
target_option_val!(supports_stack_protector);
|
target_option_val!(supports_stack_protector);
|
||||||
|
target_option_val!(entry_name);
|
||||||
|
target_option_val!(entry_abi);
|
||||||
|
|
||||||
if let Some(abi) = self.default_adjusted_cabi {
|
if let Some(abi) = self.default_adjusted_cabi {
|
||||||
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
|
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user