1 use std::cell::{Cell, RefCell};
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::{
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;
21 use crate::declare::mangle_name;
24 pub struct FuncSig<'gcc> {
25 pub params: Vec<Type<'gcc>>,
26 pub return_type: Type<'gcc>,
29 pub struct CodegenCx<'gcc, 'tcx> {
30 pub check_overflow: bool,
31 pub codegen_unit: &'tcx CodegenUnit<'tcx>,
32 pub context: &'gcc Context<'gcc>,
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>>>,
39 pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
41 pub tls_model: gccjit::TlsModel,
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>,
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>,
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>,
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 /// Cache of emitted const globals (value -> global)
85 pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
87 /// Cache of constant strings,
88 pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
91 pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
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>,
97 eh_personality: Cell<Option<RValue<'gcc>>>,
99 pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
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>>>,
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?
127 let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
129 let float_type = context.new_type::<f32>();
130 let double_type = context.new_type::<f64>();
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);
139 assert_eq!(isize_type, i64_type);
140 assert_eq!(usize_type, u64_type);
142 let mut functions = FxHashMap::default();
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",
155 for builtin in builtins.iter() {
156 functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
163 current_block: RefCell::new(None),
164 current_func: RefCell::new(None),
165 normal_function_addresses: Default::default(),
166 functions: RefCell::new(functions),
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(),
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(),
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());
220 pub fn sess(&self) -> &Session {
225 impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
226 type Value = RValue<'gcc>;
227 type Function = RValue<'gcc>;
229 type BasicBlock = Block<'gcc>;
230 type Type = Type<'gcc>;
231 type Funclet = (); // TODO(antoyo)
233 type DIScope = (); // TODO(antoyo)
234 type DILocation = (); // TODO(antoyo)
235 type DIVariable = (); // TODO(antoyo)
238 impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
239 fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
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));
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);
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).
257 self.normal_function_addresses.borrow_mut().insert(ptr);
262 fn eh_personality(&self) -> RValue<'gcc> {
263 // The exception handling personality function.
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.
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;
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(
291 ty::ParamEnv::reveal_all(),
293 tcx.intern_substs(&[]),
298 let _name = if wants_msvc_seh(self.sess()) {
301 "rust_eh_personality"
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)
309 // TODO(antoyo): apply target cpu attributes.
310 self.eh_personality.set(Some(llfn));
314 fn sess(&self) -> &Session {
318 fn check_overflow(&self) -> bool {
322 fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
326 fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
330 fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
334 fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
338 fn create_used_variable(&self) {
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))
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]
354 fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
358 fn create_compiler_used_variable(&self) {
363 impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
364 fn tcx(&self) -> TyCtxt<'tcx> {
369 impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> {
370 fn data_layout(&self) -> &TargetDataLayout {
371 &self.tcx.data_layout
375 impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
376 fn target_spec(&self) -> &Target {
377 &self.tcx.sess.target
381 impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
382 type LayoutOfResult = TyAndLayout<'tcx>;
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())
389 span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
394 impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
395 type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
398 fn handle_fn_abi_err(
400 err: FnAbiError<'tcx>,
402 fn_abi_request: FnAbiRequest<'tcx>,
404 if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
405 self.sess().span_fatal(span, &err.to_string())
407 match fn_abi_request {
408 FnAbiRequest::OfFnPtr { sig, extra_args } => {
411 "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
417 FnAbiRequest::OfInstance { instance, extra_args } => {
420 "`fn_abi_of_instance({}, {:?})` failed: {}",
431 impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
432 fn param_env(&self) -> ParamEnv<'tcx> {
433 ParamEnv::reveal_all()
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);
448 base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
453 pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String {
454 let name = &codegen_unit.name().to_string();
455 mangle_name(&name.replace('-', "_"))
458 fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
460 TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
461 TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
462 TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
463 TlsModel::LocalExec => gccjit::TlsModel::LocalExec,