1 use std::cell::{Cell, RefCell};
14 use rustc_codegen_ssa::base::wants_msvc_seh;
15 use rustc_codegen_ssa::traits::{
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};
30 use crate::callee::get_fn;
31 use crate::declare::mangle_name;
34 pub struct FuncSig<'gcc> {
35 pub params: Vec<Type<'gcc>>,
36 pub return_type: Type<'gcc>,
39 pub struct CodegenCx<'gcc, 'tcx> {
40 pub check_overflow: bool,
41 pub codegen_unit: &'tcx CodegenUnit<'tcx>,
42 pub context: &'gcc Context<'gcc>,
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>>>,
49 /// The function where globals are initialized.
50 pub global_init_func: Function<'gcc>,
51 pub global_init_block: Block<'gcc>,
53 pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
55 pub tls_model: gccjit::TlsModel,
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>,
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>,
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>,
79 pub float_type: Type<'gcc>,
80 pub double_type: Type<'gcc>,
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>,
87 pub struct_types: RefCell<FxHashMap<Vec<Type<'gcc>>, Type<'gcc>>>,
89 pub types_with_fields_to_set: RefCell<FxHashMap<Type<'gcc>, (Struct<'gcc>, TyAndLayout<'tcx>)>>,
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>>>,
96 /// Cache of emitted const globals (value -> global)
97 pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
99 pub init_argv_var: RefCell<String>,
100 pub argv_initialized: Cell<bool>,
102 /// Cache of constant strings,
103 pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
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>>,
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>,
114 eh_personality: Cell<Option<RValue<'gcc>>>,
116 pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
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>>>,
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
128 /// FIXME: remove when the API supports more types.
129 #[cfg(debug_assertions)]
130 lvalues: RefCell<FxHashSet<LValue<'gcc>>>,
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?
153 let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
155 let float_type = context.new_type::<f32>();
156 let double_type = context.new_type::<f64>();
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);
165 assert_eq!(isize_type, i64_type);
166 assert_eq!(usize_type, u64_type);
168 let mut functions = FxHashMap::default();
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",
181 for builtin in builtins.iter() {
182 functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
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");
193 current_block: RefCell::new(None),
194 current_func: RefCell::new(None),
195 normal_function_addresses: Default::default(),
196 functions: RefCell::new(functions),
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(),
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(),
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) }
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());
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);
268 pub fn sess(&self) -> &Session {
273 impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
274 type Value = RValue<'gcc>;
275 type Function = RValue<'gcc>;
277 type BasicBlock = Block<'gcc>;
278 type Type = Type<'gcc>;
279 type Funclet = (); // TODO
281 type DIScope = (); // TODO
282 type DILocation = (); // TODO
283 type DIVariable = (); // TODO
286 impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
287 fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
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));
297 fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
298 //let symbol = self.tcx.symbol_name(instance).name;
300 let func = get_fn(self, instance);
301 let func = self.rvalue_as_function(func);
302 let ptr = func.get_address(None);
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();
310 self.normal_function_addresses.borrow_mut().insert(ptr);
315 fn eh_personality(&self) -> RValue<'gcc> {
316 // The exception handling personality function.
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.
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;
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(
344 ty::ParamEnv::reveal_all(),
346 tcx.intern_substs(&[]),
351 let _name = if wants_msvc_seh(self.sess()) {
354 "rust_eh_personality"
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)
362 //attributes::apply_target_cpu_attr(self, llfn);
363 self.eh_personality.set(Some(llfn));
367 fn sess(&self) -> &Session {
371 fn check_overflow(&self) -> bool {
375 fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
379 fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
384 fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
386 //attributes::set_frame_pointer_type(self, llfn)
389 fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
391 //attributes::apply_target_cpu_attr(self, llfn)
394 fn create_used_variable(&self) {
396 /*let name = const_cstr!("llvm.used");
397 let section = const_cstr!("llvm.metadata");
399 self.const_array(&self.type_ptr_to(self.type_i8()), &*self.used_statics.borrow());
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());
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))
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]
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> LayoutOf for CodegenCx<'gcc, 'tcx> {
442 type TyAndLayout = TyAndLayout<'tcx>;
444 fn layout_of(&self, ty: Ty<'tcx>) -> Self::TyAndLayout {
445 self.spanned_layout_of(ty, DUMMY_SP)
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())
453 bug!("failed to get layout for `{}`: {}", ty, e)
459 impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
460 fn param_env(&self) -> ParamEnv<'tcx> {
461 ParamEnv::reveal_all()
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);
476 base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name);
481 pub fn unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String {
482 let name = &codegen_unit.name().to_string();
483 mangle_name(&name.replace('-', "_"))
486 fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
488 TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
489 TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
490 TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
491 TlsModel::LocalExec => gccjit::TlsModel::LocalExec,