1use crate::constant::ConstantRef;
2use crate::debugloc::*;
3use crate::function::{Function, FunctionAttribute, FunctionDeclaration, GroupID};
4use crate::llvm_sys::*;
5use crate::name::Name;
6use crate::types::{FPType, Type, TypeRef, Typed, Types, TypesBuilder};
7use std::collections::{BTreeMap, HashMap, HashSet};
8use std::path::Path;
9
10#[derive(Clone)]
12pub struct Module {
13 pub name: String,
15 pub source_file_name: String,
17 pub data_layout: DataLayout,
19 pub target_triple: Option<String>,
21 pub functions: Vec<Function>,
24 pub func_declarations: Vec<FunctionDeclaration>,
27 pub global_vars: Vec<GlobalVariable>,
29 pub global_aliases: Vec<GlobalAlias>,
31 pub global_ifuncs: Vec<GlobalIFunc>,
33 pub inline_assembly: String,
36 pub types: Types,
42}
43
44impl Module {
45 pub fn type_of<T: Typed + ?Sized>(&self, t: &T) -> TypeRef {
47 self.types.type_of(t)
48 }
49
50 pub fn get_func_by_name(&self, name: &str) -> Option<&Function> {
56 self.functions.iter().find(|func| func.name == name)
57 }
58
59 pub fn get_func_decl_by_name(&self, name: &str) -> Option<&FunctionDeclaration> {
65 self.func_declarations.iter().find(|decl| decl.name == name)
66 }
67
68 pub fn get_global_var_by_name(&self, name: &Name) -> Option<&GlobalVariable> {
70 self.global_vars.iter().find(|global| global.name == *name)
71 }
72
73 pub fn get_global_alias_by_name(&self, name: &Name) -> Option<&GlobalAlias> {
75 self.global_aliases.iter().find(|global| global.name == *name)
76 }
77
78 pub fn get_global_ifunc_by_name(&self, name: &Name) -> Option<&GlobalIFunc> {
80 self.global_ifuncs.iter().find(|global| global.name == *name)
81 }
82
83 pub fn from_bc_path(path: impl AsRef<Path>) -> Result<Self, String> {
85 unsafe fn parse_bc(
86 context_ref: LLVMContextRef,
87 mem_buf: LLVMMemoryBufferRef,
88 out_module: *mut LLVMModuleRef,
89 ) -> Result<(), String> {
90 let result =
91 llvm_sys::bit_reader::LLVMParseBitcodeInContext2(context_ref, mem_buf, out_module);
92 LLVMDisposeMemoryBuffer(mem_buf);
93 match result {
94 0 => Ok(()),
95 _ => Err("Failed to parse bitcode".to_owned())
96 }
97 }
98 Self::from_path(path, parse_bc)
99 }
100
101 pub fn from_ir_path(path: impl AsRef<Path>) -> Result<Self, String> {
103 Self::from_path(path, Self::parse_ir)
104 }
105
106 pub fn from_ir_str(str: &str) -> Result<Self, String> {
108 let memory_buffer = unsafe {
109 LLVMCreateMemoryBufferWithMemoryRangeCopy(
110 str.as_ptr() as *const _,
111 str.len(),
112 std::ffi::CString::default().as_ptr(),
113 )
114 };
115 Self::from_buffer(memory_buffer, Self::parse_ir)
116 }
117
118 unsafe fn parse_ir(
119 context_ref: LLVMContextRef,
120 mem_buf: LLVMMemoryBufferRef,
121 out_module: *mut LLVMModuleRef,
122 ) -> Result<(), String> {
123 use std::ffi::CStr;
124 let mut err_string = std::mem::zeroed();
125 match llvm_sys::ir_reader::LLVMParseIRInContext(context_ref, mem_buf, out_module, &mut err_string) {
127 0 => Ok(()),
128 _ => Err(format!("Failed to parse IR: {}",
129 CStr::from_ptr(err_string).to_str().expect("Failed to convert CStr")))
130 }
131 }
132
133 fn from_path(
134 path: impl AsRef<Path>,
135 parse: unsafe fn(
136 context_ref: LLVMContextRef,
137 mem_buf: LLVMMemoryBufferRef,
138 out_module: *mut LLVMModuleRef,
139 ) -> Result<(), String>,
140 ) -> Result<Self, String> {
141 use std::ffi::{CStr, CString};
143
144 let path = CString::new(
145 path.as_ref()
146 .to_str()
147 .expect("Did not find a valid Unicode path string"),
148 )
149 .expect("Failed to convert to CString");
150 debug!("Creating a Module from path {:?}", path);
151
152 let memory_buffer = unsafe {
153 let mut memory_buffer = std::ptr::null_mut();
154 let mut err_string = std::mem::zeroed();
155 let return_code = LLVMCreateMemoryBufferWithContentsOfFile(
156 path.as_ptr() as *const _,
157 &mut memory_buffer,
158 &mut err_string,
159 );
160 if return_code != 0 {
161 return Err(CStr::from_ptr(err_string)
162 .to_str()
163 .expect("Failed to convert CStr")
164 .to_owned());
165 }
166 memory_buffer
167 };
168 debug!("Created a MemoryBuffer");
169
170 Self::from_buffer(memory_buffer, parse)
171 }
172
173 fn from_buffer(
174 memory_buffer: LLVMMemoryBufferRef,
175 parse: unsafe fn(
176 context_ref: LLVMContextRef,
177 mem_buf: LLVMMemoryBufferRef,
178 out_module: *mut LLVMModuleRef,
179 ) -> Result<(), String>,
180 ) -> Result<Self, String> {
181 let context = crate::from_llvm::Context::new();
182
183 let module = unsafe {
184 let mut module: std::mem::MaybeUninit<LLVMModuleRef> = std::mem::MaybeUninit::uninit();
185 parse(context.ctx, memory_buffer, module.as_mut_ptr())?;
186 module.assume_init()
187 };
188 debug!("Parsed bitcode to llvm_sys module");
189 Ok(Self::from_llvm_ref(module))
190 }
191}
192
193#[derive(PartialEq, Clone, Debug, Hash)]
195pub struct GlobalVariable {
196 pub name: Name,
197 pub linkage: Linkage,
198 pub visibility: Visibility,
199 pub is_constant: bool,
200 pub ty: TypeRef,
201 pub addr_space: AddrSpace,
202 pub dll_storage_class: DLLStorageClass,
203 pub thread_local_mode: ThreadLocalMode,
204 pub unnamed_addr: Option<UnnamedAddr>,
205 pub initializer: Option<ConstantRef>,
206 pub section: Option<String>,
207 pub comdat: Option<Comdat>, pub alignment: u32,
209 pub debugloc: Option<DebugLoc>,
210 }
212
213impl Typed for GlobalVariable {
214 fn get_type(&self, _types: &Types) -> TypeRef {
215 self.ty.clone()
216 }
217}
218
219impl HasDebugLoc for GlobalVariable {
220 fn get_debug_loc(&self) -> &Option<DebugLoc> {
221 &self.debugloc
222 }
223}
224
225#[derive(PartialEq, Clone, Debug, Hash)]
227pub struct GlobalAlias {
228 pub name: Name,
229 pub aliasee: ConstantRef,
230 pub linkage: Linkage,
231 pub visibility: Visibility,
232 pub ty: TypeRef,
233 pub addr_space: AddrSpace,
234 pub dll_storage_class: DLLStorageClass,
235 pub thread_local_mode: ThreadLocalMode,
236 pub unnamed_addr: Option<UnnamedAddr>,
237}
238
239impl Typed for GlobalAlias {
240 fn get_type(&self, _types: &Types) -> TypeRef {
241 self.ty.clone()
242 }
243}
244
245#[derive(PartialEq, Clone, Debug, Hash)]
247pub struct GlobalIFunc {
248 pub name: Name,
249 pub linkage: Linkage,
250 pub visibility: Visibility,
251 pub ty: TypeRef,
252 pub resolver_fn: ConstantRef,
253}
254
255impl Typed for GlobalIFunc {
256 fn get_type(&self, _types: &Types) -> TypeRef {
257 self.ty.clone()
258 }
259}
260
261#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
262pub enum UnnamedAddr {
263 Local,
264 Global,
265}
266
267#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
269pub enum Linkage {
270 Private,
271 Internal,
272 External,
273 ExternalWeak,
274 AvailableExternally,
275 LinkOnceAny,
276 LinkOnceODR,
277 LinkOnceODRAutoHide,
278 WeakAny,
279 WeakODR,
280 Common,
281 Appending,
282 DLLImport,
283 DLLExport,
284 Ghost,
285 LinkerPrivate,
286 LinkerPrivateWeak,
287}
288
289#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
291pub enum Visibility {
292 Default,
293 Hidden,
294 Protected,
295}
296
297#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
299pub enum DLLStorageClass {
300 Default,
301 Import,
302 Export,
303}
304
305#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
307pub enum ThreadLocalMode {
308 NotThreadLocal,
309 GeneralDynamic,
310 LocalDynamic,
311 InitialExec,
312 LocalExec,
313}
314
315pub type AddrSpace = u32;
317
318#[derive(PartialEq, Eq, Clone, Debug, Hash)]
320pub struct FunctionAttributeGroup {
321 pub group_id: GroupID,
322 pub attrs: Vec<FunctionAttribute>,
323}
324
325#[derive(PartialEq, Eq, Clone, Debug, Hash)]
336pub struct Comdat {
337 pub name: String,
338 pub selection_kind: SelectionKind,
339}
340
341#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
342pub enum SelectionKind {
343 Any,
344 ExactMatch,
345 Largest,
346 NoDuplicates,
347 SameSize,
348}
349
350#[derive(Clone, Debug)]
352pub struct DataLayout {
353 pub layout_str: String,
355 pub endianness: Endianness,
357 pub stack_alignment: Option<u32>,
359 pub program_address_space: AddrSpace,
361 pub alloca_address_space: AddrSpace,
363 pub alignments: Alignments,
365 pub mangling: Option<Mangling>,
367 pub native_int_widths: Option<HashSet<u32>>,
369 pub non_integral_ptr_types: HashSet<AddrSpace>,
371}
372
373impl PartialEq for DataLayout {
374 fn eq(&self, other: &Self) -> bool {
375 self.layout_str == other.layout_str
377 }
378}
379
380impl Eq for DataLayout {}
381
382#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
383pub enum Endianness {
384 LittleEndian,
386 BigEndian,
388}
389
390#[derive(Clone, PartialEq, Eq, Debug, Hash)]
393pub struct Alignment {
394 pub abi: u32,
396 pub pref: u32,
398}
399
400#[derive(Clone, PartialEq, Eq, Debug, Hash)]
403pub struct FunctionPtrAlignment {
404 pub independent: bool,
407 pub abi: u32,
409}
410
411#[derive(Clone, PartialEq, Eq, Debug, Hash)]
414pub struct PointerLayout {
415 pub size: u32,
417 pub alignment: Alignment,
419 pub index_size: u32,
421}
422
423#[derive(Clone, Debug)]
426pub struct Alignments {
427 int_alignments: BTreeMap<u32, Alignment>,
431 vec_alignments: BTreeMap<u32, Alignment>,
435 fp_alignments: HashMap<u32, Alignment>,
437 agg_alignment: Alignment,
439 fptr_alignment: FunctionPtrAlignment,
441 fptr_alignment_as_alignment: Alignment,
443 pointer_layouts: HashMap<AddrSpace, PointerLayout>,
445}
446
447impl Alignments {
448 pub fn type_alignment(&self, ty: &Type) -> &Alignment {
450 match ty {
451 Type::IntegerType { bits } => self.int_alignment(*bits),
452 Type::VectorType {
453 element_type,
454 num_elements,
455 ..
456 } => {
457 let element_size_bits = match element_type.as_ref() {
458 Type::IntegerType { bits } => *bits,
459 Type::FPType(fpt) => Self::fpt_size(*fpt),
460 ty => panic!("Didn't expect a vector with element type {:?}", ty),
461 };
462 self.vec_alignment(element_size_bits * (*num_elements as u32))
463 },
464 Type::FPType(fpt) => self.fp_alignment(*fpt),
465 Type::StructType { .. } | Type::NamedStructType { .. } | Type::ArrayType { .. } => {
466 self.agg_alignment()
467 },
468 #[cfg(feature = "llvm-14-or-lower")]
469 Type::PointerType {
470 pointee_type,
471 addr_space,
472 } => match pointee_type.as_ref() {
473 Type::FuncType { .. } => &self.fptr_alignment_as_alignment,
474 _ => &self.ptr_alignment(*addr_space).alignment,
475 },
476 #[cfg(feature = "llvm-15-or-greater")]
477 Type::PointerType { addr_space } => &self.ptr_alignment(*addr_space).alignment,
478 _ => panic!("Don't know how to get the alignment of {:?}", ty),
479 }
480 }
481
482 pub fn int_alignment(&self, size: u32) -> &Alignment {
484 if let Some(alignment) = self.int_alignments.get(&size) {
486 return alignment;
487 }
488 let next_largest_entry = self.int_alignments.iter().find(|(&k, _)| k > size);
490 match next_largest_entry {
491 Some((_, alignment)) => alignment,
492 None => {
493 self.int_alignments
495 .values()
496 .rev()
497 .next()
498 .expect("Should have at least one explicit entry")
499 },
500 }
501 }
502
503 pub fn vec_alignment(&self, size: u32) -> &Alignment {
505 if let Some(alignment) = self.vec_alignments.get(&size) {
507 return alignment;
508 }
509 let next_smaller_entry = self.vec_alignments.iter().find(|(&k, _)| k < size);
511 match next_smaller_entry {
512 Some((_, alignment)) => alignment,
513 None => {
514 self.vec_alignments
518 .values()
519 .next()
520 .expect("Should have at least one explicit entry")
521 },
522 }
523 }
524
525 pub fn fp_alignment(&self, fpt: FPType) -> &Alignment {
527 self.fp_alignments
528 .get(&Self::fpt_size(fpt))
529 .unwrap_or_else(|| {
530 panic!(
531 "No alignment information for {:?} - does the target support that type?",
532 fpt
533 )
534 })
535 }
536
537 pub fn agg_alignment(&self) -> &Alignment {
539 &self.agg_alignment
540 }
541
542 pub fn fptr_alignment(&self) -> &FunctionPtrAlignment {
544 &self.fptr_alignment
545 }
546
547 pub fn ptr_alignment(&self, addr_space: AddrSpace) -> &PointerLayout {
549 match self.pointer_layouts.get(&addr_space) {
550 Some(layout) => layout,
551 None => self
552 .pointer_layouts
553 .get(&0)
554 .expect("Should have a pointer layout for address space 0"),
555 }
556 }
557
558 fn fpt_size(fpt: FPType) -> u32 {
560 match fpt {
561 FPType::Half => 16,
562 #[cfg(feature = "llvm-11-or-greater")]
563 FPType::BFloat => 16,
564 FPType::Single => 32,
565 FPType::Double => 64,
566 FPType::FP128 => 128,
567 FPType::X86_FP80 => 80,
568 FPType::PPC_FP128 => 128,
569 }
570 }
571}
572
573#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
575pub enum Mangling {
576 ELF,
577 MIPS,
578 MachO,
579 WindowsX86COFF,
580 WindowsCOFF,
581 #[cfg(feature = "llvm-11-or-greater")]
582 XCOFF,
583}
584
585use crate::constant::Constant;
590use crate::from_llvm::*;
591use crate::function::AttributesData;
592use llvm_sys::comdat::*;
593use llvm_sys::{
594 LLVMDLLStorageClass,
595 LLVMLinkage,
596 LLVMThreadLocalMode,
597 LLVMUnnamedAddr,
598 LLVMVisibility,
599};
600
601pub(crate) struct ModuleContext<'a> {
604 pub types: TypesBuilder,
605 pub attrsdata: AttributesData,
606 #[allow(clippy::mutable_key_type)]
609 pub constants: HashMap<LLVMValueRef, ConstantRef>,
610 #[allow(clippy::mutable_key_type)]
613 pub global_names: &'a HashMap<LLVMValueRef, Name>,
614}
615
616impl<'a> ModuleContext<'a> {
617 #[allow(clippy::mutable_key_type)]
619 fn new(global_names: &'a HashMap<LLVMValueRef, Name>) -> Self {
620 Self {
621 types: TypesBuilder::new(),
622 attrsdata: AttributesData::create(),
623 constants: HashMap::new(),
624 global_names,
625 }
626 }
627}
628
629impl Module {
630 pub(crate) fn from_llvm_ref(module: LLVMModuleRef) -> Self {
631 debug!("Creating a Module from an LLVMModuleRef");
632 let mut global_ctr = 0; #[allow(clippy::mutable_key_type)]
643 let global_names: HashMap<LLVMValueRef, Name> = get_defined_functions(module)
644 .chain(get_declared_functions(module))
645 .chain(get_globals(module))
646 .chain(get_global_aliases(module))
647 .chain(get_global_ifuncs(module))
648 .map(|g| {
649 (
650 g,
651 Name::name_or_num(unsafe { get_value_name(g) }, &mut global_ctr),
652 )
653 })
654 .collect();
655 global_ctr = 0; let mut ctx = ModuleContext::new(&global_names);
658
659 Self {
660 name: unsafe { get_module_identifier(module) },
661 source_file_name: unsafe { get_source_file_name(module) },
662 data_layout: DataLayout::from_module_ref(module),
663 target_triple: unsafe { get_target(module) },
664 functions: get_defined_functions(module)
665 .map(|f| Function::from_llvm_ref(f, &mut ctx))
666 .collect(),
667 func_declarations: get_declared_functions(module)
668 .map(|f| FunctionDeclaration::from_llvm_ref(f, &mut ctx))
669 .collect(),
670 global_vars: get_globals(module)
671 .map(|g| GlobalVariable::from_llvm_ref(g, &mut global_ctr, &mut ctx))
672 .collect(),
673 global_aliases: get_global_aliases(module)
674 .map(|g| GlobalAlias::from_llvm_ref(g, &mut global_ctr, &mut ctx))
675 .collect(),
676 global_ifuncs: get_global_ifuncs(module)
677 .map(|g| GlobalIFunc::from_llvm_ref(g, &mut global_ctr, &mut ctx))
678 .collect(),
679 inline_assembly: unsafe { get_module_inline_asm(module) },
681 types: ctx.types.build(),
685 }
686 }
687}
688
689impl GlobalVariable {
690 pub(crate) fn from_llvm_ref(
691 global: LLVMValueRef,
692 ctr: &mut usize,
693 ctx: &mut ModuleContext,
694 ) -> Self {
695 let ty = ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(global) });
696 let addr_space = match ty.as_ref() {
697 Type::PointerType { addr_space, .. } => *addr_space,
698 _ => panic!("GlobalVariable has a non-pointer type, {:?}", ty),
699 };
700 debug!("Processing a GlobalVariable with type {:?}", ty);
701 Self {
702 name: Name::name_or_num(unsafe { get_value_name(global) }, ctr),
703 linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(global) }),
704 visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(global) }),
705 is_constant: unsafe { LLVMIsGlobalConstant(global) } != 0,
706 ty,
707 addr_space,
708 dll_storage_class: DLLStorageClass::from_llvm(unsafe {
709 LLVMGetDLLStorageClass(global)
710 }),
711 thread_local_mode: ThreadLocalMode::from_llvm(unsafe {
712 LLVMGetThreadLocalMode(global)
713 }),
714 unnamed_addr: UnnamedAddr::from_llvm(unsafe { LLVMGetUnnamedAddress(global) }),
715 initializer: {
716 let it = unsafe { LLVMGetInitializer(global) };
717 if it.is_null() {
718 None
719 } else {
720 Some(Constant::from_llvm_ref(it, ctx))
721 }
722 },
723 section: unsafe { get_section(global) },
724 comdat: {
725 let comdat = unsafe { LLVMGetComdat(global) };
726 if comdat.is_null() {
727 None
728 } else {
729 Some(Comdat::from_llvm_ref(unsafe { LLVMGetComdat(global) }))
730 }
731 },
732 alignment: unsafe { LLVMGetAlignment(global) },
733 debugloc: DebugLoc::from_llvm_no_col(global),
734 }
736 }
737}
738
739impl GlobalAlias {
740 pub(crate) fn from_llvm_ref(
741 alias: LLVMValueRef,
742 ctr: &mut usize,
743 ctx: &mut ModuleContext,
744 ) -> Self {
745 let ty = ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(alias) });
746 let addr_space = match ty.as_ref() {
747 Type::PointerType { addr_space, .. } => *addr_space,
748 _ => panic!("GlobalAlias has a non-pointer type, {:?}", ty),
749 };
750 Self {
751 name: Name::name_or_num(unsafe { get_value_name(alias) }, ctr),
752 aliasee: Constant::from_llvm_ref(unsafe { LLVMAliasGetAliasee(alias) }, ctx),
753 linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(alias) }),
754 visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(alias) }),
755 ty,
756 addr_space,
757 dll_storage_class: DLLStorageClass::from_llvm(unsafe { LLVMGetDLLStorageClass(alias) }),
758 thread_local_mode: ThreadLocalMode::from_llvm(unsafe { LLVMGetThreadLocalMode(alias) }),
759 unnamed_addr: UnnamedAddr::from_llvm(unsafe { LLVMGetUnnamedAddress(alias) }),
760 }
761 }
762}
763
764impl GlobalIFunc {
765 pub(crate) fn from_llvm_ref(
766 ifunc: LLVMValueRef,
767 ctr: &mut usize,
768 ctx: &mut ModuleContext,
769 ) -> Self {
770 Self {
771 name: Name::name_or_num(unsafe { get_value_name(ifunc) }, ctr),
772 linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(ifunc) }),
773 visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(ifunc) }),
774 ty: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(ifunc) }),
775 resolver_fn: Constant::from_llvm_ref(unsafe { LLVMGetGlobalIFuncResolver(ifunc) }, ctx),
776 }
777 }
778}
779
780impl UnnamedAddr {
789 pub(crate) fn from_llvm(ua: LLVMUnnamedAddr) -> Option<Self> {
790 use LLVMUnnamedAddr::*;
791 match ua {
792 LLVMNoUnnamedAddr => None,
793 LLVMLocalUnnamedAddr => Some(UnnamedAddr::Local),
794 LLVMGlobalUnnamedAddr => Some(UnnamedAddr::Global),
795 }
796 }
797}
798
799impl Linkage {
800 pub(crate) fn from_llvm(linkage: LLVMLinkage) -> Self {
801 use LLVMLinkage::*;
802 match linkage {
803 LLVMExternalLinkage => Linkage::External,
804 LLVMAvailableExternallyLinkage => Linkage::AvailableExternally,
805 LLVMLinkOnceAnyLinkage => Linkage::LinkOnceAny,
806 LLVMLinkOnceODRLinkage => Linkage::LinkOnceODR,
807 LLVMLinkOnceODRAutoHideLinkage => Linkage::LinkOnceODRAutoHide,
808 LLVMWeakAnyLinkage => Linkage::WeakAny,
809 LLVMWeakODRLinkage => Linkage::WeakODR,
810 LLVMAppendingLinkage => Linkage::Appending,
811 LLVMInternalLinkage => Linkage::Internal,
812 LLVMPrivateLinkage => Linkage::Private,
813 LLVMDLLImportLinkage => Linkage::DLLImport,
814 LLVMDLLExportLinkage => Linkage::DLLExport,
815 LLVMExternalWeakLinkage => Linkage::ExternalWeak,
816 LLVMGhostLinkage => Linkage::Ghost,
817 LLVMCommonLinkage => Linkage::Common,
818 LLVMLinkerPrivateLinkage => Linkage::LinkerPrivate,
819 LLVMLinkerPrivateWeakLinkage => Linkage::LinkerPrivateWeak,
820 }
821 }
822}
823
824impl Visibility {
825 pub(crate) fn from_llvm(visibility: LLVMVisibility) -> Self {
826 use LLVMVisibility::*;
827 match visibility {
828 LLVMDefaultVisibility => Visibility::Default,
829 LLVMHiddenVisibility => Visibility::Hidden,
830 LLVMProtectedVisibility => Visibility::Protected,
831 }
832 }
833}
834
835impl DLLStorageClass {
836 pub(crate) fn from_llvm(dllsc: LLVMDLLStorageClass) -> Self {
837 use LLVMDLLStorageClass::*;
838 match dllsc {
839 LLVMDefaultStorageClass => DLLStorageClass::Default,
840 LLVMDLLImportStorageClass => DLLStorageClass::Import,
841 LLVMDLLExportStorageClass => DLLStorageClass::Export,
842 }
843 }
844}
845
846impl ThreadLocalMode {
847 pub(crate) fn from_llvm(tlm: LLVMThreadLocalMode) -> Self {
848 use LLVMThreadLocalMode::*;
849 match tlm {
850 LLVMNotThreadLocal => ThreadLocalMode::NotThreadLocal,
851 LLVMGeneralDynamicTLSModel => ThreadLocalMode::GeneralDynamic,
852 LLVMLocalDynamicTLSModel => ThreadLocalMode::LocalDynamic,
853 LLVMInitialExecTLSModel => ThreadLocalMode::InitialExec,
854 LLVMLocalExecTLSModel => ThreadLocalMode::LocalExec,
855 }
856 }
857}
858
859impl Comdat {
860 pub(crate) fn from_llvm_ref(comdat: LLVMComdatRef) -> Self {
861 Self {
862 name: "error: not yet implemented: Comdat.name".to_owned(), selection_kind: SelectionKind::from_llvm(unsafe { LLVMGetComdatSelectionKind(comdat) }),
864 }
865 }
866}
867
868impl SelectionKind {
869 pub(crate) fn from_llvm(sk: LLVMComdatSelectionKind) -> Self {
870 use LLVMComdatSelectionKind::*;
871 match sk {
872 LLVMAnyComdatSelectionKind => SelectionKind::Any,
873 LLVMExactMatchComdatSelectionKind => SelectionKind::ExactMatch,
874 LLVMLargestComdatSelectionKind => SelectionKind::Largest,
875 LLVMNoDuplicatesComdatSelectionKind => SelectionKind::NoDuplicates,
876 LLVMSameSizeComdatSelectionKind => SelectionKind::SameSize,
877 }
878 }
879}
880
881impl Default for DataLayout {
882 fn default() -> Self {
883 Self {
884 layout_str: String::new(),
885 endianness: Endianness::BigEndian,
886 stack_alignment: None,
887 program_address_space: 0,
888 alloca_address_space: 0,
889 alignments: Alignments::default(),
890 mangling: None,
891 native_int_widths: None,
892 non_integral_ptr_types: HashSet::new(),
893 }
894 }
895}
896
897impl DataLayout {
898 pub(crate) fn from_module_ref(module: LLVMModuleRef) -> Self {
899 let layout_str = unsafe { get_data_layout_str(module) };
900 let mut data_layout = DataLayout {
901 layout_str,
902 ..Default::default()
903 };
904 for spec in data_layout.layout_str.split('-') {
905 if spec == "E" {
906 data_layout.endianness = Endianness::BigEndian;
907 } else if spec == "e" {
908 data_layout.endianness = Endianness::LittleEndian;
909 } else if let Some(stripped) = spec.strip_prefix('S') {
910 data_layout.stack_alignment =
911 Some(stripped.parse().expect("datalayout 'S': Failed to parse"));
912 } else if let Some(stripped) = spec.strip_prefix('P') {
913 data_layout.program_address_space =
914 stripped.parse().expect("datalayout 'P': Failed to parse");
915 } else if let Some(stripped) = spec.strip_prefix('A') {
916 data_layout.alloca_address_space =
917 stripped.parse().expect("datalayout 'A': Failed to parse");
918 } else if spec.starts_with('p') {
919 let mut chunks = spec.split(':');
920 let first_chunk = chunks.next().unwrap();
921 let addr_space: AddrSpace = if first_chunk == "p" {
922 0
923 } else {
924 first_chunk[1 ..]
925 .parse()
926 .expect("datalayout 'p': Failed to parse address space")
927 };
928 let second_chunk = chunks
929 .next()
930 .expect("datalayout 'p' spec should have a size chunk");
931 let size: u32 = second_chunk
932 .parse()
933 .expect("datalayout 'p': Failed to parse pointer size");
934 let third_chunk = chunks
935 .next()
936 .expect("datalayout 'p' spec should have an abi chunk");
937 let abi: u32 = third_chunk
938 .parse()
939 .expect("datalayout 'p': Failed to parse abi");
940 let pref: u32 = if let Some(fourth_chunk) = chunks.next() {
941 fourth_chunk
942 .parse()
943 .expect("datalayout 'p': Failed to parse pref")
944 } else {
945 abi
946 };
947 let idx: u32 = if let Some(fifth_chunk) = chunks.next() {
948 fifth_chunk
949 .parse()
950 .expect("datalayout 'p': Failed to parse idx")
951 } else {
952 size
953 };
954 assert!(chunks.next().is_none(), "datalayout 'p': Too many chunks");
955 data_layout.alignments.pointer_layouts.insert(
956 addr_space,
957 PointerLayout {
958 size,
959 alignment: Alignment { abi, pref },
960 index_size: idx,
961 },
962 );
963 } else if spec.starts_with('i') {
964 let mut chunks = spec.split(':');
965 let first_chunk = chunks.next().unwrap();
966 let size: u32 = first_chunk[1 ..]
967 .parse()
968 .expect("datalayout 'i': Failed to parse size");
969 let second_chunk = chunks
970 .next()
971 .expect("datalayout 'i' spec should have an abi chunk");
972 let abi: u32 = second_chunk
973 .parse()
974 .expect("datalayout 'i': Failed to parse abi");
975 let pref = if let Some(third_chunk) = chunks.next() {
976 third_chunk
977 .parse()
978 .expect("datalayout 'i': Failed to parse pref")
979 } else {
980 abi
981 };
982 assert!(chunks.next().is_none(), "datalayout 'i': Too many chunks");
983 data_layout
984 .alignments
985 .int_alignments
986 .insert(size, Alignment { abi, pref });
987 } else if spec.starts_with('v') {
988 let mut chunks = spec.split(':');
989 let first_chunk = chunks.next().unwrap();
990 let size: u32 = first_chunk[1 ..]
991 .parse()
992 .expect("datalayout 'v': Failed to parse size");
993 let second_chunk = chunks
994 .next()
995 .expect("datalayout 'v' spec should have an abi chunk");
996 let abi: u32 = second_chunk
997 .parse()
998 .expect("datalayout 'v': Failed to parse abi");
999 let pref = if let Some(third_chunk) = chunks.next() {
1000 third_chunk
1001 .parse()
1002 .expect("datalayout 'v': Failed to parse pref")
1003 } else {
1004 abi
1005 };
1006 assert!(chunks.next().is_none(), "datalayout 'v': Too many chunks");
1007 data_layout
1008 .alignments
1009 .vec_alignments
1010 .insert(size, Alignment { abi, pref });
1011 } else if spec.starts_with('f') {
1012 let mut chunks = spec.split(':');
1013 let first_chunk = chunks.next().unwrap();
1014 let size: u32 = first_chunk[1 ..]
1015 .parse()
1016 .expect("datalayout 'f': Failed to parse size");
1017 let second_chunk = chunks
1018 .next()
1019 .expect("datalayout 'f' spec should have an abi chunk");
1020 let abi: u32 = second_chunk
1021 .parse()
1022 .expect("datalayout 'f': Failed to parse abi");
1023 let pref = if let Some(third_chunk) = chunks.next() {
1024 third_chunk
1025 .parse()
1026 .expect("datalayout 'f': Failed to parse pref")
1027 } else {
1028 abi
1029 };
1030 assert!(chunks.next().is_none(), "datalayout 'f': Too many chunks");
1031 data_layout
1032 .alignments
1033 .fp_alignments
1034 .insert(size, Alignment { abi, pref });
1035 } else if spec.starts_with('a') {
1036 let mut chunks = spec.split(':');
1037 let first_chunk = chunks.next().unwrap();
1038 assert!(first_chunk == "a" || first_chunk == "a0");
1039 let second_chunk = chunks
1040 .next()
1041 .expect("datalayout 'a' spec should have an abi chunk");
1042 let abi: u32 = second_chunk
1043 .parse()
1044 .expect("datalayout 'a': Failed to parse abi");
1045 let pref = if let Some(third_chunk) = chunks.next() {
1046 third_chunk
1047 .parse()
1048 .expect("datalayout 'a': Failed to parse pref")
1049 } else {
1050 abi
1051 };
1052 assert!(chunks.next().is_none(), "datalayout 'a': Too many chunks");
1053 data_layout.alignments.agg_alignment = Alignment { abi, pref };
1054 } else if let Some(stripped) = spec.strip_prefix("Fi") {
1055 let abi: u32 = stripped
1056 .parse()
1057 .expect("datalayout 'Fi': Failed to parse abi");
1058 data_layout.alignments.fptr_alignment = FunctionPtrAlignment {
1059 independent: true,
1060 abi,
1061 };
1062 data_layout.alignments.fptr_alignment_as_alignment =
1063 Alignment { abi, pref: abi };
1064 } else if let Some(stripped) = spec.strip_prefix("Fn") {
1065 let abi: u32 = stripped
1066 .parse()
1067 .expect("datalayout 'Fn': Failed to parse abi");
1068 data_layout.alignments.fptr_alignment = FunctionPtrAlignment {
1069 independent: false,
1070 abi,
1071 };
1072 data_layout.alignments.fptr_alignment_as_alignment =
1073 Alignment { abi, pref: abi };
1074 } else if spec.starts_with('m') {
1075 let mut chunks = spec.split(':');
1076 let first_chunk = chunks.next().unwrap();
1077 assert_eq!(first_chunk, "m");
1078 let second_chunk = chunks
1079 .next()
1080 .expect("datalayout 'm' spec should have a mangling chunk");
1081 let mangling = match second_chunk {
1082 "e" => Mangling::ELF,
1083 "m" => Mangling::MIPS,
1084 "o" => Mangling::MachO,
1085 "x" => Mangling::WindowsX86COFF,
1086 "w" => Mangling::WindowsCOFF,
1087 #[cfg(feature = "llvm-11-or-greater")]
1088 "a" => Mangling::XCOFF,
1089 _ => panic!("datalayout 'm': Unknown mangling {:?}", second_chunk),
1090 };
1091 assert!(chunks.next().is_none(), "datalayout 'm': Too many chunks");
1092 data_layout.mangling = Some(mangling);
1093 } else if spec.starts_with("ni") {
1094 let mut chunks = spec.split(':');
1095 let first_chunk = chunks.next().unwrap();
1096 assert_eq!(first_chunk, "ni");
1097 for chunk in chunks {
1098 let addr_space: AddrSpace = chunk
1099 .parse()
1100 .expect("datalayout 'ni': Failed to parse addr space");
1101 assert_ne!(addr_space, 0, "LLVM spec does not allow address space 0 to have non-integral pointer types");
1102 data_layout.non_integral_ptr_types.insert(addr_space);
1103 }
1104 } else if spec.starts_with('n') {
1105 let native_int_widths = data_layout
1106 .native_int_widths
1107 .get_or_insert_with(HashSet::new);
1108 let mut chunks = spec.split(':');
1109 let first_chunk = chunks.next().unwrap();
1110 let size = first_chunk[1 ..]
1111 .parse()
1112 .expect("datalayout 'n': Failed to parse first size");
1113 native_int_widths.insert(size);
1114 for chunk in chunks {
1115 let size = chunk.parse().expect("datalayout 'n': Failed to parse size");
1116 native_int_widths.insert(size);
1117 }
1118 } else if spec.is_empty() {
1119 } else {
1121 panic!("datalayout: Unknown spec {:?}", spec);
1122 }
1123 }
1124 data_layout
1125 }
1126}
1127
1128impl Default for Alignments {
1129 fn default() -> Self {
1130 Self {
1131 int_alignments: vec![
1135 (1, Alignment { abi: 8, pref: 8 }),
1136 (8, Alignment { abi: 8, pref: 8 }),
1137 (16, Alignment { abi: 16, pref: 16 }),
1138 (32, Alignment { abi: 32, pref: 32 }),
1139 (64, Alignment { abi: 32, pref: 64 }),
1140 ]
1141 .into_iter()
1142 .collect(),
1143 vec_alignments: vec![
1147 (64, Alignment { abi: 64, pref: 64 }),
1148 (
1149 128,
1150 Alignment {
1151 abi: 128,
1152 pref: 128,
1153 },
1154 ),
1155 ]
1156 .into_iter()
1157 .collect(),
1158 fp_alignments: vec![
1160 (16, Alignment { abi: 16, pref: 16 }),
1161 (32, Alignment { abi: 32, pref: 32 }),
1162 (64, Alignment { abi: 64, pref: 64 }),
1163 (
1164 128,
1165 Alignment {
1166 abi: 128,
1167 pref: 128,
1168 },
1169 ),
1170 ]
1171 .into_iter()
1172 .collect(),
1173 agg_alignment: Alignment { abi: 0, pref: 64 },
1175 fptr_alignment: FunctionPtrAlignment {
1177 independent: true,
1178 abi: 64,
1179 },
1180 fptr_alignment_as_alignment: Alignment { abi: 64, pref: 64 },
1182 pointer_layouts: vec![(
1184 0,
1185 PointerLayout {
1186 size: 64,
1187 alignment: Alignment { abi: 64, pref: 64 },
1188 index_size: 64,
1189 },
1190 )]
1191 .into_iter()
1192 .collect(),
1193 }
1194 }
1195}