llvm_wrap/
target.rs

1//! Provides wrappers for target-related operations
2use super::*;
3use super::c_api::*;
4
5use std::path::Path;
6use std::ptr::null_mut;
7use llvm_sys::target::*;
8use llvm_sys::target_machine::*;
9
10static mut UNINITIALIZED: bool = true;
11
12unsafe fn initialize() {
13    if UNINITIALIZED {
14        UNINITIALIZED = false;
15        LLVM_InitializeAllTargets();
16        LLVM_InitializeAllTargetInfos();
17        LLVM_InitializeAllTargetMCs();
18    }
19}
20
21/// The default target triple
22pub fn default_triple() -> String {
23    from_c(unsafe {
24        LLVMGetDefaultTargetTriple()
25    }).unwrap_or(String::new())
26}
27
28/// A renamed `LLVMCodeGenOptLevel`
29#[derive(Copy, Clone, Debug, Eq, PartialEq)]
30pub enum OptLevel {
31    /// No optimization (`-O0`)
32    None = 0,
33    /// Less optimization (`-O1`)
34    Less = 1,
35    /// Default optimization (`-O2`)
36    Default = 2,
37    /// Aggressive optimization (`-O3`)
38    Aggressive = 3,
39}
40
41impl OptLevel {
42    /// The `LLVMCodeGenOptLevel` this value represents
43    pub unsafe fn inner(&self) -> LLVMCodeGenOptLevel {
44        use llvm_sys::target_machine::LLVMCodeGenOptLevel::*;
45        use self::OptLevel::*;
46        match self {
47            &None => LLVMCodeGenLevelNone,
48            &Less => LLVMCodeGenLevelLess,
49            &Default => LLVMCodeGenLevelDefault,
50            &Aggressive => LLVMCodeGenLevelAggressive,
51        }
52    }
53}
54
55/// A renamed `LLVMCodeGenFileType`
56#[derive(Copy, Clone, Debug, Eq, PartialEq)]
57pub enum FileType {
58    /// The assembly (`.s`) file type
59    Assembly,
60    /// The object (`.o`) file type
61    Object,
62}
63
64impl FileType {
65    /// The `LLVMCodeGenFileType` this value represents
66    pub fn inner(&self) -> LLVMCodeGenFileType {
67        use llvm_sys::target_machine::LLVMCodeGenFileType::*;
68        use self::FileType::*;
69        match self {
70            &Assembly => LLVMAssemblyFile,
71            &Object => LLVMObjectFile,
72        }
73    }
74}
75
76/// A renamed `LLVMByteOrdering`
77#[derive(Copy, Clone, Debug, Eq, PartialEq)]
78pub enum ByteOrdering {
79    /// The most significant byte is stored first
80    BigEndian,
81    /// The least significant byte is stored first
82    LittleEndian,
83}
84
85impl ByteOrdering {
86    /// The `LLVMByteOrdering` this value represents
87    pub fn inner(&self) -> LLVMByteOrdering {
88        use llvm_sys::target::LLVMByteOrdering::*;
89        use self::ByteOrdering::*;
90        match self {
91            &BigEndian => LLVMBigEndian,
92            &LittleEndian => LLVMLittleEndian,
93        }
94    }
95}
96
97/// A wrapper around a `LLVMTargetRef`
98#[derive(Copy, Clone)]
99pub struct Target {
100    target: LLVMTargetRef,
101}
102
103impl Target {
104    /// Attempts to create a `Target` using the given triple
105    pub fn from_triple(triple: String) -> Result<Target, String> {
106        unsafe {
107            initialize();
108            let mut target: LLVMTargetRef = null_mut();
109            let mut error = null_mut();
110            if LLVMGetTargetFromTriple(
111                    into_c(triple).as_ptr(),
112                    &mut target as *mut LLVMTargetRef,
113                    &mut error as *mut *mut i8,
114                ) == 1 || target.is_null() {
115                Err(from_c(error).unwrap_or(String::new()))
116            } else {
117                Ok(Target {
118                    target,
119                })
120            }
121        }
122    }
123
124    /// Creates a target machine with the default options
125    pub fn create_machine(&self, triple: String) -> TargetMachine {
126        self.create_machine_with_options(triple, "generic".to_owned(), String::new(), OptLevel::Default)
127    }
128
129    /// Creates a target machine with the given options
130    pub fn create_machine_with_options(&self, triple: String, cpu: String, features: String,
131                                       level: OptLevel) -> TargetMachine {
132        TargetMachine {
133            machine: unsafe {
134                LLVMCreateTargetMachine(
135                    self.target,
136                    into_c(triple).as_ptr(),
137                    into_c(cpu).as_ptr(),
138                    into_c(features).as_ptr(),
139                    level.inner(),
140                    LLVMRelocMode::LLVMRelocDefault,
141                    LLVMCodeModel::LLVMCodeModelDefault,
142                )
143            }
144        }
145    }
146
147    /// Gets the name of this target
148    pub fn name(&self) -> String {
149        unsafe {
150            from_c(LLVMGetTargetName(self.target)).unwrap_or(String::new())
151        }
152    }
153
154    /// Gets the description of this target
155    pub fn description(&self) -> String {
156        unsafe {
157            from_c(LLVMGetTargetDescription(self.target)).unwrap_or(String::new())
158        }
159    }
160}
161
162impl Debug for Target {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        write!(f, "Target({:?}, {:?})", self.name(), self.description())
165    }
166}
167
168impl Display for Target {
169    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
170        write!(f, "{}", self.name())
171    }
172}
173
174/// A wrapper around a `LLVMTargetMachineRef`
175#[derive(Clone)]
176pub struct TargetMachine {
177    machine: LLVMTargetMachineRef,
178}
179
180impl TargetMachine {
181    /// Creates a target machine with the native target triple and options
182    pub fn native() -> Result<TargetMachine, String> {
183        TargetMachine::new(default_triple())
184    }
185
186    /// Creates a target machine with the default options
187    pub fn new(triple: String) -> Result<TargetMachine, String> {
188        Ok(Target::from_triple(triple.clone())?.create_machine(triple))
189    }
190
191    /// Creates a target machine with the given options
192    pub fn new_with_options(triple: String, cpu: String, features: String,
193                            level: OptLevel) -> Result<TargetMachine, String> {
194        Ok(Target::from_triple(triple.clone())?.create_machine_with_options(triple, cpu, features, level))
195    }
196
197    /// Emits code for a module to a given file with the given file type
198    pub fn emit_module_to_file<P>(&self, module: &Module, file: P, file_type: FileType) -> Result<(), String>
199        where P: AsRef<Path> {
200        unsafe {
201            LLVM_InitializeAllAsmPrinters();
202            let file_str = into_c(file.as_ref().to_str().expect("invalid path")).into_raw();
203            let mut error = null_mut();
204            let flag = LLVMTargetMachineEmitToFile(
205                self.machine,
206                module.module.unwrap(),
207                file_str,
208                file_type.inner(),
209                &mut error as *mut *mut i8,
210            ) == 1;
211            CString::from_raw(file_str);
212            if flag {
213                Err(from_c(error).unwrap_or(String::new()))
214            } else {
215                Ok(())
216            }
217        }
218    }
219
220    /// Creates a data layout based on this target machine
221    pub fn data_layout(&self) -> TargetData {
222        TargetData {
223            data: unsafe {
224                LLVMCreateTargetDataLayout(self.machine)
225            }
226        }
227    }
228
229    /// Gets the target of this target machine
230    pub fn target(&self) -> Target {
231        Target {
232            target: unsafe{
233                LLVMGetTargetMachineTarget(self.machine)
234            }
235        }
236    }
237
238    /// Gets the target triple of this target machine
239    pub fn triple(&self) -> String {
240        unsafe {
241            from_c(LLVMGetTargetMachineTriple(self.machine)).unwrap_or(String::new())
242        }
243    }
244
245    /// Gets the cpu of this target machine
246    pub fn cpu(&self) -> String {
247        unsafe {
248            from_c(LLVMGetTargetMachineCPU(self.machine)).unwrap_or(String::new())
249        }
250    }
251
252    /// Gets the features of this target machine
253    pub fn features(&self) -> String {
254        unsafe {
255            from_c(LLVMGetTargetMachineFeatureString(self.machine)).unwrap_or(String::new())
256        }
257    }
258}
259
260impl Debug for TargetMachine {
261    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262        write!(f, "TargetMachine({:?}, {:?}, {:?}, {:?})", self.target(), self.triple(), self.cpu(), self.features())
263    }
264}
265
266impl Drop for TargetMachine {
267    fn drop(&mut self) {
268        unsafe {
269            LLVMDisposeTargetMachine(self.machine);
270        }
271    }
272}
273
274/// A wrapper around a `LLVMTargetDataRef`
275#[derive(Clone)]
276pub struct TargetData {
277    pub(crate) data: LLVMTargetDataRef,
278}
279
280impl TargetData {
281    /// Returns the byte order of this data layout
282    pub fn byte_order(&self) -> ByteOrdering {
283        unsafe {
284            use llvm_sys::target::LLVMByteOrdering::*;
285            use self::ByteOrdering::*;
286            match LLVMByteOrder(self.data) {
287                LLVMBigEndian => BigEndian,
288                LLVMLittleEndian => LittleEndian,
289            }
290        }
291    }
292
293    /// Returns the size of a pointer
294    pub fn size_of_ptr(&self) -> u64 {
295        unsafe {
296            LLVMPointerSize(self.data) as u64
297        }
298    }
299
300    /// Returns the size of a pointer in bits
301    pub fn bit_size_of_ptr(&self) -> u64 {
302        unsafe {
303            LLVMPointerSize(self.data) as u64 * 8
304        }
305    }
306
307    /// Returns the byte offset of an element in a struct
308    pub fn offset_of_element(&self, ty: Type, index: u32) -> u64 {
309        unsafe {
310            LLVMOffsetOfElement(self.data, ty.ty, index)
311        }
312    }
313
314    /// Returns the element at a byte offset in a struct
315    pub fn element_at_offset(&self, ty: Type, offset: u64) -> u32 {
316        unsafe {
317            LLVMElementAtOffset(self.data, ty.ty, offset)
318        }
319    }
320
321    /// Returns the size of a type
322    pub fn size_of(&self, ty: Type) -> u64 {
323        unsafe {
324            LLVMABISizeOfType(self.data, ty.ty)
325        }
326    }
327
328    /// Returns the size of a type in bits
329    pub fn bit_size_of(&self, ty: Type) -> u64 {
330        unsafe {
331            LLVMSizeOfTypeInBits(self.data, ty.ty)
332        }
333    }
334
335    /// Returns the size of a type when stored
336    pub fn store_size_of(&self, ty: Type) -> u64 {
337        unsafe {
338            LLVMStoreSizeOfType(self.data, ty.ty)
339        }
340    }
341
342    /// Returns the ABI alignment of a type
343    pub fn abi_alignment_of(&self, ty: Type) -> u32 {
344        unsafe {
345            LLVMABIAlignmentOfType(self.data, ty.ty)
346        }
347    }
348
349    /// Returns the ABI alignment of a type
350    pub fn call_frame_alignment_of(&self, ty: Type) -> u32 {
351        unsafe {
352            LLVMCallFrameAlignmentOfType(self.data, ty.ty)
353        }
354    }
355
356    /// Returns the preferred alignment of a type
357    pub fn preferred_alignment_of(&self, ty: Type) -> u32 {
358        unsafe {
359            LLVMPreferredAlignmentOfType(self.data, ty.ty)
360        }
361    }
362}
363
364impl Debug for TargetData {
365    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
366        write!(f, "TargetData({:?})", self.to_string())
367    }
368}
369
370impl Display for TargetData {
371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372        write!(f, "{}", unsafe {
373            from_c(LLVMCopyStringRepOfTargetData(self.data)).unwrap_or(String::new())
374        })
375    }
376}
377
378impl Drop for TargetData {
379    fn drop(&mut self) {
380        unsafe {
381            LLVMDisposeTargetData(self.data);
382        }
383    }
384}