Skip to main content

inkwell/
targets.rs

1use llvm_sys::target::{
2    LLVMABIAlignmentOfType, LLVMABISizeOfType, LLVMByteOrder, LLVMByteOrdering, LLVMCallFrameAlignmentOfType,
3    LLVMCopyStringRepOfTargetData, LLVMCreateTargetData, LLVMDisposeTargetData, LLVMElementAtOffset,
4    LLVMIntPtrTypeForASInContext, LLVMIntPtrTypeInContext, LLVMOffsetOfElement, LLVMPointerSize, LLVMPointerSizeForAS,
5    LLVMPreferredAlignmentOfGlobal, LLVMPreferredAlignmentOfType, LLVMSizeOfTypeInBits, LLVMStoreSizeOfType,
6    LLVMTargetDataRef,
7};
8use llvm_sys::target_machine::LLVMCreateTargetDataLayout;
9use llvm_sys::target_machine::{
10    LLVMAddAnalysisPasses, LLVMCodeGenFileType, LLVMCodeModel, LLVMCreateTargetMachine, LLVMDisposeTargetMachine,
11    LLVMGetDefaultTargetTriple, LLVMGetFirstTarget, LLVMGetNextTarget, LLVMGetTargetDescription, LLVMGetTargetFromName,
12    LLVMGetTargetFromTriple, LLVMGetTargetMachineCPU, LLVMGetTargetMachineFeatureString, LLVMGetTargetMachineTarget,
13    LLVMGetTargetMachineTriple, LLVMGetTargetName, LLVMRelocMode, LLVMSetTargetMachineAsmVerbosity,
14    LLVMTargetHasAsmBackend, LLVMTargetHasJIT, LLVMTargetHasTargetMachine, LLVMTargetMachineEmitToFile,
15    LLVMTargetMachineEmitToMemoryBuffer, LLVMTargetMachineRef, LLVMTargetRef,
16};
17#[llvm_versions(18..)]
18use llvm_sys::target_machine::{
19    LLVMCreateTargetMachineOptions, LLVMCreateTargetMachineWithOptions, LLVMDisposeTargetMachineOptions,
20    LLVMTargetMachineOptionsRef, LLVMTargetMachineOptionsSetABI, LLVMTargetMachineOptionsSetCPU,
21    LLVMTargetMachineOptionsSetCodeGenOptLevel, LLVMTargetMachineOptionsSetCodeModel,
22    LLVMTargetMachineOptionsSetFeatures, LLVMTargetMachineOptionsSetRelocMode,
23};
24use once_cell::sync::Lazy;
25use std::sync::RwLock;
26
27use crate::context::AsContextRef;
28use crate::data_layout::DataLayout;
29use crate::memory_buffer::MemoryBuffer;
30use crate::module::Module;
31use crate::passes::PassManager;
32use crate::support::{to_c_str, LLVMString};
33use crate::types::{AnyType, AsTypeRef, IntType, StructType};
34use crate::values::{AsValueRef, GlobalValue};
35use crate::{AddressSpace, OptimizationLevel};
36
37use std::default::Default;
38use std::ffi::CStr;
39use std::fmt;
40use std::mem::MaybeUninit;
41use std::path::Path;
42use std::ptr;
43
44#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
45pub enum CodeModel {
46    #[default]
47    Default,
48    JITDefault,
49    Small,
50    Kernel,
51    Medium,
52    Large,
53}
54
55impl From<CodeModel> for LLVMCodeModel {
56    fn from(value: CodeModel) -> Self {
57        match value {
58            CodeModel::Default => LLVMCodeModel::LLVMCodeModelDefault,
59            CodeModel::JITDefault => LLVMCodeModel::LLVMCodeModelJITDefault,
60            CodeModel::Small => LLVMCodeModel::LLVMCodeModelSmall,
61            CodeModel::Kernel => LLVMCodeModel::LLVMCodeModelKernel,
62            CodeModel::Medium => LLVMCodeModel::LLVMCodeModelMedium,
63            CodeModel::Large => LLVMCodeModel::LLVMCodeModelLarge,
64        }
65    }
66}
67
68#[derive(Default, Debug, PartialEq, Eq, Copy, Clone)]
69pub enum RelocMode {
70    #[default]
71    Default,
72    Static,
73    PIC,
74    DynamicNoPic,
75}
76
77impl From<RelocMode> for LLVMRelocMode {
78    fn from(value: RelocMode) -> Self {
79        match value {
80            RelocMode::Default => LLVMRelocMode::LLVMRelocDefault,
81            RelocMode::Static => LLVMRelocMode::LLVMRelocStatic,
82            RelocMode::PIC => LLVMRelocMode::LLVMRelocPIC,
83            RelocMode::DynamicNoPic => LLVMRelocMode::LLVMRelocDynamicNoPic,
84        }
85    }
86}
87
88#[derive(Debug, PartialEq, Eq, Copy, Clone)]
89pub enum FileType {
90    Assembly,
91    Object,
92}
93
94impl FileType {
95    fn as_llvm_file_type(&self) -> LLVMCodeGenFileType {
96        match *self {
97            FileType::Assembly => LLVMCodeGenFileType::LLVMAssemblyFile,
98            FileType::Object => LLVMCodeGenFileType::LLVMObjectFile,
99        }
100    }
101}
102
103// TODO: Doc: Base gets you TargetMachine support, machine_code gets you asm_backend
104#[derive(Copy, Clone, Debug, PartialEq, Eq)]
105pub struct InitializationConfig {
106    pub asm_parser: bool,
107    pub asm_printer: bool,
108    pub base: bool,
109    pub disassembler: bool,
110    pub info: bool,
111    pub machine_code: bool,
112}
113
114impl Default for InitializationConfig {
115    fn default() -> Self {
116        InitializationConfig {
117            asm_parser: true,
118            asm_printer: true,
119            base: true,
120            disassembler: true,
121            info: true,
122            machine_code: true,
123        }
124    }
125}
126
127#[derive(Eq)]
128pub struct TargetTriple {
129    pub(crate) triple: LLVMString,
130}
131
132impl TargetTriple {
133    pub unsafe fn new(triple: LLVMString) -> TargetTriple {
134        TargetTriple { triple }
135    }
136
137    pub fn create(triple: &str) -> TargetTriple {
138        let c_string = to_c_str(triple);
139
140        TargetTriple {
141            triple: LLVMString::create_from_c_str(&c_string),
142        }
143    }
144
145    pub fn as_str(&self) -> &CStr {
146        unsafe { CStr::from_ptr(self.as_ptr()) }
147    }
148
149    pub fn as_ptr(&self) -> *const ::libc::c_char {
150        self.triple.as_ptr()
151    }
152}
153
154impl PartialEq for TargetTriple {
155    fn eq(&self, other: &TargetTriple) -> bool {
156        self.triple == other.triple
157    }
158}
159
160impl fmt::Debug for TargetTriple {
161    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
162        write!(f, "TargetTriple({:?})", self.triple)
163    }
164}
165
166impl fmt::Display for TargetTriple {
167    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
168        write!(f, "TargetTriple({:?})", self.triple)
169    }
170}
171
172static TARGET_LOCK: Lazy<RwLock<()>> = Lazy::new(|| RwLock::new(()));
173
174// NOTE: Versions verified as target-complete: 3.6, 3.7, 3.8, 3.9, 4.0
175#[derive(Debug, Eq, PartialEq)]
176pub struct Target {
177    target: LLVMTargetRef,
178}
179
180impl Target {
181    pub unsafe fn new(target: LLVMTargetRef) -> Self {
182        assert!(!target.is_null());
183
184        Target { target }
185    }
186
187    /// Acquires the underlying raw pointer belonging to this `Target` type.
188    pub fn as_mut_ptr(&self) -> LLVMTargetRef {
189        self.target
190    }
191
192    // REVIEW: Should this just initialize all? Is opt into each a good idea?
193    #[cfg(feature = "target-x86")]
194    pub fn initialize_x86(config: &InitializationConfig) {
195        use llvm_sys::target::{
196            LLVMInitializeX86AsmParser, LLVMInitializeX86AsmPrinter, LLVMInitializeX86Disassembler,
197            LLVMInitializeX86Target, LLVMInitializeX86TargetInfo, LLVMInitializeX86TargetMC,
198        };
199
200        if config.base {
201            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
202            unsafe { LLVMInitializeX86Target() };
203        }
204
205        if config.info {
206            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
207            unsafe { LLVMInitializeX86TargetInfo() };
208        }
209
210        if config.asm_printer {
211            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
212            unsafe { LLVMInitializeX86AsmPrinter() };
213        }
214
215        if config.asm_parser {
216            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
217            unsafe { LLVMInitializeX86AsmParser() };
218        }
219
220        if config.disassembler {
221            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
222            unsafe { LLVMInitializeX86Disassembler() };
223        }
224
225        if config.machine_code {
226            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
227            unsafe { LLVMInitializeX86TargetMC() };
228        }
229    }
230
231    #[cfg(feature = "target-arm")]
232    pub fn initialize_arm(config: &InitializationConfig) {
233        use llvm_sys::target::{
234            LLVMInitializeARMAsmParser, LLVMInitializeARMAsmPrinter, LLVMInitializeARMDisassembler,
235            LLVMInitializeARMTarget, LLVMInitializeARMTargetInfo, LLVMInitializeARMTargetMC,
236        };
237
238        if config.base {
239            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
240            unsafe { LLVMInitializeARMTarget() };
241        }
242
243        if config.info {
244            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
245            unsafe { LLVMInitializeARMTargetInfo() };
246        }
247
248        if config.asm_printer {
249            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
250            unsafe { LLVMInitializeARMAsmPrinter() };
251        }
252
253        if config.asm_parser {
254            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
255            unsafe { LLVMInitializeARMAsmParser() };
256        }
257
258        if config.disassembler {
259            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
260            unsafe { LLVMInitializeARMDisassembler() };
261        }
262
263        if config.machine_code {
264            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
265            unsafe { LLVMInitializeARMTargetMC() };
266        }
267    }
268
269    #[cfg(feature = "target-mips")]
270    pub fn initialize_mips(config: &InitializationConfig) {
271        use llvm_sys::target::{
272            LLVMInitializeMipsAsmParser, LLVMInitializeMipsAsmPrinter, LLVMInitializeMipsDisassembler,
273            LLVMInitializeMipsTarget, LLVMInitializeMipsTargetInfo, LLVMInitializeMipsTargetMC,
274        };
275
276        if config.base {
277            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
278            unsafe { LLVMInitializeMipsTarget() };
279        }
280
281        if config.info {
282            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
283            unsafe { LLVMInitializeMipsTargetInfo() };
284        }
285
286        if config.asm_printer {
287            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
288            unsafe { LLVMInitializeMipsAsmPrinter() };
289        }
290
291        if config.asm_parser {
292            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
293            unsafe { LLVMInitializeMipsAsmParser() };
294        }
295
296        if config.disassembler {
297            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
298            unsafe { LLVMInitializeMipsDisassembler() };
299        }
300
301        if config.machine_code {
302            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
303            unsafe { LLVMInitializeMipsTargetMC() };
304        }
305    }
306
307    #[cfg(feature = "target-aarch64")]
308    pub fn initialize_aarch64(config: &InitializationConfig) {
309        use llvm_sys::target::{
310            LLVMInitializeAArch64AsmParser, LLVMInitializeAArch64AsmPrinter, LLVMInitializeAArch64Disassembler,
311            LLVMInitializeAArch64Target, LLVMInitializeAArch64TargetInfo, LLVMInitializeAArch64TargetMC,
312        };
313
314        if config.base {
315            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
316            unsafe { LLVMInitializeAArch64Target() };
317        }
318
319        if config.info {
320            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
321            unsafe { LLVMInitializeAArch64TargetInfo() };
322        }
323
324        if config.asm_printer {
325            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
326            unsafe { LLVMInitializeAArch64AsmPrinter() };
327        }
328
329        if config.asm_parser {
330            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
331            unsafe { LLVMInitializeAArch64AsmParser() };
332        }
333
334        if config.disassembler {
335            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
336            unsafe { LLVMInitializeAArch64Disassembler() };
337        }
338
339        if config.machine_code {
340            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
341            unsafe { LLVMInitializeAArch64TargetMC() };
342        }
343    }
344
345    #[cfg(feature = "target-amdgpu")]
346    pub fn initialize_amd_gpu(config: &InitializationConfig) {
347        use llvm_sys::target::{
348            LLVMInitializeAMDGPUAsmParser, LLVMInitializeAMDGPUAsmPrinter, LLVMInitializeAMDGPUTarget,
349            LLVMInitializeAMDGPUTargetInfo, LLVMInitializeAMDGPUTargetMC,
350        };
351
352        if config.base {
353            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
354            unsafe { LLVMInitializeAMDGPUTarget() };
355        }
356
357        if config.info {
358            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
359            unsafe { LLVMInitializeAMDGPUTargetInfo() };
360        }
361
362        if config.asm_printer {
363            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
364            unsafe { LLVMInitializeAMDGPUAsmPrinter() };
365        }
366
367        if config.asm_parser {
368            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
369            unsafe { LLVMInitializeAMDGPUAsmParser() };
370        }
371
372        if config.machine_code {
373            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
374            unsafe { LLVMInitializeAMDGPUTargetMC() };
375        }
376
377        // Disassembler Status Unknown
378    }
379
380    #[cfg(feature = "target-systemz")]
381    pub fn initialize_system_z(config: &InitializationConfig) {
382        use llvm_sys::target::{
383            LLVMInitializeSystemZAsmParser, LLVMInitializeSystemZAsmPrinter, LLVMInitializeSystemZDisassembler,
384            LLVMInitializeSystemZTarget, LLVMInitializeSystemZTargetInfo, LLVMInitializeSystemZTargetMC,
385        };
386
387        if config.base {
388            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
389            unsafe { LLVMInitializeSystemZTarget() };
390        }
391
392        if config.info {
393            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
394            unsafe { LLVMInitializeSystemZTargetInfo() };
395        }
396
397        if config.asm_printer {
398            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
399            unsafe { LLVMInitializeSystemZAsmPrinter() };
400        }
401
402        if config.asm_parser {
403            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
404            unsafe { LLVMInitializeSystemZAsmParser() };
405        }
406
407        if config.disassembler {
408            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
409            unsafe { LLVMInitializeSystemZDisassembler() };
410        }
411
412        if config.machine_code {
413            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
414            unsafe { LLVMInitializeSystemZTargetMC() };
415        }
416    }
417
418    #[cfg(feature = "target-hexagon")]
419    pub fn initialize_hexagon(config: &InitializationConfig) {
420        use llvm_sys::target::{
421            LLVMInitializeHexagonAsmPrinter, LLVMInitializeHexagonDisassembler, LLVMInitializeHexagonTarget,
422            LLVMInitializeHexagonTargetInfo, LLVMInitializeHexagonTargetMC,
423        };
424
425        if config.base {
426            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
427            unsafe { LLVMInitializeHexagonTarget() };
428        }
429
430        if config.info {
431            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
432            unsafe { LLVMInitializeHexagonTargetInfo() };
433        }
434
435        if config.asm_printer {
436            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
437            unsafe { LLVMInitializeHexagonAsmPrinter() };
438        }
439
440        // Asm parser status unknown
441
442        if config.disassembler {
443            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
444            unsafe { LLVMInitializeHexagonDisassembler() };
445        }
446
447        if config.machine_code {
448            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
449            unsafe { LLVMInitializeHexagonTargetMC() };
450        }
451    }
452
453    #[cfg(feature = "target-nvptx")]
454    pub fn initialize_nvptx(config: &InitializationConfig) {
455        use llvm_sys::target::{
456            LLVMInitializeNVPTXAsmPrinter, LLVMInitializeNVPTXTarget, LLVMInitializeNVPTXTargetInfo,
457            LLVMInitializeNVPTXTargetMC,
458        };
459
460        if config.base {
461            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
462            unsafe { LLVMInitializeNVPTXTarget() };
463        }
464
465        if config.info {
466            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
467            unsafe { LLVMInitializeNVPTXTargetInfo() };
468        }
469
470        if config.asm_printer {
471            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
472            unsafe { LLVMInitializeNVPTXAsmPrinter() };
473        }
474
475        // Asm parser status unknown
476
477        if config.machine_code {
478            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
479            unsafe { LLVMInitializeNVPTXTargetMC() };
480        }
481
482        // Disassembler status unknown
483    }
484
485    #[cfg(feature = "target-msp430")]
486    pub fn initialize_msp430(config: &InitializationConfig) {
487        use llvm_sys::target::{
488            LLVMInitializeMSP430AsmPrinter, LLVMInitializeMSP430Target, LLVMInitializeMSP430TargetInfo,
489            LLVMInitializeMSP430TargetMC,
490        };
491
492        if config.base {
493            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
494            unsafe { LLVMInitializeMSP430Target() };
495        }
496
497        if config.info {
498            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
499            unsafe { LLVMInitializeMSP430TargetInfo() };
500        }
501
502        if config.asm_printer {
503            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
504            unsafe { LLVMInitializeMSP430AsmPrinter() };
505        }
506
507        // Asm parser status unknown
508
509        if config.machine_code {
510            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
511            unsafe { LLVMInitializeMSP430TargetMC() };
512        }
513
514        // Disassembler status unknown
515    }
516
517    #[cfg(feature = "target-xcore")]
518    pub fn initialize_x_core(config: &InitializationConfig) {
519        use llvm_sys::target::{
520            LLVMInitializeXCoreAsmPrinter, LLVMInitializeXCoreDisassembler, LLVMInitializeXCoreTarget,
521            LLVMInitializeXCoreTargetInfo, LLVMInitializeXCoreTargetMC,
522        };
523
524        if config.base {
525            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
526            unsafe { LLVMInitializeXCoreTarget() };
527        }
528
529        if config.info {
530            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
531            unsafe { LLVMInitializeXCoreTargetInfo() };
532        }
533
534        if config.asm_printer {
535            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
536            unsafe { LLVMInitializeXCoreAsmPrinter() };
537        }
538
539        // Asm parser status unknown
540
541        if config.disassembler {
542            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
543            unsafe { LLVMInitializeXCoreDisassembler() };
544        }
545
546        if config.machine_code {
547            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
548            unsafe { LLVMInitializeXCoreTargetMC() };
549        }
550    }
551
552    #[cfg(feature = "target-powerpc")]
553    pub fn initialize_power_pc(config: &InitializationConfig) {
554        use llvm_sys::target::{
555            LLVMInitializePowerPCAsmParser, LLVMInitializePowerPCAsmPrinter, LLVMInitializePowerPCDisassembler,
556            LLVMInitializePowerPCTarget, LLVMInitializePowerPCTargetInfo, LLVMInitializePowerPCTargetMC,
557        };
558
559        if config.base {
560            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
561            unsafe { LLVMInitializePowerPCTarget() };
562        }
563
564        if config.info {
565            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
566            unsafe { LLVMInitializePowerPCTargetInfo() };
567        }
568
569        if config.asm_printer {
570            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
571            unsafe { LLVMInitializePowerPCAsmPrinter() };
572        }
573
574        if config.asm_parser {
575            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
576            unsafe { LLVMInitializePowerPCAsmParser() };
577        }
578
579        if config.disassembler {
580            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
581            unsafe { LLVMInitializePowerPCDisassembler() };
582        }
583
584        if config.machine_code {
585            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
586            unsafe { LLVMInitializePowerPCTargetMC() };
587        }
588    }
589
590    #[cfg(feature = "target-sparc")]
591    pub fn initialize_sparc(config: &InitializationConfig) {
592        use llvm_sys::target::{
593            LLVMInitializeSparcAsmParser, LLVMInitializeSparcAsmPrinter, LLVMInitializeSparcDisassembler,
594            LLVMInitializeSparcTarget, LLVMInitializeSparcTargetInfo, LLVMInitializeSparcTargetMC,
595        };
596
597        if config.base {
598            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
599            unsafe { LLVMInitializeSparcTarget() };
600        }
601
602        if config.info {
603            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
604            unsafe { LLVMInitializeSparcTargetInfo() };
605        }
606
607        if config.asm_printer {
608            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
609            unsafe { LLVMInitializeSparcAsmPrinter() };
610        }
611
612        if config.asm_parser {
613            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
614            unsafe { LLVMInitializeSparcAsmParser() };
615        }
616
617        if config.disassembler {
618            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
619            unsafe { LLVMInitializeSparcDisassembler() };
620        }
621
622        if config.machine_code {
623            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
624            unsafe { LLVMInitializeSparcTargetMC() };
625        }
626    }
627
628    #[cfg(feature = "target-bpf")]
629    pub fn initialize_bpf(config: &InitializationConfig) {
630        use llvm_sys::target::{
631            LLVMInitializeBPFAsmPrinter, LLVMInitializeBPFTarget, LLVMInitializeBPFTargetInfo,
632            LLVMInitializeBPFTargetMC,
633        };
634
635        if config.base {
636            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
637            unsafe { LLVMInitializeBPFTarget() };
638        }
639
640        if config.info {
641            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
642            unsafe { LLVMInitializeBPFTargetInfo() };
643        }
644
645        if config.asm_printer {
646            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
647            unsafe { LLVMInitializeBPFAsmPrinter() };
648        }
649
650        // No asm parser
651
652        if config.disassembler {
653            use llvm_sys::target::LLVMInitializeBPFDisassembler;
654
655            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
656            unsafe { LLVMInitializeBPFDisassembler() };
657        }
658
659        if config.machine_code {
660            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
661            unsafe { LLVMInitializeBPFTargetMC() };
662        }
663    }
664
665    #[cfg(feature = "target-lanai")]
666    pub fn initialize_lanai(config: &InitializationConfig) {
667        use llvm_sys::target::{
668            LLVMInitializeLanaiAsmParser, LLVMInitializeLanaiAsmPrinter, LLVMInitializeLanaiDisassembler,
669            LLVMInitializeLanaiTarget, LLVMInitializeLanaiTargetInfo, LLVMInitializeLanaiTargetMC,
670        };
671
672        if config.base {
673            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
674            unsafe { LLVMInitializeLanaiTarget() };
675        }
676
677        if config.info {
678            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
679            unsafe { LLVMInitializeLanaiTargetInfo() };
680        }
681
682        if config.asm_printer {
683            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
684            unsafe { LLVMInitializeLanaiAsmPrinter() };
685        }
686
687        if config.asm_parser {
688            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
689            unsafe { LLVMInitializeLanaiAsmParser() };
690        }
691
692        if config.disassembler {
693            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
694            unsafe { LLVMInitializeLanaiDisassembler() };
695        }
696
697        if config.machine_code {
698            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
699            unsafe { LLVMInitializeLanaiTargetMC() };
700        }
701    }
702
703    #[cfg(feature = "target-riscv")]
704    pub fn initialize_riscv(config: &InitializationConfig) {
705        use llvm_sys::target::{
706            LLVMInitializeRISCVAsmParser, LLVMInitializeRISCVAsmPrinter, LLVMInitializeRISCVDisassembler,
707            LLVMInitializeRISCVTarget, LLVMInitializeRISCVTargetInfo, LLVMInitializeRISCVTargetMC,
708        };
709
710        if config.base {
711            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
712            unsafe { LLVMInitializeRISCVTarget() };
713        }
714
715        if config.info {
716            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
717            unsafe { LLVMInitializeRISCVTargetInfo() };
718        }
719
720        if config.asm_printer {
721            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
722            unsafe { LLVMInitializeRISCVAsmPrinter() };
723        }
724
725        if config.asm_parser {
726            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
727            unsafe { LLVMInitializeRISCVAsmParser() };
728        }
729
730        if config.disassembler {
731            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
732            unsafe { LLVMInitializeRISCVDisassembler() };
733        }
734
735        if config.machine_code {
736            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
737            unsafe { LLVMInitializeRISCVTargetMC() };
738        }
739    }
740
741    #[cfg(feature = "target-loongarch")]
742    #[llvm_versions(16..)]
743    pub fn initialize_loongarch(config: &InitializationConfig) {
744        use llvm_sys::target::{
745            LLVMInitializeLoongArchAsmParser, LLVMInitializeLoongArchAsmPrinter, LLVMInitializeLoongArchDisassembler,
746            LLVMInitializeLoongArchTarget, LLVMInitializeLoongArchTargetInfo, LLVMInitializeLoongArchTargetMC,
747        };
748
749        if config.base {
750            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
751            unsafe { LLVMInitializeLoongArchTarget() };
752        }
753
754        if config.info {
755            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
756            unsafe { LLVMInitializeLoongArchTargetInfo() };
757        }
758
759        if config.asm_printer {
760            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
761            unsafe { LLVMInitializeLoongArchAsmPrinter() };
762        }
763
764        if config.asm_parser {
765            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
766            unsafe { LLVMInitializeLoongArchAsmParser() };
767        }
768
769        if config.disassembler {
770            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
771            unsafe { LLVMInitializeLoongArchDisassembler() };
772        }
773
774        if config.machine_code {
775            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
776            unsafe { LLVMInitializeLoongArchTargetMC() };
777        }
778    }
779
780    #[cfg(feature = "target-webassembly")]
781    pub fn initialize_webassembly(config: &InitializationConfig) {
782        use llvm_sys::target::{
783            LLVMInitializeWebAssemblyAsmParser, LLVMInitializeWebAssemblyAsmPrinter,
784            LLVMInitializeWebAssemblyDisassembler, LLVMInitializeWebAssemblyTarget,
785            LLVMInitializeWebAssemblyTargetInfo, LLVMInitializeWebAssemblyTargetMC,
786        };
787
788        if config.base {
789            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
790            unsafe { LLVMInitializeWebAssemblyTarget() };
791        }
792
793        if config.info {
794            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
795            unsafe { LLVMInitializeWebAssemblyTargetInfo() };
796        }
797
798        if config.asm_printer {
799            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
800            unsafe { LLVMInitializeWebAssemblyAsmPrinter() };
801        }
802
803        if config.asm_parser {
804            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
805            unsafe { LLVMInitializeWebAssemblyAsmParser() };
806        }
807
808        if config.disassembler {
809            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
810            unsafe { LLVMInitializeWebAssemblyDisassembler() };
811        }
812
813        if config.machine_code {
814            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
815            unsafe { LLVMInitializeWebAssemblyTargetMC() };
816        }
817    }
818
819    pub fn initialize_native(config: &InitializationConfig) -> Result<(), String> {
820        use llvm_sys::target::{
821            LLVM_InitializeNativeAsmParser, LLVM_InitializeNativeAsmPrinter, LLVM_InitializeNativeDisassembler,
822            LLVM_InitializeNativeTarget,
823        };
824
825        if config.base {
826            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
827            let code = unsafe { LLVM_InitializeNativeTarget() };
828
829            if code == 1 {
830                return Err("Unknown error in initializing native target".into());
831            }
832        }
833
834        if config.asm_printer {
835            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
836            let code = unsafe { LLVM_InitializeNativeAsmPrinter() };
837
838            if code == 1 {
839                return Err("Unknown error in initializing native asm printer".into());
840            }
841        }
842
843        if config.asm_parser {
844            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
845            let code = unsafe { LLVM_InitializeNativeAsmParser() };
846
847            if code == 1 {
848                // REVIEW: Does parser need to go before printer?
849                return Err("Unknown error in initializing native asm parser".into());
850            }
851        }
852
853        if config.disassembler {
854            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
855            let code = unsafe { LLVM_InitializeNativeDisassembler() };
856
857            if code == 1 {
858                return Err("Unknown error in initializing native disassembler".into());
859            }
860        }
861
862        Ok(())
863    }
864
865    pub fn initialize_all(config: &InitializationConfig) {
866        use llvm_sys::target::{
867            LLVM_InitializeAllAsmParsers, LLVM_InitializeAllAsmPrinters, LLVM_InitializeAllDisassemblers,
868            LLVM_InitializeAllTargetInfos, LLVM_InitializeAllTargetMCs, LLVM_InitializeAllTargets,
869        };
870
871        if config.base {
872            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
873            unsafe { LLVM_InitializeAllTargets() };
874        }
875
876        if config.info {
877            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
878            unsafe { LLVM_InitializeAllTargetInfos() };
879        }
880
881        if config.asm_parser {
882            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
883            unsafe { LLVM_InitializeAllAsmParsers() };
884        }
885
886        if config.asm_printer {
887            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
888            unsafe { LLVM_InitializeAllAsmPrinters() };
889        }
890
891        if config.disassembler {
892            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
893            unsafe { LLVM_InitializeAllDisassemblers() };
894        }
895
896        if config.machine_code {
897            let _guard = TARGET_LOCK.write().unwrap_or_else(|e| e.into_inner());
898            unsafe { LLVM_InitializeAllTargetMCs() };
899        }
900    }
901
902    pub fn create_target_machine(
903        &self,
904        triple: &TargetTriple,
905        cpu: &str,
906        features: &str,
907        level: OptimizationLevel,
908        reloc_mode: RelocMode,
909        code_model: CodeModel,
910    ) -> Option<TargetMachine> {
911        let cpu = to_c_str(cpu);
912        let features = to_c_str(features);
913
914        let target_machine = unsafe {
915            LLVMCreateTargetMachine(
916                self.target,
917                triple.as_ptr(),
918                cpu.as_ptr(),
919                features.as_ptr(),
920                level.into(),
921                reloc_mode.into(),
922                code_model.into(),
923            )
924        };
925
926        if target_machine.is_null() {
927            return None;
928        }
929
930        unsafe { Some(TargetMachine::new(target_machine)) }
931    }
932
933    /// Create a target machine from given [TargetMachineOptions].
934    ///
935    /// # Example
936    ///
937    /// ```no_run
938    /// use inkwell::targets::{InitializationConfig, Target, TargetTriple, TargetMachineOptions};
939    /// use inkwell::OptimizationLevel;
940    ///
941    /// Target::initialize_x86(&InitializationConfig::default());
942    ///
943    /// let triple = TargetTriple::create("x86_64-pc-linux-gnu");
944    /// let target = Target::from_triple(&triple).unwrap();
945    /// let options = TargetMachineOptions::default()
946    ///     .set_cpu("x86-64")
947    ///     .set_features("+avx2")
948    ///     .set_abi("sysv")
949    ///     .set_level(OptimizationLevel::Aggressive);
950    ///
951    /// let target_machine = target.create_target_machine_from_options(&triple, options).unwrap();
952    ///
953    /// assert_eq!(target_machine.get_cpu().to_str(), Ok("x86-64"));
954    /// assert_eq!(target_machine.get_feature_string().to_str(), Ok("+avx2"));
955    /// ```
956    #[llvm_versions(18..)]
957    pub fn create_target_machine_from_options(
958        &self,
959        triple: &TargetTriple,
960        options: TargetMachineOptions,
961    ) -> Option<TargetMachine> {
962        options.into_target_machine(self.target, triple)
963    }
964
965    pub fn get_first() -> Option<Self> {
966        let target = {
967            let _guard = TARGET_LOCK.read().unwrap_or_else(|e| e.into_inner());
968            unsafe { LLVMGetFirstTarget() }
969        };
970
971        if target.is_null() {
972            return None;
973        }
974
975        unsafe { Some(Target::new(target)) }
976    }
977
978    pub fn get_next(&self) -> Option<Self> {
979        let target = unsafe { LLVMGetNextTarget(self.target) };
980
981        if target.is_null() {
982            return None;
983        }
984
985        unsafe { Some(Target::new(target)) }
986    }
987
988    pub fn get_name(&self) -> &CStr {
989        unsafe { CStr::from_ptr(LLVMGetTargetName(self.target)) }
990    }
991
992    pub fn get_description(&self) -> &CStr {
993        unsafe { CStr::from_ptr(LLVMGetTargetDescription(self.target)) }
994    }
995
996    pub fn from_name(name: &str) -> Option<Self> {
997        let c_string = to_c_str(name);
998
999        Self::from_name_raw(c_string.as_ptr())
1000    }
1001
1002    pub(crate) fn from_name_raw(c_string: *const ::libc::c_char) -> Option<Self> {
1003        let target = {
1004            let _guard = TARGET_LOCK.read().unwrap_or_else(|e| e.into_inner());
1005            unsafe { LLVMGetTargetFromName(c_string) }
1006        };
1007
1008        if target.is_null() {
1009            return None;
1010        }
1011
1012        unsafe { Some(Target::new(target)) }
1013    }
1014
1015    pub fn from_triple(triple: &TargetTriple) -> Result<Self, LLVMString> {
1016        let mut target = ptr::null_mut();
1017        let mut err_string = MaybeUninit::uninit();
1018
1019        let code = {
1020            let _guard = TARGET_LOCK.read().unwrap_or_else(|e| e.into_inner());
1021            unsafe { LLVMGetTargetFromTriple(triple.as_ptr(), &mut target, err_string.as_mut_ptr()) }
1022        };
1023
1024        if code == 1 {
1025            unsafe {
1026                return Err(LLVMString::new(err_string.assume_init()));
1027            }
1028        }
1029
1030        unsafe { Ok(Target::new(target)) }
1031    }
1032
1033    pub fn has_jit(&self) -> bool {
1034        unsafe { LLVMTargetHasJIT(self.target) == 1 }
1035    }
1036
1037    pub fn has_target_machine(&self) -> bool {
1038        unsafe { LLVMTargetHasTargetMachine(self.target) == 1 }
1039    }
1040
1041    pub fn has_asm_backend(&self) -> bool {
1042        unsafe { LLVMTargetHasAsmBackend(self.target) == 1 }
1043    }
1044}
1045
1046#[derive(Debug)]
1047pub struct TargetMachine {
1048    pub(crate) target_machine: LLVMTargetMachineRef,
1049}
1050
1051impl TargetMachine {
1052    pub unsafe fn new(target_machine: LLVMTargetMachineRef) -> Self {
1053        assert!(!target_machine.is_null());
1054
1055        TargetMachine { target_machine }
1056    }
1057
1058    /// Acquires the underlying raw pointer belonging to this `TargetMachine` type.
1059    pub fn as_mut_ptr(&self) -> LLVMTargetMachineRef {
1060        self.target_machine
1061    }
1062
1063    pub fn get_target(&self) -> Target {
1064        unsafe { Target::new(LLVMGetTargetMachineTarget(self.target_machine)) }
1065    }
1066
1067    pub fn get_triple(&self) -> TargetTriple {
1068        let str = unsafe { LLVMString::new(LLVMGetTargetMachineTriple(self.target_machine)) };
1069
1070        unsafe { TargetTriple::new(str) }
1071    }
1072
1073    /// Gets the default triple for the current system.
1074    ///
1075    /// # Example
1076    ///
1077    /// ```no_run
1078    /// use inkwell::targets::TargetMachine;
1079    ///
1080    /// let default_triple = TargetMachine::get_default_triple();
1081    ///
1082    /// assert_eq!(default_triple.as_str().to_str(), Ok("x86_64-pc-linux-gnu"));
1083    /// ```
1084    pub fn get_default_triple() -> TargetTriple {
1085        let llvm_string = unsafe { LLVMString::new(LLVMGetDefaultTargetTriple()) };
1086
1087        unsafe { TargetTriple::new(llvm_string) }
1088    }
1089
1090    pub fn normalize_triple(triple: &TargetTriple) -> TargetTriple {
1091        use llvm_sys::target_machine::LLVMNormalizeTargetTriple;
1092
1093        let normalized = unsafe { LLVMString::new(LLVMNormalizeTargetTriple(triple.as_ptr())) };
1094
1095        unsafe { TargetTriple::new(normalized) }
1096    }
1097
1098    /// Gets a string containing the host CPU's name (triple).
1099    ///
1100    /// # Example Output
1101    ///
1102    /// `x86_64-pc-linux-gnu`
1103    pub fn get_host_cpu_name() -> LLVMString {
1104        use llvm_sys::target_machine::LLVMGetHostCPUName;
1105
1106        unsafe { LLVMString::new(LLVMGetHostCPUName()) }
1107    }
1108
1109    /// Gets a comma separated list of supported features by the host CPU.
1110    ///
1111    /// # Example Output
1112    ///
1113    /// `+sse2,+cx16,+sahf,-tbm`
1114    pub fn get_host_cpu_features() -> LLVMString {
1115        use llvm_sys::target_machine::LLVMGetHostCPUFeatures;
1116
1117        unsafe { LLVMString::new(LLVMGetHostCPUFeatures()) }
1118    }
1119
1120    pub fn get_cpu(&self) -> LLVMString {
1121        unsafe { LLVMString::new(LLVMGetTargetMachineCPU(self.target_machine)) }
1122    }
1123
1124    pub fn get_feature_string(&self) -> &CStr {
1125        unsafe { CStr::from_ptr(LLVMGetTargetMachineFeatureString(self.target_machine)) }
1126    }
1127
1128    /// Create TargetData from this target machine
1129    pub fn get_target_data(&self) -> TargetData {
1130        unsafe { TargetData::new(LLVMCreateTargetDataLayout(self.target_machine)) }
1131    }
1132
1133    pub fn set_asm_verbosity(&self, verbosity: bool) {
1134        unsafe { LLVMSetTargetMachineAsmVerbosity(self.target_machine, verbosity as i32) }
1135    }
1136
1137    // TODO: Move to PassManager?
1138    pub fn add_analysis_passes<T>(&self, pass_manager: &PassManager<T>) {
1139        unsafe { LLVMAddAnalysisPasses(self.target_machine, pass_manager.pass_manager) }
1140    }
1141
1142    /// Writes a `TargetMachine` to a `MemoryBuffer`.
1143    ///
1144    /// # Example
1145    ///
1146    /// ```no_run
1147    /// use inkwell::OptimizationLevel;
1148    /// use inkwell::context::Context;
1149    /// use inkwell::targets::{CodeModel, RelocMode, FileType, Target, TargetMachine, TargetTriple, InitializationConfig};
1150    ///
1151    /// Target::initialize_x86(&InitializationConfig::default());
1152    ///
1153    /// let opt = OptimizationLevel::Default;
1154    /// let reloc = RelocMode::Default;
1155    /// let model = CodeModel::Default;
1156    /// let target = Target::from_name("x86-64").unwrap();
1157    /// let target_machine = target.create_target_machine(
1158    ///     &TargetTriple::create("x86_64-pc-linux-gnu"),
1159    ///     "x86-64",
1160    ///     "+avx2",
1161    ///     opt,
1162    ///     reloc,
1163    ///     model
1164    /// )
1165    /// .unwrap();
1166    ///
1167    /// let context = Context::create();
1168    /// let module = context.create_module("my_module");
1169    /// let void_type = context.void_type();
1170    /// let fn_type = void_type.fn_type(&[], false);
1171    ///
1172    /// module.add_function("my_fn", fn_type, None);
1173    ///
1174    /// let buffer = target_machine.write_to_memory_buffer(&module, FileType::Assembly).unwrap();
1175    /// ```
1176    pub fn write_to_memory_buffer(&self, module: &Module, file_type: FileType) -> Result<MemoryBuffer, LLVMString> {
1177        let mut memory_buffer = ptr::null_mut();
1178        let mut err_string = MaybeUninit::uninit();
1179        let return_code = unsafe {
1180            let module_ptr = module.module.get();
1181            let file_type_ptr = file_type.as_llvm_file_type();
1182
1183            LLVMTargetMachineEmitToMemoryBuffer(
1184                self.target_machine,
1185                module_ptr,
1186                file_type_ptr,
1187                err_string.as_mut_ptr(),
1188                &mut memory_buffer,
1189            )
1190        };
1191
1192        if return_code == 1 {
1193            unsafe {
1194                return Err(LLVMString::new(err_string.assume_init()));
1195            }
1196        }
1197
1198        unsafe { Ok(MemoryBuffer::new(memory_buffer)) }
1199    }
1200
1201    /// Saves a `TargetMachine` to a file.
1202    ///
1203    /// # Example
1204    ///
1205    /// ```no_run
1206    /// use inkwell::OptimizationLevel;
1207    /// use inkwell::context::Context;
1208    /// use inkwell::targets::{CodeModel, RelocMode, FileType, Target, TargetMachine, TargetTriple, InitializationConfig};
1209    ///
1210    /// use std::path::Path;
1211    ///
1212    /// Target::initialize_x86(&InitializationConfig::default());
1213    ///
1214    /// let opt = OptimizationLevel::Default;
1215    /// let reloc = RelocMode::Default;
1216    /// let model = CodeModel::Default;
1217    /// let path = Path::new("/tmp/some/path/main.asm");
1218    /// let target = Target::from_name("x86-64").unwrap();
1219    /// let target_machine = target.create_target_machine(
1220    ///     &TargetTriple::create("x86_64-pc-linux-gnu"),
1221    ///     "x86-64",
1222    ///     "+avx2",
1223    ///     opt,
1224    ///     reloc,
1225    ///     model
1226    /// )
1227    /// .unwrap();
1228    ///
1229    /// let context = Context::create();
1230    /// let module = context.create_module("my_module");
1231    /// let void_type = context.void_type();
1232    /// let fn_type = void_type.fn_type(&[], false);
1233    ///
1234    /// module.add_function("my_fn", fn_type, None);
1235    ///
1236    /// assert!(target_machine.write_to_file(&module, FileType::Object, &path).is_ok());
1237    /// ```
1238    pub fn write_to_file(&self, module: &Module, file_type: FileType, path: &Path) -> Result<(), LLVMString> {
1239        let path = path.to_str().expect("Did not find a valid Unicode path string");
1240        let path_c_string = to_c_str(path);
1241        let mut err_string = MaybeUninit::uninit();
1242        let return_code = unsafe {
1243            // REVIEW: Why does LLVM need a mutable ptr to path...?
1244            let module_ptr = module.module.get();
1245            let path_ptr = path_c_string.as_ptr() as *mut _;
1246            let file_type_ptr = file_type.as_llvm_file_type();
1247
1248            LLVMTargetMachineEmitToFile(
1249                self.target_machine,
1250                module_ptr,
1251                path_ptr,
1252                file_type_ptr,
1253                err_string.as_mut_ptr(),
1254            )
1255        };
1256
1257        if return_code == 1 {
1258            unsafe {
1259                return Err(LLVMString::new(err_string.assume_init()));
1260            }
1261        }
1262
1263        Ok(())
1264    }
1265}
1266
1267impl Drop for TargetMachine {
1268    fn drop(&mut self) {
1269        unsafe { LLVMDisposeTargetMachine(self.target_machine) }
1270    }
1271}
1272
1273#[derive(Debug, PartialEq, Eq, Copy, Clone)]
1274pub enum ByteOrdering {
1275    BigEndian,
1276    LittleEndian,
1277}
1278
1279#[derive(PartialEq, Eq, Debug)]
1280pub struct TargetData {
1281    pub(crate) target_data: LLVMTargetDataRef,
1282}
1283
1284impl TargetData {
1285    pub unsafe fn new(target_data: LLVMTargetDataRef) -> TargetData {
1286        assert!(!target_data.is_null());
1287
1288        TargetData { target_data }
1289    }
1290
1291    /// Acquires the underlying raw pointer belonging to this `TargetData` type.
1292    pub fn as_mut_ptr(&self) -> LLVMTargetDataRef {
1293        self.target_data
1294    }
1295
1296    /// Gets the `IntType` representing a bit width of a pointer. It will be assigned the referenced context.
1297    ///
1298    /// # Example
1299    ///
1300    /// ```no_run
1301    /// use inkwell::OptimizationLevel;
1302    /// use inkwell::context::Context;
1303    /// use inkwell::targets::{InitializationConfig, Target};
1304    ///
1305    /// Target::initialize_native(&InitializationConfig::default()).expect("Failed to initialize native target");
1306    ///
1307    /// let context = Context::create();
1308    /// let module = context.create_module("sum");
1309    /// let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None).unwrap();
1310    /// let target_data = execution_engine.get_target_data();
1311    /// let int_type = target_data.ptr_sized_int_type_in_context(&context, None);
1312    /// ```
1313    #[deprecated(note = "This method will be removed in the future. Please use Context::ptr_sized_int_type instead.")]
1314    pub fn ptr_sized_int_type_in_context<'ctx>(
1315        &self,
1316        context: impl AsContextRef<'ctx>,
1317        address_space: Option<AddressSpace>,
1318    ) -> IntType<'ctx> {
1319        let int_type_ptr = match address_space {
1320            Some(address_space) => unsafe {
1321                LLVMIntPtrTypeForASInContext(context.as_ctx_ref(), self.target_data, address_space.0)
1322            },
1323            None => unsafe { LLVMIntPtrTypeInContext(context.as_ctx_ref(), self.target_data) },
1324        };
1325
1326        unsafe { IntType::new(int_type_ptr) }
1327    }
1328
1329    pub fn get_data_layout(&self) -> DataLayout {
1330        unsafe { DataLayout::new_owned(LLVMCopyStringRepOfTargetData(self.target_data)) }
1331    }
1332
1333    // REVIEW: Does this only work if Sized?
1334    pub fn get_bit_size(&self, type_: &dyn AnyType) -> u64 {
1335        unsafe { LLVMSizeOfTypeInBits(self.target_data, type_.as_type_ref()) }
1336    }
1337
1338    // TODOC: This can fail on LLVM's side(exit?), but it doesn't seem like we have any way to check this in rust
1339    pub fn create(str_repr: &str) -> TargetData {
1340        let c_string = to_c_str(str_repr);
1341
1342        unsafe { TargetData::new(LLVMCreateTargetData(c_string.as_ptr())) }
1343    }
1344
1345    pub fn get_byte_ordering(&self) -> ByteOrdering {
1346        let byte_ordering = unsafe { LLVMByteOrder(self.target_data) };
1347
1348        match byte_ordering {
1349            LLVMByteOrdering::LLVMBigEndian => ByteOrdering::BigEndian,
1350            LLVMByteOrdering::LLVMLittleEndian => ByteOrdering::LittleEndian,
1351        }
1352    }
1353
1354    pub fn get_pointer_byte_size(&self, address_space: Option<AddressSpace>) -> u32 {
1355        match address_space {
1356            Some(address_space) => unsafe { LLVMPointerSizeForAS(self.target_data, address_space.0) },
1357            None => unsafe { LLVMPointerSize(self.target_data) },
1358        }
1359    }
1360
1361    pub fn get_store_size(&self, type_: &dyn AnyType) -> u64 {
1362        unsafe { LLVMStoreSizeOfType(self.target_data, type_.as_type_ref()) }
1363    }
1364
1365    pub fn get_abi_size(&self, type_: &dyn AnyType) -> u64 {
1366        unsafe { LLVMABISizeOfType(self.target_data, type_.as_type_ref()) }
1367    }
1368
1369    pub fn get_abi_alignment(&self, type_: &dyn AnyType) -> u32 {
1370        unsafe { LLVMABIAlignmentOfType(self.target_data, type_.as_type_ref()) }
1371    }
1372
1373    pub fn get_call_frame_alignment(&self, type_: &dyn AnyType) -> u32 {
1374        unsafe { LLVMCallFrameAlignmentOfType(self.target_data, type_.as_type_ref()) }
1375    }
1376
1377    pub fn get_preferred_alignment(&self, type_: &dyn AnyType) -> u32 {
1378        unsafe { LLVMPreferredAlignmentOfType(self.target_data, type_.as_type_ref()) }
1379    }
1380
1381    pub fn get_preferred_alignment_of_global(&self, value: &GlobalValue) -> u32 {
1382        unsafe { LLVMPreferredAlignmentOfGlobal(self.target_data, value.as_value_ref()) }
1383    }
1384
1385    pub fn element_at_offset(&self, struct_type: &StructType, offset: u64) -> u32 {
1386        unsafe { LLVMElementAtOffset(self.target_data, struct_type.as_type_ref(), offset) }
1387    }
1388
1389    pub fn offset_of_element(&self, struct_type: &StructType, element: u32) -> Option<u64> {
1390        if element > struct_type.count_fields() - 1 {
1391            return None;
1392        }
1393
1394        unsafe {
1395            Some(LLVMOffsetOfElement(
1396                self.target_data,
1397                struct_type.as_type_ref(),
1398                element,
1399            ))
1400        }
1401    }
1402}
1403
1404impl Drop for TargetData {
1405    fn drop(&mut self) {
1406        unsafe { LLVMDisposeTargetData(self.target_data) }
1407    }
1408}
1409
1410/// LLVM target machine options provide another way to create target machines,
1411/// used with [Target::create_target_machine_from_options].
1412///
1413/// The option structure exposes an additional setting (i.e., the target ABI)
1414/// and provides default values for unspecified settings.
1415#[llvm_versions(18..)]
1416#[derive(Default, Debug)]
1417pub struct TargetMachineOptions(Option<LLVMTargetMachineOptionsRef>);
1418
1419#[llvm_versions(18..)]
1420impl TargetMachineOptions {
1421    pub fn new() -> Self {
1422        Default::default()
1423    }
1424
1425    pub fn set_cpu(mut self, cpu: &str) -> Self {
1426        let cpu = to_c_str(cpu);
1427        unsafe { LLVMTargetMachineOptionsSetCPU(self.inner(), cpu.as_ptr()) };
1428
1429        self
1430    }
1431
1432    pub fn set_features(mut self, features: &str) -> Self {
1433        let features = to_c_str(features);
1434        unsafe { LLVMTargetMachineOptionsSetFeatures(self.inner(), features.as_ptr()) };
1435
1436        self
1437    }
1438
1439    pub fn set_abi(mut self, abi: &str) -> Self {
1440        let abi = to_c_str(abi);
1441        unsafe { LLVMTargetMachineOptionsSetABI(self.inner(), abi.as_ptr()) };
1442
1443        self
1444    }
1445
1446    pub fn set_level(mut self, level: OptimizationLevel) -> Self {
1447        unsafe { LLVMTargetMachineOptionsSetCodeGenOptLevel(self.inner(), level.into()) };
1448
1449        self
1450    }
1451
1452    pub fn set_reloc_mode(mut self, reloc_mode: RelocMode) -> Self {
1453        unsafe { LLVMTargetMachineOptionsSetRelocMode(self.inner(), reloc_mode.into()) }
1454
1455        self
1456    }
1457
1458    pub fn set_code_model(mut self, code_model: CodeModel) -> Self {
1459        unsafe { LLVMTargetMachineOptionsSetCodeModel(self.inner(), code_model.into()) };
1460
1461        self
1462    }
1463
1464    fn into_target_machine(mut self, target: LLVMTargetRef, triple: &TargetTriple) -> Option<TargetMachine> {
1465        let target_machine = unsafe { LLVMCreateTargetMachineWithOptions(target, triple.as_ptr(), self.inner()) };
1466
1467        if target_machine.is_null() {
1468            return None;
1469        }
1470
1471        unsafe { Some(TargetMachine::new(target_machine)) }
1472    }
1473
1474    /// SAFETY:
1475    /// - The internal `LLVMCreateTargetMachineOptionsRef` structure leaks memory
1476    /// if not disposed via `fn LLVMCreateTargetMachineWithOptions()`.
1477    /// - The only way to access it is via this private method.
1478    /// - Disposal is taken care of automatically in `Drop::drop`.
1479    unsafe fn inner(&mut self) -> LLVMTargetMachineOptionsRef {
1480        *self.0.get_or_insert_with(|| LLVMCreateTargetMachineOptions())
1481    }
1482}
1483
1484#[llvm_versions(18..)]
1485impl Drop for TargetMachineOptions {
1486    fn drop(&mut self) {
1487        if let Some(inner) = self.0 {
1488            unsafe { LLVMDisposeTargetMachineOptions(inner) };
1489        }
1490    }
1491}