]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/context.rs
Auto merge of #106399 - estebank:type-err-span-label, r=nagisa
[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, source_map::respan};
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().any(|value| *value == function),
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) -> &'tcx 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 set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
420         // TODO(antoyo)
421     }
422
423     fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
424         // TODO(antoyo)
425     }
426
427     fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
428         let entry_name = self.sess().target.entry_name.as_ref();
429         if self.get_declared_value(entry_name).is_none() {
430             Some(self.declare_entry_fn(entry_name, fn_type, ()))
431         }
432         else {
433             // If the symbol already exists, it is an error: for example, the user wrote
434             // #[no_mangle] extern "C" fn main(..) {..}
435             // instead of #[start]
436             None
437         }
438     }
439 }
440
441 impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
442     fn tcx(&self) -> TyCtxt<'tcx> {
443         self.tcx
444     }
445 }
446
447 impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> {
448     fn data_layout(&self) -> &TargetDataLayout {
449         &self.tcx.data_layout
450     }
451 }
452
453 impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
454     fn target_spec(&self) -> &Target {
455         &self.tcx.sess.target
456     }
457 }
458
459 impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
460     type LayoutOfResult = TyAndLayout<'tcx>;
461
462     #[inline]
463     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
464         if let LayoutError::SizeOverflow(_) = err {
465             self.sess().emit_fatal(respan(span, err))
466         } else {
467             span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
468         }
469     }
470 }
471
472 impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
473     type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
474
475     #[inline]
476     fn handle_fn_abi_err(
477         &self,
478         err: FnAbiError<'tcx>,
479         span: Span,
480         fn_abi_request: FnAbiRequest<'tcx>,
481     ) -> ! {
482         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
483             self.sess().emit_fatal(respan(span, err))
484         } else {
485             match fn_abi_request {
486                 FnAbiRequest::OfFnPtr { sig, extra_args } => {
487                     span_bug!(
488                         span,
489                         "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
490                         sig,
491                         extra_args,
492                         err
493                     );
494                 }
495                 FnAbiRequest::OfInstance { instance, extra_args } => {
496                     span_bug!(
497                         span,
498                         "`fn_abi_of_instance({}, {:?})` failed: {}",
499                         instance,
500                         extra_args,
501                         err
502                     );
503                 }
504             }
505         }
506     }
507 }
508
509 impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
510     fn param_env(&self) -> ParamEnv<'tcx> {
511         ParamEnv::reveal_all()
512     }
513 }
514
515 impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
516     /// Generates a new symbol name with the given prefix. This symbol name must
517     /// only be used for definitions with `internal` or `private` linkage.
518     pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
519         let idx = self.local_gen_sym_counter.get();
520         self.local_gen_sym_counter.set(idx + 1);
521         // Include a '.' character, so there can be no accidental conflicts with
522         // user defined names
523         let mut name = String::with_capacity(prefix.len() + 6);
524         name.push_str(prefix);
525         name.push_str(".");
526         base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
527         name
528     }
529 }
530
531 fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
532     match tls_model {
533         TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
534         TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
535         TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
536         TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
537     }
538 }