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