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