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