1 use std::cell::{Cell, RefCell};
2
3 use gccjit::{
4 Block,
5 Context,
6 CType,
7 Function,
8 FunctionType,
9 LValue,
10 RValue,
11 Struct,
12 Type,
13 };
14 use rustc_codegen_ssa::base::wants_msvc_seh;
15 use rustc_codegen_ssa::traits::{
16 BackendTypes,
17 MiscMethods,
18 };
19 use rustc_data_structures::base_n;
20 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
21 use rustc_middle::span_bug;
22 use rustc_middle::mir::mono::CodegenUnit;
23 use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
24 use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
25 use rustc_session::Session;
26 use rustc_span::{Span, Symbol};
27 use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
28 use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
29
30 use crate::callee::get_fn;
31 use crate::declare::mangle_name;
32
33 #[derive(Clone)]
34 pub struct FuncSig<'gcc> {
35 pub params: Vec<Type<'gcc>>,
36 pub return_type: Type<'gcc>,
37 }
38
39 pub struct CodegenCx<'gcc, 'tcx> {
40 pub check_overflow: bool,
41 pub codegen_unit: &'tcx CodegenUnit<'tcx>,
42 pub context: &'gcc Context<'gcc>,
43
44 // TODO(antoyo): First set it to a dummy block to avoid using Option?
45 pub current_block: RefCell<Option<Block<'gcc>>>,
46 pub current_func: RefCell<Option<Function<'gcc>>>,
47 pub normal_function_addresses: RefCell<FxHashSet<RValue<'gcc>>>,
48
49 pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
50
51 pub tls_model: gccjit::TlsModel,
52
53 pub bool_type: Type<'gcc>,
54 pub i8_type: Type<'gcc>,
55 pub i16_type: Type<'gcc>,
56 pub i32_type: Type<'gcc>,
57 pub i64_type: Type<'gcc>,
58 pub i128_type: Type<'gcc>,
59 pub isize_type: Type<'gcc>,
60
61 pub u8_type: Type<'gcc>,
62 pub u16_type: Type<'gcc>,
63 pub u32_type: Type<'gcc>,
64 pub u64_type: Type<'gcc>,
65 pub u128_type: Type<'gcc>,
66 pub usize_type: Type<'gcc>,
67
68 pub int_type: Type<'gcc>,
69 pub uint_type: Type<'gcc>,
70 pub long_type: Type<'gcc>,
71 pub ulong_type: Type<'gcc>,
72 pub ulonglong_type: Type<'gcc>,
73 pub sizet_type: Type<'gcc>,
74
75 pub float_type: Type<'gcc>,
76 pub double_type: Type<'gcc>,
77
78 pub linkage: Cell<FunctionType>,
79 pub scalar_types: RefCell<FxHashMap<Ty<'tcx>, Type<'gcc>>>,
80 pub types: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), Type<'gcc>>>,
81 pub tcx: TyCtxt<'tcx>,
82
83 pub struct_types: RefCell<FxHashMap<Vec<Type<'gcc>>, Type<'gcc>>>,
84
85 pub types_with_fields_to_set: RefCell<FxHashMap<Type<'gcc>, (Struct<'gcc>, TyAndLayout<'tcx>)>>,
86
87 /// Cache instances of monomorphic and polymorphic items
88 pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
89 /// Cache function instances of monomorphic and polymorphic items
90 pub function_instances: RefCell<FxHashMap<Instance<'tcx>, RValue<'gcc>>>,
91 /// Cache generated vtables
92 pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
93
94 /// Cache of emitted const globals (value -> global)
95 pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
96
97 /// Cache of constant strings,
98 pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
99
100 /// Cache of globals.
101 pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
102
103 /// A counter that is used for generating local symbol names
104 local_gen_sym_counter: Cell<usize>,
105 pub global_gen_sym_counter: Cell<usize>,
106
107 eh_personality: Cell<Option<RValue<'gcc>>>,
108
109 pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
110
111 /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
112 /// `const_undef()` returns struct as pointer so that they can later be assigned a value.
113 /// As such, this set remembers which of these pointers were returned by this function so that
114 /// they can be deferenced later.
115 /// FIXME(antoyo): fix the rustc API to avoid having this hack.
116 pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
117 }
118
119 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self120 pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
121 let check_overflow = tcx.sess.overflow_checks();
122 // TODO(antoyo): fix this mess. libgccjit seems to return random type when using new_int_type().
123 let isize_type = context.new_c_type(CType::LongLong);
124 let usize_type = context.new_c_type(CType::ULongLong);
125 let bool_type = context.new_type::<bool>();
126 let i8_type = context.new_type::<i8>();
127 let i16_type = context.new_type::<i16>();
128 let i32_type = context.new_type::<i32>();
129 let i64_type = context.new_c_type(CType::LongLong);
130 let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
131 let u8_type = context.new_type::<u8>();
132 let u16_type = context.new_type::<u16>();
133 let u32_type = context.new_type::<u32>();
134 let u64_type = context.new_c_type(CType::ULongLong);
135 let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
136
137 let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
138
139 let float_type = context.new_type::<f32>();
140 let double_type = context.new_type::<f64>();
141
142 let int_type = context.new_c_type(CType::Int);
143 let uint_type = context.new_c_type(CType::UInt);
144 let long_type = context.new_c_type(CType::Long);
145 let ulong_type = context.new_c_type(CType::ULong);
146 let ulonglong_type = context.new_c_type(CType::ULongLong);
147 let sizet_type = context.new_c_type(CType::SizeT);
148
149 assert_eq!(isize_type, i64_type);
150 assert_eq!(usize_type, u64_type);
151
152 let mut functions = FxHashMap::default();
153 let builtins = [
154 "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
155 "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
156 "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow",
157 "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow",
158 "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos",
159 "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf",
160 "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf",
161 "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round",
162 "__builtin_expect_with_probability",
163 ];
164
165 for builtin in builtins.iter() {
166 functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
167 }
168
169 Self {
170 check_overflow,
171 codegen_unit,
172 context,
173 current_block: RefCell::new(None),
174 current_func: RefCell::new(None),
175 normal_function_addresses: Default::default(),
176 functions: RefCell::new(functions),
177
178 tls_model,
179
180 bool_type,
181 i8_type,
182 i16_type,
183 i32_type,
184 i64_type,
185 i128_type,
186 isize_type,
187 usize_type,
188 u8_type,
189 u16_type,
190 u32_type,
191 u64_type,
192 u128_type,
193 int_type,
194 uint_type,
195 long_type,
196 ulong_type,
197 ulonglong_type,
198 sizet_type,
199
200 float_type,
201 double_type,
202
203 linkage: Cell::new(FunctionType::Internal),
204 instances: Default::default(),
205 function_instances: Default::default(),
206 vtables: Default::default(),
207 const_globals: Default::default(),
208 const_cstr_cache: Default::default(),
209 globals: Default::default(),
210 scalar_types: Default::default(),
211 types: Default::default(),
212 tcx,
213 struct_types: Default::default(),
214 types_with_fields_to_set: Default::default(),
215 local_gen_sym_counter: Cell::new(0),
216 global_gen_sym_counter: Cell::new(0),
217 eh_personality: Cell::new(None),
218 pointee_infos: Default::default(),
219 structs_as_pointer: Default::default(),
220 }
221 }
222
rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc>223 pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
224 let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
225 debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
226 "{:?} ({:?}) is not a function", value, value.get_type());
227 function
228 }
229
sess(&self) -> &Session230 pub fn sess(&self) -> &Session {
231 &self.tcx.sess
232 }
233 }
234
235 impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
236 type Value = RValue<'gcc>;
237 type Function = RValue<'gcc>;
238
239 type BasicBlock = Block<'gcc>;
240 type Type = Type<'gcc>;
241 type Funclet = (); // TODO(antoyo)
242
243 type DIScope = (); // TODO(antoyo)
244 type DILocation = (); // TODO(antoyo)
245 type DIVariable = (); // TODO(antoyo)
246 }
247
248 impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>249 fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
250 &self.vtables
251 }
252
get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc>253 fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
254 let func = get_fn(self, instance);
255 *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func));
256 func
257 }
258
get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc>259 fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
260 let func = get_fn(self, instance);
261 let func = self.rvalue_as_function(func);
262 let ptr = func.get_address(None);
263
264 // TODO(antoyo): don't do this twice: i.e. in declare_fn and here.
265 // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI).
266
267 self.normal_function_addresses.borrow_mut().insert(ptr);
268
269 ptr
270 }
271
eh_personality(&self) -> RValue<'gcc>272 fn eh_personality(&self) -> RValue<'gcc> {
273 // The exception handling personality function.
274 //
275 // If our compilation unit has the `eh_personality` lang item somewhere
276 // within it, then we just need to codegen that. Otherwise, we're
277 // building an rlib which will depend on some upstream implementation of
278 // this function, so we just codegen a generic reference to it. We don't
279 // specify any of the types for the function, we just make it a symbol
280 // that LLVM can later use.
281 //
282 // Note that MSVC is a little special here in that we don't use the
283 // `eh_personality` lang item at all. Currently LLVM has support for
284 // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the
285 // *name of the personality function* to decide what kind of unwind side
286 // tables/landing pads to emit. It looks like Dwarf is used by default,
287 // injecting a dependency on the `_Unwind_Resume` symbol for resuming
288 // an "exception", but for MSVC we want to force SEH. This means that we
289 // can't actually have the personality function be our standard
290 // `rust_eh_personality` function, but rather we wired it up to the
291 // CRT's custom personality function, which forces LLVM to consider
292 // landing pads as "landing pads for SEH".
293 if let Some(llpersonality) = self.eh_personality.get() {
294 return llpersonality;
295 }
296 let tcx = self.tcx;
297 let llfn = match tcx.lang_items().eh_personality() {
298 Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr(
299 ty::Instance::resolve(
300 tcx,
301 ty::ParamEnv::reveal_all(),
302 def_id,
303 tcx.intern_substs(&[]),
304 )
305 .unwrap().unwrap(),
306 ),
307 _ => {
308 let _name = if wants_msvc_seh(self.sess()) {
309 "__CxxFrameHandler3"
310 } else {
311 "rust_eh_personality"
312 };
313 //let func = self.declare_func(name, self.type_i32(), &[], true);
314 // FIXME(antoyo): this hack should not be needed. That will probably be removed when
315 // unwinding support is added.
316 self.context.new_rvalue_from_int(self.int_type, 0)
317 }
318 };
319 // TODO(antoyo): apply target cpu attributes.
320 self.eh_personality.set(Some(llfn));
321 llfn
322 }
323
sess(&self) -> &Session324 fn sess(&self) -> &Session {
325 &self.tcx.sess
326 }
327
check_overflow(&self) -> bool328 fn check_overflow(&self) -> bool {
329 self.check_overflow
330 }
331
codegen_unit(&self) -> &'tcx CodegenUnit<'tcx>332 fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
333 self.codegen_unit
334 }
335
used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>>336 fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
337 unimplemented!();
338 }
339
set_frame_pointer_type(&self, _llfn: RValue<'gcc>)340 fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
341 // TODO(antoyo)
342 }
343
apply_target_cpu_attr(&self, _llfn: RValue<'gcc>)344 fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
345 // TODO(antoyo)
346 }
347
create_used_variable(&self)348 fn create_used_variable(&self) {
349 unimplemented!();
350 }
351
declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function>352 fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
353 if self.get_declared_value("main").is_none() {
354 Some(self.declare_cfn("main", fn_type))
355 }
356 else {
357 // If the symbol already exists, it is an error: for example, the user wrote
358 // #[no_mangle] extern "C" fn main(..) {..}
359 // instead of #[start]
360 None
361 }
362 }
363
compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>>364 fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
365 unimplemented!()
366 }
367
create_compiler_used_variable(&self)368 fn create_compiler_used_variable(&self) {
369 unimplemented!()
370 }
371 }
372
373 impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
tcx(&self) -> TyCtxt<'tcx>374 fn tcx(&self) -> TyCtxt<'tcx> {
375 self.tcx
376 }
377 }
378
379 impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> {
data_layout(&self) -> &TargetDataLayout380 fn data_layout(&self) -> &TargetDataLayout {
381 &self.tcx.data_layout
382 }
383 }
384
385 impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
target_spec(&self) -> &Target386 fn target_spec(&self) -> &Target {
387 &self.tcx.sess.target
388 }
389 }
390
391 impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
392 type LayoutOfResult = TyAndLayout<'tcx>;
393
394 #[inline]
handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> !395 fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
396 if let LayoutError::SizeOverflow(_) = err {
397 self.sess().span_fatal(span, &err.to_string())
398 } else {
399 span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
400 }
401 }
402 }
403
404 impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
405 type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
406
407 #[inline]
handle_fn_abi_err( &self, err: FnAbiError<'tcx>, span: Span, fn_abi_request: FnAbiRequest<'tcx>, ) -> !408 fn handle_fn_abi_err(
409 &self,
410 err: FnAbiError<'tcx>,
411 span: Span,
412 fn_abi_request: FnAbiRequest<'tcx>,
413 ) -> ! {
414 if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
415 self.sess().span_fatal(span, &err.to_string())
416 } else {
417 match fn_abi_request {
418 FnAbiRequest::OfFnPtr { sig, extra_args } => {
419 span_bug!(
420 span,
421 "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
422 sig,
423 extra_args,
424 err
425 );
426 }
427 FnAbiRequest::OfInstance { instance, extra_args } => {
428 span_bug!(
429 span,
430 "`fn_abi_of_instance({}, {:?})` failed: {}",
431 instance,
432 extra_args,
433 err
434 );
435 }
436 }
437 }
438 }
439 }
440
441 impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
param_env(&self) -> ParamEnv<'tcx>442 fn param_env(&self) -> ParamEnv<'tcx> {
443 ParamEnv::reveal_all()
444 }
445 }
446
447 impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
448 /// Generates a new symbol name with the given prefix. This symbol name must
449 /// only be used for definitions with `internal` or `private` linkage.
generate_local_symbol_name(&self, prefix: &str) -> String450 pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
451 let idx = self.local_gen_sym_counter.get();
452 self.local_gen_sym_counter.set(idx + 1);
453 // Include a '.' character, so there can be no accidental conflicts with
454 // user defined names
455 let mut name = String::with_capacity(prefix.len() + 6);
456 name.push_str(prefix);
457 name.push_str(".");
458 base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
459 name
460 }
461 }
462
unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String463 pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String {
464 let name = &codegen_unit.name().to_string();
465 mangle_name(&name.replace('-', "_"))
466 }
467
to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel468 fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
469 match tls_model {
470 TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
471 TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
472 TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
473 TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
474 }
475 }
476