rust/src/declare.rs

283 lines
9.6 KiB
Rust
Raw Normal View History

2024-02-28 17:06:24 -05:00
#[cfg(feature = "master")]
2023-05-12 11:40:04 -04:00
use gccjit::{FnAttribute, ToRValue};
2024-02-28 17:06:24 -05:00
use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
2020-05-10 10:54:30 -04:00
use rustc_codegen_ssa::traits::BaseTypeMethods;
use rustc_middle::ty::Ty;
use rustc_span::Symbol;
use rustc_target::abi::call::FnAbi;
2023-10-17 21:55:36 +02:00
use crate::abi::{FnAbiGcc, FnAbiGccExt};
use crate::context::CodegenCx;
2020-05-10 10:54:30 -04:00
use crate::intrinsic::llvm;
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
2024-02-28 17:06:24 -05:00
pub fn get_or_insert_global(
&self,
name: &str,
ty: Type<'gcc>,
is_tls: bool,
link_section: Option<Symbol>,
) -> LValue<'gcc> {
2020-05-10 10:54:30 -04:00
if self.globals.borrow().contains_key(name) {
let typ = self.globals.borrow()[name].get_type();
2020-05-10 10:54:30 -04:00
let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
if is_tls {
global.set_tls_model(self.tls_model);
}
if let Some(link_section) = link_section {
global.set_link_section(link_section.as_str());
2020-05-10 10:54:30 -04:00
}
global
2024-02-28 17:06:24 -05:00
} else {
self.declare_global(name, ty, GlobalKind::Exported, is_tls, link_section)
2020-05-10 10:54:30 -04:00
}
}
pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> {
let name = self.generate_local_symbol_name("global");
self.context.new_global(None, GlobalKind::Internal, ty, name)
2020-05-10 10:54:30 -04:00
}
2024-02-28 17:06:24 -05:00
pub fn declare_global_with_linkage(
&self,
name: &str,
ty: Type<'gcc>,
linkage: GlobalKind,
) -> LValue<'gcc> {
let global = self.context.new_global(None, linkage, ty, name);
let global_address = global.get_address(None);
self.globals.borrow_mut().insert(name.to_string(), global_address);
2020-05-10 10:54:30 -04:00
global
}
2024-02-28 17:06:24 -05:00
pub fn declare_func(
&self,
name: &str,
return_type: Type<'gcc>,
params: &[Type<'gcc>],
variadic: bool,
) -> Function<'gcc> {
self.linkage.set(FunctionType::Extern);
declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic)
}
2020-05-10 10:54:30 -04:00
2024-02-28 17:06:24 -05:00
pub fn declare_global(
&self,
name: &str,
ty: Type<'gcc>,
global_kind: GlobalKind,
is_tls: bool,
link_section: Option<Symbol>,
) -> LValue<'gcc> {
let global = self.context.new_global(None, global_kind, ty, name);
2020-05-10 10:54:30 -04:00
if is_tls {
global.set_tls_model(self.tls_model);
}
if let Some(link_section) = link_section {
global.set_link_section(link_section.as_str());
2020-05-10 10:54:30 -04:00
}
let global_address = global.get_address(None);
self.globals.borrow_mut().insert(name.to_string(), global_address);
global
}
pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> {
let global = self.context.new_global(None, GlobalKind::Internal, ty, name);
let global_address = global.get_address(None);
self.globals.borrow_mut().insert(name.to_string(), global_address);
2020-05-10 10:54:30 -04:00
global
}
2024-02-28 17:06:24 -05:00
pub fn declare_entry_fn(
&self,
name: &str,
_fn_type: Type<'gcc>,
callconv: (), /*llvm::CCallConv*/
) -> RValue<'gcc> {
2021-08-15 08:28:46 -04:00
// TODO(antoyo): use the fn_type parameter.
2020-05-10 10:54:30 -04:00
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
let return_type = self.type_i32();
let variadic = false;
self.linkage.set(FunctionType::Exported);
2024-02-28 17:06:24 -05:00
let func = declare_raw_fn(
self,
name,
callconv,
return_type,
&[self.type_i32(), const_string],
variadic,
);
2020-05-10 10:54:30 -04:00
// NOTE: it is needed to set the current_func here as well, because get_fn() is not called
// for the main function.
*self.current_func.borrow_mut() = Some(func);
2021-08-15 08:28:46 -04:00
// FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
2020-05-10 10:54:30 -04:00
unsafe { std::mem::transmute(func) }
}
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
2023-10-17 21:55:36 +02:00
let FnAbiGcc {
return_type,
arguments_type,
is_c_variadic,
on_stack_param_indices,
2024-02-28 17:06:24 -05:00
#[cfg(feature = "master")]
2023-10-17 21:55:36 +02:00
fn_attributes,
} = fn_abi.gcc_type(self);
2024-02-28 17:06:24 -05:00
let func = declare_raw_fn(
self,
name,
(), /*fn_abi.llvm_cconv()*/
return_type,
&arguments_type,
is_c_variadic,
);
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
2024-02-28 17:06:24 -05:00
#[cfg(feature = "master")]
2023-10-17 21:55:36 +02:00
for fn_attr in fn_attributes {
func.add_attribute(fn_attr);
}
func
2020-05-10 10:54:30 -04:00
}
2024-02-28 17:06:24 -05:00
pub fn define_global(
&self,
name: &str,
ty: Type<'gcc>,
is_tls: bool,
link_section: Option<Symbol>,
) -> LValue<'gcc> {
self.get_or_insert_global(name, ty, is_tls, link_section)
2020-05-10 10:54:30 -04:00
}
pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
2021-08-15 08:28:46 -04:00
// TODO(antoyo): use a different field than globals, because this seems to return a function?
2020-05-10 10:54:30 -04:00
self.globals.borrow().get(name).cloned()
}
}
/// Declare a function.
///
/// If theres a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
2024-02-28 17:06:24 -05:00
fn declare_raw_fn<'gcc>(
cx: &CodegenCx<'gcc, '_>,
name: &str,
_callconv: (), /*llvm::CallConv*/
return_type: Type<'gcc>,
param_types: &[Type<'gcc>],
variadic: bool,
) -> Function<'gcc> {
2020-05-10 10:54:30 -04:00
if name.starts_with("llvm.") {
let intrinsic = llvm::intrinsic(name, cx);
cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic);
return intrinsic;
2020-05-10 10:54:30 -04:00
}
2024-02-28 17:06:24 -05:00
let func = if cx.functions.borrow().contains_key(name) {
cx.functions.borrow()[name]
} else {
let params: Vec<_> = param_types
.iter()
2024-02-28 17:06:24 -05:00
.enumerate()
.map(|(index, param)| cx.context.new_parameter(None, *param, format!("param{}", index))) // TODO(antoyo): set name.
2024-02-28 17:06:24 -05:00
.collect();
#[cfg(not(feature = "master"))]
let name = mangle_name(name);
#[cfg(not(feature = "master"))]
let func = cx.context.new_function(
None,
cx.linkage.get(),
return_type,
&params,
name.clone(),
variadic,
);
#[cfg(feature = "master")]
2024-02-28 17:06:24 -05:00
let func =
cx.context.new_function(None, cx.linkage.get(), return_type, &params, name, variadic);
2024-02-28 17:06:24 -05:00
cx.functions.borrow_mut().insert(name.to_string(), func);
#[cfg(feature = "master")]
if name == "rust_eh_personality" {
// NOTE: GCC will sometimes change the personality function set on a function from
// rust_eh_personality to __gcc_personality_v0 as an optimization.
// As such, we need to create a weak alias from __gcc_personality_v0 to
// rust_eh_personality in order to avoid a linker error.
// This needs to be weak in order to still allow using the standard
// __gcc_personality_v0 when the linking to it.
// Since aliases don't work (maybe because of a bug in LTO partitioning?), we
// create a wrapper function that calls rust_eh_personality.
let params: Vec<_> = param_types
.iter()
2024-02-28 17:06:24 -05:00
.enumerate()
.map(|(index, param)| {
cx.context.new_parameter(None, *param, format!("param{}", index))
2024-02-28 17:06:24 -05:00
}) // TODO(antoyo): set name.
2020-05-10 10:54:30 -04:00
.collect();
2024-02-28 17:06:24 -05:00
let gcc_func = cx.context.new_function(
None,
FunctionType::Exported,
return_type,
&params,
"__gcc_personality_v0",
variadic,
);
// We need a normal extern function for the crates that access rust_eh_personality
// without defining it, otherwise we'll get a compiler error.
//
// For the crate defining it, that needs to be a weak alias instead.
gcc_func.add_attribute(FnAttribute::Weak);
let block = gcc_func.new_block("start");
let mut args = vec![];
for param in &params {
args.push(param.to_rvalue());
2023-05-12 11:40:04 -04:00
}
2024-02-28 17:06:24 -05:00
let call = cx.context.new_call(None, func, &args);
if return_type == cx.type_void() {
block.add_eval(None, call);
block.end_with_void_return(None);
} else {
block.end_with_return(None, call);
}
}
2023-05-12 11:40:04 -04:00
2024-02-28 17:06:24 -05:00
func
};
2020-05-10 10:54:30 -04:00
2021-08-15 08:28:46 -04:00
// TODO(antoyo): set function calling convention.
// TODO(antoyo): set unnamed address.
// TODO(antoyo): set no red zone function attribute.
// TODO(antoyo): set attributes for optimisation.
// TODO(antoyo): set attributes for non lazy bind.
2020-05-10 10:54:30 -04:00
2021-08-15 08:28:46 -04:00
// FIXME(antoyo): invalid cast.
2020-05-10 10:54:30 -04:00
func
}
2021-08-15 08:28:46 -04:00
// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
// Unsupported characters: `$`, `.` and `*`.
// FIXME(antoyo): `*` might not be expected: https://github.com/rust-lang/rust/issues/116979#issuecomment-1840926865
2024-02-28 17:06:24 -05:00
#[cfg(not(feature = "master"))]
2024-02-15 17:16:04 -05:00
fn mangle_name(name: &str) -> String {
2024-02-28 17:06:24 -05:00
name.replace(
|char: char| {
if !char.is_alphanumeric() && char != '_' {
debug_assert!(
"$.*".contains(char),
"Unsupported char in function name {}: {}",
name,
char
);
true
} else {
false
}
},
"_",
)
2020-05-10 10:54:30 -04:00
}