1 use std
::cell
::{Cell, RefCell}
;
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
::{
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}
;
20 use crate::callee
::get_fn
;
23 pub struct FuncSig
<'gcc
> {
24 pub params
: Vec
<Type
<'gcc
>>,
25 pub return_type
: Type
<'gcc
>,
28 pub struct CodegenCx
<'gcc
, 'tcx
> {
29 pub check_overflow
: bool
,
30 pub codegen_unit
: &'tcx CodegenUnit
<'tcx
>,
31 pub context
: &'gcc Context
<'gcc
>,
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
>>>,
37 pub functions
: RefCell
<FxHashMap
<String
, Function
<'gcc
>>>,
39 pub tls_model
: gccjit
::TlsModel
,
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
>,
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
>,
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
>,
63 pub supports_128bit_integers
: bool
,
65 pub float_type
: Type
<'gcc
>,
66 pub double_type
: Type
<'gcc
>,
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
>,
73 pub struct_types
: RefCell
<FxHashMap
<Vec
<Type
<'gcc
>>, Type
<'gcc
>>>,
75 pub types_with_fields_to_set
: RefCell
<FxHashMap
<Type
<'gcc
>, (Struct
<'gcc
>, TyAndLayout
<'tcx
>)>>,
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
>>>,
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>>>,
90 /// Cache of emitted const globals (value -> global)
91 pub const_globals
: RefCell
<FxHashMap
<RValue
<'gcc
>, RValue
<'gcc
>>>,
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
>>>,
97 /// Cache of constant strings,
98 pub const_str_cache
: RefCell
<FxHashMap
<Symbol
, LValue
<'gcc
>>>,
100 /// Cache of globals.
101 pub globals
: RefCell
<FxHashMap
<String
, RValue
<'gcc
>>>,
103 /// A counter that is used for generating local symbol names
104 local_gen_sym_counter
: Cell
<usize>,
106 eh_personality
: Cell
<Option
<RValue
<'gcc
>>>,
108 pub pointee_infos
: RefCell
<FxHashMap
<(Ty
<'tcx
>, Size
), Option
<PointeeInfo
>>>,
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
>>>,
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();
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
);
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
)
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
)
143 let tls_model
= to_gcc_tls_mode(tcx
.sess
.tls_model());
145 let float_type
= context
.new_type
::<f32>();
146 let double_type
= context
.new_type
::<f64>();
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
);
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
>();
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());
163 let mut functions
= FxHashMap
::default();
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",
176 for builtin
in builtins
.iter() {
177 functions
.insert(builtin
.to_string(), context
.get_builtin_function(builtin
));
184 current_func
: RefCell
::new(None
),
185 normal_function_addresses
: Default
::default(),
186 functions
: RefCell
::new(functions
),
210 supports_128bit_integers
,
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(),
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(),
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());
244 pub fn is_native_int_type(&self, typ
: Type
<'gcc
>) -> bool
{
256 for native_type
in types
{
257 if native_type
.is_compatible_with(typ
) {
262 self.supports_128bit_integers
&&
263 (self.u128_type
.is_compatible_with(typ
) || self.i128_type
.is_compatible_with(typ
))
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
))
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
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
279 pub fn sess(&self) -> &Session
{
284 impl<'gcc
, 'tcx
> BackendTypes
for CodegenCx
<'gcc
, 'tcx
> {
285 type Value
= RValue
<'gcc
>;
286 type Function
= RValue
<'gcc
>;
288 type BasicBlock
= Block
<'gcc
>;
289 type Type
= Type
<'gcc
>;
290 type Funclet
= (); // TODO(antoyo)
292 type DIScope
= (); // TODO(antoyo)
293 type DILocation
= (); // TODO(antoyo)
294 type DIVariable
= (); // TODO(antoyo)
297 impl<'gcc
, 'tcx
> MiscMethods
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
298 fn vtables(&self) -> &RefCell
<FxHashMap
<(Ty
<'tcx
>, Option
<PolyExistentialTraitRef
<'tcx
>>), RValue
<'gcc
>>> {
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
));
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
);
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).
316 self.normal_function_addresses
.borrow_mut().insert(ptr
);
321 fn eh_personality(&self) -> RValue
<'gcc
> {
322 // The exception handling personality function.
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.
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
;
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(
350 ty
::ParamEnv
::reveal_all(),
352 tcx
.intern_substs(&[]),
357 let _name
= if wants_msvc_seh(self.sess()) {
360 "rust_eh_personality"
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)
368 // TODO(antoyo): apply target cpu attributes.
369 self.eh_personality
.set(Some(llfn
));
373 fn sess(&self) -> &Session
{
377 fn check_overflow(&self) -> bool
{
381 fn codegen_unit(&self) -> &'tcx CodegenUnit
<'tcx
> {
385 fn used_statics(&self) -> &RefCell
<Vec
<RValue
<'gcc
>>> {
389 fn set_frame_pointer_type(&self, _llfn
: RValue
<'gcc
>) {
393 fn apply_target_cpu_attr(&self, _llfn
: RValue
<'gcc
>) {
397 fn create_used_variable(&self) {
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
))
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]
413 fn compiler_used_statics(&self) -> &RefCell
<Vec
<RValue
<'gcc
>>> {
417 fn create_compiler_used_variable(&self) {
422 impl<'gcc
, 'tcx
> HasTyCtxt
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
423 fn tcx(&self) -> TyCtxt
<'tcx
> {
428 impl<'gcc
, 'tcx
> HasDataLayout
for CodegenCx
<'gcc
, 'tcx
> {
429 fn data_layout(&self) -> &TargetDataLayout
{
430 &self.tcx
.data_layout
434 impl<'gcc
, 'tcx
> HasTargetSpec
for CodegenCx
<'gcc
, 'tcx
> {
435 fn target_spec(&self) -> &Target
{
436 &self.tcx
.sess
.target
440 impl<'gcc
, 'tcx
> LayoutOfHelpers
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
441 type LayoutOfResult
= TyAndLayout
<'tcx
>;
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())
448 span_bug
!(span
, "failed to get layout for `{}`: {}", ty
, err
)
453 impl<'gcc
, 'tcx
> FnAbiOfHelpers
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
454 type FnAbiOfResult
= &'tcx FnAbi
<'tcx
, Ty
<'tcx
>>;
457 fn handle_fn_abi_err(
459 err
: FnAbiError
<'tcx
>,
461 fn_abi_request
: FnAbiRequest
<'tcx
>,
463 if let FnAbiError
::Layout(LayoutError
::SizeOverflow(_
)) = err
{
464 self.sess().span_fatal(span
, &err
.to_string())
466 match fn_abi_request
{
467 FnAbiRequest
::OfFnPtr { sig, extra_args }
=> {
470 "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
476 FnAbiRequest
::OfInstance { instance, extra_args }
=> {
479 "`fn_abi_of_instance({}, {:?})` failed: {}",
490 impl<'tcx
, 'gcc
> HasParamEnv
<'tcx
> for CodegenCx
<'gcc
, 'tcx
> {
491 fn param_env(&self) -> ParamEnv
<'tcx
> {
492 ParamEnv
::reveal_all()
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
);
507 base_n
::push_str(idx
as u128
, base_n
::ALPHANUMERIC_ONLY
, &mut name
);
512 fn to_gcc_tls_mode(tls_model
: TlsModel
) -> gccjit
::TlsModel
{
514 TlsModel
::GeneralDynamic
=> gccjit
::TlsModel
::GlobalDynamic
,
515 TlsModel
::LocalDynamic
=> gccjit
::TlsModel
::LocalDynamic
,
516 TlsModel
::InitialExec
=> gccjit
::TlsModel
::InitialExec
,
517 TlsModel
::LocalExec
=> gccjit
::TlsModel
::LocalExec
,