]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/declare.rs
Merge commit '48d60ab7c505c6c1ebb042eacaafd8dc9f7a9267' into libgccjit-codegen
[rust.git] / compiler / rustc_codegen_gcc / src / declare.rs
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 use crate::mangled_std_symbols::{ARGV_INIT_ARRAY, ARGV_INIT_WRAPPER};
11
12 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
13     pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> RValue<'gcc> {
14         if self.globals.borrow().contains_key(name) {
15             let typ = self.globals.borrow().get(name).expect("global").get_type();
16             let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
17             if is_tls {
18                 global.set_tls_model(self.tls_model);
19             }
20             if let Some(link_section) = link_section {
21                 global.set_link_section(&link_section.as_str());
22             }
23             global.get_address(None)
24         }
25         else {
26             self.declare_global(name, ty, is_tls, link_section)
27         }
28     }
29
30     pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> {
31         let index = self.global_gen_sym_counter.get();
32         self.global_gen_sym_counter.set(index + 1);
33         let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit));
34         self.context.new_global(None, GlobalKind::Exported, ty, &name)
35     }
36
37     pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> RValue<'gcc> {
38         let global = self.context.new_global(None, linkage, ty, name)
39             .get_address(None);
40         self.globals.borrow_mut().insert(name.to_string(), global);
41         // NOTE: global seems to only be global in a module. So save the name instead of the value
42         // to import it later.
43         self.global_names.borrow_mut().insert(global, name.to_string());
44         global
45     }
46
47     pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> {
48         self.linkage.set(FunctionType::Exported);
49         let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic);
50         // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
51         unsafe { std::mem::transmute(func) }
52     }
53
54     pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> RValue<'gcc> {
55         // FIXME(antoyo): correctly support global variable initialization.
56         if name.starts_with(ARGV_INIT_ARRAY) {
57             // NOTE: hack to avoid having to update the names in mangled_std_symbols: we save the
58             // name of the variable now to actually declare it later.
59             *self.init_argv_var.borrow_mut() = name.to_string();
60
61             let global = self.context.new_global(None, GlobalKind::Imported, ty, name);
62             if let Some(link_section) = link_section {
63                 global.set_link_section(&link_section.as_str());
64             }
65             return global.get_address(None);
66         }
67         let global = self.context.new_global(None, GlobalKind::Exported, ty, name);
68         if is_tls {
69             global.set_tls_model(self.tls_model);
70         }
71         if let Some(link_section) = link_section {
72             global.set_link_section(&link_section.as_str());
73         }
74         let global = global.get_address(None);
75         self.globals.borrow_mut().insert(name.to_string(), global);
76         // NOTE: global seems to only be global in a module. So save the name instead of the value
77         // to import it later.
78         self.global_names.borrow_mut().insert(global, name.to_string());
79         global
80     }
81
82     pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> {
83         // TODO(antoyo): use the fn_type parameter.
84         let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
85         let return_type = self.type_i32();
86         let variadic = false;
87         self.linkage.set(FunctionType::Exported);
88         let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
89         // NOTE: it is needed to set the current_func here as well, because get_fn() is not called
90         // for the main function.
91         *self.current_func.borrow_mut() = Some(func);
92         // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
93         unsafe { std::mem::transmute(func) }
94     }
95
96     pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> {
97         // NOTE: hack to avoid having to update the names in mangled_std_symbols: we found the name
98         // of the variable earlier, so we declare it now.
99         // Since we don't correctly support initializers yet, we initialize this variable manually
100         // for now.
101         if name.starts_with(ARGV_INIT_WRAPPER) && !self.argv_initialized.get() {
102             let global_name = &*self.init_argv_var.borrow();
103             let return_type = self.type_void();
104             let params = [
105                 self.context.new_parameter(None, self.int_type, "argc"),
106                 self.context.new_parameter(None, self.u8_type.make_pointer().make_pointer(), "argv"),
107                 self.context.new_parameter(None, self.u8_type.make_pointer().make_pointer(), "envp"),
108             ];
109             let function = self.context.new_function(None, FunctionType::Extern, return_type, &params, name, false);
110             let initializer = function.get_address(None);
111
112             let param_types = [
113                 self.int_type,
114                 self.u8_type.make_pointer().make_pointer(),
115                 self.u8_type.make_pointer().make_pointer(),
116             ];
117             let ty = self.context.new_function_pointer_type(None, return_type, &param_types, false);
118
119             let global = self.context.new_global(None, GlobalKind::Exported, ty, global_name);
120             global.set_link_section(".init_array.00099");
121             global.global_set_initializer_value(initializer);
122             let global = global.get_address(None);
123             self.globals.borrow_mut().insert(global_name.to_string(), global);
124             // NOTE: global seems to only be global in a module. So save the name instead of the value
125             // to import it later.
126             self.global_names.borrow_mut().insert(global, global_name.to_string());
127             self.argv_initialized.set(true);
128         }
129         let (return_type, params, variadic) = fn_abi.gcc_type(self);
130         let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
131         // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
132         unsafe { std::mem::transmute(func) }
133     }
134
135     pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> Option<RValue<'gcc>> {
136         Some(self.get_or_insert_global(name, ty, is_tls, link_section))
137     }
138
139     pub fn define_private_global(&self, ty: Type<'gcc>) -> RValue<'gcc> {
140         let global = self.declare_unnamed_global(ty);
141         global.get_address(None)
142     }
143
144     pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
145         // TODO(antoyo): use a different field than globals, because this seems to return a function?
146         self.globals.borrow().get(name).cloned()
147     }
148 }
149
150 /// Declare a function.
151 ///
152 /// If there’s a value with the same name already declared, the function will
153 /// update the declaration and return existing Value instead.
154 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> {
155     if name.starts_with("llvm.") {
156         return llvm::intrinsic(name, cx);
157     }
158     let func =
159         if cx.functions.borrow().contains_key(name) {
160             *cx.functions.borrow().get(name).expect("function")
161         }
162         else {
163             let params: Vec<_> = param_types.into_iter().enumerate()
164                 .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
165                 .collect();
166             let func = cx.context.new_function(None, cx.linkage.get(), return_type, &params, mangle_name(name), variadic);
167             cx.functions.borrow_mut().insert(name.to_string(), func);
168             func
169         };
170
171     // TODO(antoyo): set function calling convention.
172     // TODO(antoyo): set unnamed address.
173     // TODO(antoyo): set no red zone function attribute.
174     // TODO(antoyo): set attributes for optimisation.
175     // TODO(antoyo): set attributes for non lazy bind.
176
177     // FIXME(antoyo): invalid cast.
178     func
179 }
180
181 // FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
182 // Unsupported characters: `$` and `.`.
183 pub fn mangle_name(name: &str) -> String {
184     name.replace(|char: char| {
185         if !char.is_alphanumeric() && char != '_' {
186             debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
187             true
188         }
189         else {
190             false
191         }
192     }, "_")
193 }