1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//! Inkwell documentation is a work in progress.
//!
//! If you have any LLVM knowledge that could be used to improve these docs, we would greatly appreciate you opening an issue and/or a pull request on our [GitHub page](https://github.com/TheDan64/inkwell).
//!
//! Due to a rustdoc issue, this documentation represents only the latest supported LLVM version. We hope that this issue will be resolved in the future so that multiple versions can be documented side by side.
//!
//! # Library Wide Notes
//!
//! * Most functions which take a string slice as input may possibly panic in the unlikely event that a c style string cannot be created based on it. (IE if your slice already has a null byte in it)

#![deny(missing_debug_implementations)]
extern crate either;
#[macro_use]
extern crate enum_methods;
extern crate libc;
extern crate llvm_sys;
#[macro_use]
extern crate inkwell_internal_macros;
#[macro_use]
extern crate lazy_static;

#[macro_use]
pub mod support;
#[deny(missing_docs)]
pub mod attributes;
#[deny(missing_docs)]
#[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7", feature = "llvm3-8", feature = "llvm3-9",
              feature = "llvm4-0", feature = "llvm5-0", feature = "llvm6-0")))]
pub mod comdat;
#[deny(missing_docs)]
pub mod basic_block;
pub mod builder;
#[deny(missing_docs)]
pub mod context;
pub mod data_layout;
pub mod execution_engine;
pub mod memory_buffer;
#[deny(missing_docs)]
pub mod module;
pub mod object_file;
pub mod passes;
pub mod targets;
pub mod types;
pub mod values;

use llvm_sys::{LLVMIntPredicate, LLVMRealPredicate, LLVMVisibility, LLVMThreadLocalMode, LLVMDLLStorageClass, LLVMAtomicOrdering, LLVMAtomicRMWBinOp};

use std::convert::TryFrom;

// Thanks to kennytm for coming up with assert_unique_features!
// which ensures that the LLVM feature flags are mutually exclusive
macro_rules! assert_unique_features {
    () => {};
    ($first:tt $(,$rest:tt)*) => {
        $(
            #[cfg(all(feature = $first, feature = $rest))]
            compile_error!(concat!("features \"", $first, "\" and \"", $rest, "\" cannot be used together"));
        )*
        assert_unique_features!($($rest),*);
    }
}

// This macro ensures that at least one of the LLVM feature
// flags are provided and prints them out if none are provided
macro_rules! assert_used_features {
    ($($all:tt),*) => {
        #[cfg(not(any($(feature = $all),*)))]
        compile_error!(concat!("One of the LLVM feature flags must be provided: ", $($all, " "),*));
    }
}

macro_rules! assert_unique_used_features {
    ($($all:tt),*) => {
        assert_unique_features!($($all),*);
        assert_used_features!($($all),*);
    }
}

assert_unique_used_features!{"llvm3-6", "llvm3-7", "llvm3-8", "llvm3-9", "llvm4-0", "llvm5-0", "llvm6-0", "llvm7-0", "llvm8-0"}

/// Defines the address space in which a global will be inserted.
///
/// # Remarks
/// See also: https://llvm.org/doxygen/NVPTXBaseInfo_8h_source.html
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum AddressSpace {
    Generic = 0,
    Global  = 1,
    Shared  = 3,
    Const   = 4,
    Local   = 5,
}

impl TryFrom<u32> for AddressSpace {
    type Error = ();

    fn try_from(val: u32) -> Result<Self, Self::Error> {
        match val {
            0 => Ok(AddressSpace::Generic),
            1 => Ok(AddressSpace::Global),
            2 => Ok(AddressSpace::Shared),
            3 => Ok(AddressSpace::Const),
            4 => Ok(AddressSpace::Local),
            _ => Err(()),
        }
    }
}

// REVIEW: Maybe this belongs in some sort of prelude?
enum_rename!{
    /// This enum defines how to compare a `left` and `right` `IntValue`.
    IntPredicate <=> LLVMIntPredicate {
        /// Equal
        EQ <=> LLVMIntEQ,
        /// Not Equal
        NE <=> LLVMIntNE,
        /// Unsigned Greater Than
        UGT <=> LLVMIntUGT,
        /// Unsigned Greater Than or Equal
        UGE <=> LLVMIntUGE,
        /// Unsigned Less Than
        ULT <=> LLVMIntULT,
        /// Unsigned Less Than or Equal
        ULE <=> LLVMIntULE,
        /// Signed Greater Than
        SGT <=> LLVMIntSGT,
        /// Signed Greater Than or Equal
        SGE <=> LLVMIntSGE,
        /// Signed Less Than
        SLT <=> LLVMIntSLT,
        /// Signed Less Than or Equal
        SLE <=> LLVMIntSLE,
    }
}

// REVIEW: Maybe this belongs in some sort of prelude?
enum_rename!{
    /// Defines how to compare a `left` and `right` `FloatValue`.
    FloatPredicate <=> LLVMRealPredicate {
        /// Returns true if `left` == `right` and neither are NaN
        OEQ <=> LLVMRealOEQ,
        /// Returns true if `left` >= `right` and neither are NaN
        OGE <=> LLVMRealOGE,
        /// Returns true if `left` > `right` and neither are NaN
        OGT <=> LLVMRealOGT,
        /// Returns true if `left` <= `right` and neither are NaN
        OLE <=> LLVMRealOLE,
        /// Returns true if `left` < `right` and neither are NaN
        OLT <=> LLVMRealOLT,
        /// Returns true if `left` != `right` and neither are NaN
        ONE <=> LLVMRealONE,
        /// Returns true if neither value is NaN
        ORD <=> LLVMRealORD,
        /// Always returns false
        PredicateFalse <=> LLVMRealPredicateFalse,
        /// Always returns true
        PredicateTrue <=> LLVMRealPredicateTrue,
        /// Returns true if `left` == `right` or either is NaN
        UEQ <=> LLVMRealUEQ,
        /// Returns true if `left` >= `right` or either is NaN
        UGE <=> LLVMRealUGE,
        /// Returns true if `left` > `right` or either is NaN
        UGT <=> LLVMRealUGT,
        /// Returns true if `left` <= `right` or either is NaN
        ULE <=> LLVMRealULE,
        /// Returns true if `left` < `right` or either is NaN
        ULT <=> LLVMRealULT,
        /// Returns true if `left` != `right` or either is NaN
        UNE <=> LLVMRealUNE,
        /// Returns true if either value is NaN
        UNO <=> LLVMRealUNO,
    }
}

// REVIEW: Maybe this belongs in some sort of prelude?
#[llvm_enum(LLVMAtomicOrdering)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AtomicOrdering {
    #[llvm_variant(LLVMAtomicOrderingNotAtomic)]
    NotAtomic,
    #[llvm_variant(LLVMAtomicOrderingUnordered)]
    Unordered,
    #[llvm_variant(LLVMAtomicOrderingMonotonic)]
    Monotonic,
    #[llvm_variant(LLVMAtomicOrderingAcquire)]
    Acquire,
    #[llvm_variant(LLVMAtomicOrderingRelease)]
    Release,
    #[llvm_variant(LLVMAtomicOrderingAcquireRelease)]
    AcquireRelease,
    #[llvm_variant(LLVMAtomicOrderingSequentiallyConsistent)]
    SequentiallyConsistent,
}

#[llvm_enum(LLVMAtomicRMWBinOp)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum AtomicRMWBinOp {
    /// Stores to memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpXchg)]
    Xchg,

    /// Adds to the value in memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpAdd)]
    Add,

    /// Subtract a value off the value in memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpSub)]
    Sub,

    /// Bitwise and into memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpAnd)]
    And,

    /// Bitwise nands into memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpNand)]
    Nand,

    /// Bitwise ors into memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpOr)]
    Or,

    /// Bitwise xors into memory and returns the prior value.
    #[llvm_variant(LLVMAtomicRMWBinOpXor)]
    Xor,

    /// Sets memory to the signed-greater of the value provided and the value in memory. Returns the value that was in memory.
    #[llvm_variant(LLVMAtomicRMWBinOpMax)]
    Max,

    /// Sets memory to the signed-lesser of the value provided and the value in memory. Returns the value that was in memory.
    #[llvm_variant(LLVMAtomicRMWBinOpMin)]
    Min,

    /// Sets memory to the unsigned-greater of the value provided and the value in memory. Returns the value that was in memory.
    #[llvm_variant(LLVMAtomicRMWBinOpUMax)]
    UMax,

    /// Sets memory to the unsigned-lesser of the value provided and the value in memory. Returns the value that was in memory.
    #[llvm_variant(LLVMAtomicRMWBinOpUMin)]
    UMin,
}

/// Defines the optimization level used to compile a `Module`.
///
/// # Remarks
/// See also: https://llvm.org/doxygen/CodeGen_8h_source.html
#[repr(u32)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum OptimizationLevel {
    None       = 0,
    Less       = 1,
    Default    = 2,
    Aggressive = 3
}

impl Default for OptimizationLevel {
    /// Returns the default value for `OptimizationLevel`, namely `OptimizationLevel::Default`.
    fn default() -> Self {
        OptimizationLevel::Default
    }
}

enum_rename!{
    GlobalVisibility <=> LLVMVisibility {
        Default <=> LLVMDefaultVisibility,
        Hidden <=> LLVMHiddenVisibility,
        Protected <=> LLVMProtectedVisibility,
    }
}

impl Default for GlobalVisibility {
    /// Returns the default value for `GlobalVisibility`, namely `GlobalVisibility::Default`.
    fn default() -> Self {
        GlobalVisibility::Default
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ThreadLocalMode {
    GeneralDynamicTLSModel,
    LocalDynamicTLSModel,
    InitialExecTLSModel,
    LocalExecTLSModel,
}

impl ThreadLocalMode {
    pub(crate) fn new(thread_local_mode: LLVMThreadLocalMode) -> Option<Self> {
        match thread_local_mode {
            LLVMThreadLocalMode::LLVMGeneralDynamicTLSModel => Some(ThreadLocalMode::GeneralDynamicTLSModel),
            LLVMThreadLocalMode::LLVMLocalDynamicTLSModel => Some(ThreadLocalMode::LocalDynamicTLSModel),
            LLVMThreadLocalMode::LLVMInitialExecTLSModel => Some(ThreadLocalMode::InitialExecTLSModel),
            LLVMThreadLocalMode::LLVMLocalExecTLSModel => Some(ThreadLocalMode::LocalExecTLSModel),
            LLVMThreadLocalMode::LLVMNotThreadLocal => None
        }
    }

    pub(crate) fn as_llvm_mode(&self) -> LLVMThreadLocalMode {
        match *self {
            ThreadLocalMode::GeneralDynamicTLSModel => LLVMThreadLocalMode::LLVMGeneralDynamicTLSModel,
            ThreadLocalMode::LocalDynamicTLSModel => LLVMThreadLocalMode::LLVMLocalDynamicTLSModel,
            ThreadLocalMode::InitialExecTLSModel => LLVMThreadLocalMode::LLVMInitialExecTLSModel,
            ThreadLocalMode::LocalExecTLSModel => LLVMThreadLocalMode::LLVMLocalExecTLSModel,
            // None => LLVMThreadLocalMode::LLVMNotThreadLocal,
        }
    }
}

enum_rename! {
    DLLStorageClass <=> LLVMDLLStorageClass {
        Default <=> LLVMDefaultStorageClass,
        Import <=> LLVMDLLImportStorageClass,
        Export <=> LLVMDLLExportStorageClass,
    }
}

impl Default for DLLStorageClass {
    /// Returns the default value for `DLLStorageClass`, namely `DLLStorageClass::Default`.
    fn default() -> Self {
        DLLStorageClass::Default
    }
}