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