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