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