1 use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
2 use rustc_codegen_ssa::traits::BaseTypeMethods;
3 use rustc_middle::ty::Ty;
4 use rustc_span::Symbol;
5 use rustc_target::abi::call::FnAbi;
6 
7 use crate::abi::FnAbiGccExt;
8 use crate::context::{CodegenCx, unit_name};
9 use crate::intrinsic::llvm;
10 
11 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc>12     pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
13         if self.globals.borrow().contains_key(name) {
14             let typ = self.globals.borrow().get(name).expect("global").get_type();
15             let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
16             if is_tls {
17                 global.set_tls_model(self.tls_model);
18             }
19             if let Some(link_section) = link_section {
20                 global.set_link_section(&link_section.as_str());
21             }
22             global
23         }
24         else {
25             self.declare_global(name, ty, is_tls, link_section)
26         }
27     }
28 
declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc>29     pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> {
30         let index = self.global_gen_sym_counter.get();
31         self.global_gen_sym_counter.set(index + 1);
32         let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit));
33         self.context.new_global(None, GlobalKind::Exported, ty, &name)
34     }
35 
declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc>36     pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> {
37         let global = self.context.new_global(None, linkage, ty, name);
38         let global_address = global.get_address(None);
39         self.globals.borrow_mut().insert(name.to_string(), global_address);
40         global
41     }
42 
43     /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> {
44         self.linkage.set(FunctionType::Exported);
45         let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic);
46         // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
47         unsafe { std::mem::transmute(func) }
48     }*/
49 
declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc>50     pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
51         let global = self.context.new_global(None, GlobalKind::Exported, ty, name);
52         if is_tls {
53             global.set_tls_model(self.tls_model);
54         }
55         if let Some(link_section) = link_section {
56             global.set_link_section(&link_section.as_str());
57         }
58         let global_address = global.get_address(None);
59         self.globals.borrow_mut().insert(name.to_string(), global_address);
60         global
61     }
62 
declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc>63     pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> {
64         let global = self.context.new_global(None, GlobalKind::Internal, ty, name);
65         let global_address = global.get_address(None);
66         self.globals.borrow_mut().insert(name.to_string(), global_address);
67         global
68     }
69 
declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc>70     pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> {
71         // TODO(antoyo): use the fn_type parameter.
72         let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
73         let return_type = self.type_i32();
74         let variadic = false;
75         self.linkage.set(FunctionType::Exported);
76         let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
77         // NOTE: it is needed to set the current_func here as well, because get_fn() is not called
78         // for the main function.
79         *self.current_func.borrow_mut() = Some(func);
80         // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
81         unsafe { std::mem::transmute(func) }
82     }
83 
declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc>84     pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> {
85         let (return_type, params, variadic) = fn_abi.gcc_type(self);
86         let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
87         // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
88         unsafe { std::mem::transmute(func) }
89     }
90 
define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc>91     pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
92         self.get_or_insert_global(name, ty, is_tls, link_section)
93     }
94 
get_declared_value(&self, name: &str) -> Option<RValue<'gcc>>95     pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
96         // TODO(antoyo): use a different field than globals, because this seems to return a function?
97         self.globals.borrow().get(name).cloned()
98     }
99 }
100 
101 /// Declare a function.
102 ///
103 /// If there’s a value with the same name already declared, the function will
104 /// update the declaration and return existing Value instead.
declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () , return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc>105 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> {
106     if name.starts_with("llvm.") {
107         return llvm::intrinsic(name, cx);
108     }
109     let func =
110         if cx.functions.borrow().contains_key(name) {
111             *cx.functions.borrow().get(name).expect("function")
112         }
113         else {
114             let params: Vec<_> = param_types.into_iter().enumerate()
115                 .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
116                 .collect();
117             let func = cx.context.new_function(None, cx.linkage.get(), return_type, &params, mangle_name(name), variadic);
118             cx.functions.borrow_mut().insert(name.to_string(), func);
119             func
120         };
121 
122     // TODO(antoyo): set function calling convention.
123     // TODO(antoyo): set unnamed address.
124     // TODO(antoyo): set no red zone function attribute.
125     // TODO(antoyo): set attributes for optimisation.
126     // TODO(antoyo): set attributes for non lazy bind.
127 
128     // FIXME(antoyo): invalid cast.
129     func
130 }
131 
132 // FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
133 // Unsupported characters: `$` and `.`.
mangle_name(name: &str) -> String134 pub fn mangle_name(name: &str) -> String {
135     name.replace(|char: char| {
136         if !char.is_alphanumeric() && char != '_' {
137             debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
138             true
139         }
140         else {
141             false
142         }
143     }, "_")
144 }
145