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