2020-05-10 10:54:30 -04:00
|
|
|
|
use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
|
|
|
|
|
use rustc_codegen_ssa::traits::BaseTypeMethods;
|
|
|
|
|
use rustc_middle::ty::Ty;
|
|
|
|
|
use rustc_span::Symbol;
|
|
|
|
|
use rustc_target::abi::call::FnAbi;
|
|
|
|
|
|
|
|
|
|
use crate::abi::FnAbiGccExt;
|
2022-02-26 09:59:37 +01:00
|
|
|
|
use crate::context::CodegenCx;
|
2020-05-10 10:54:30 -04:00
|
|
|
|
use crate::intrinsic::llvm;
|
|
|
|
|
|
|
|
|
|
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
|
2021-09-26 12:20:02 -04: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) {
|
2022-05-04 21:53:22 -04:00
|
|
|
|
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 {
|
2021-12-15 14:39:23 +11:00
|
|
|
|
global.set_link_section(link_section.as_str());
|
2020-05-10 10:54:30 -04:00
|
|
|
|
}
|
2021-09-26 12:20:02 -04:00
|
|
|
|
global
|
2020-05-10 10:54:30 -04:00
|
|
|
|
}
|
|
|
|
|
else {
|
2022-01-23 19:39:55 +01:00
|
|
|
|
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> {
|
2022-02-26 09:59:37 +01:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 12:20:02 -04: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
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-19 09:23:23 -04:00
|
|
|
|
pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
|
|
|
|
|
self.linkage.set(FunctionType::Extern);
|
2023-01-08 11:42:00 -05:00
|
|
|
|
declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic)
|
2022-10-19 09:23:23 -04:00
|
|
|
|
}
|
2020-05-10 10:54:30 -04:00
|
|
|
|
|
2022-01-23 19:39:55 +01: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 {
|
2021-12-15 14:39:23 +11:00
|
|
|
|
global.set_link_section(link_section.as_str());
|
2020-05-10 10:54:30 -04:00
|
|
|
|
}
|
2021-09-26 12:20:02 -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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> 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);
|
2023-01-08 11:42:00 -05:00
|
|
|
|
let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, 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) }
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-08 11:42:00 -05:00
|
|
|
|
pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function<'gcc> {
|
2022-02-27 13:46:57 -05:00
|
|
|
|
let (return_type, params, variadic, on_stack_param_indices) = fn_abi.gcc_type(self);
|
2023-01-08 11:42:00 -05:00
|
|
|
|
let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, ¶ms, variadic);
|
2022-02-27 13:46:57 -05:00
|
|
|
|
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
|
2022-06-22 17:48:54 -04:00
|
|
|
|
func
|
2020-05-10 10:54:30 -04:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-26 12:20:02 -04: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 there’s a value with the same name already declared, the function will
|
|
|
|
|
/// update the declaration and return existing Value instead.
|
2023-01-08 11:42:00 -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.") {
|
2022-05-02 21:50:22 -04:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
let func =
|
|
|
|
|
if cx.functions.borrow().contains_key(name) {
|
2022-05-04 21:53:22 -04:00
|
|
|
|
cx.functions.borrow()[name]
|
2020-05-10 10:54:30 -04:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
let params: Vec<_> = param_types.into_iter().enumerate()
|
2021-08-15 08:28:46 -04:00
|
|
|
|
.map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
|
2020-05-10 10:54:30 -04:00
|
|
|
|
.collect();
|
|
|
|
|
let func = cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, mangle_name(name), variadic);
|
2023-01-08 11:42:00 -05:00
|
|
|
|
cx.functions.borrow_mut().insert(name.to_string(), func);
|
2020-05-10 10:54:30 -04:00
|
|
|
|
func
|
|
|
|
|
};
|
|
|
|
|
|
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 _.
|
2020-05-10 10:54:30 -04:00
|
|
|
|
// Unsupported characters: `$` and `.`.
|
|
|
|
|
pub fn mangle_name(name: &str) -> String {
|
|
|
|
|
name.replace(|char: char| {
|
|
|
|
|
if !char.is_alphanumeric() && char != '_' {
|
|
|
|
|
debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}, "_")
|
|
|
|
|
}
|