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