llvm_plugin_inkwell/
attributes.rs

1//! `Attribute`s are optional modifiers to functions, function parameters, and return types.
2
3use llvm_sys::core::{
4    LLVMGetEnumAttributeKind, LLVMGetEnumAttributeKindForName, LLVMGetEnumAttributeValue, LLVMGetLastEnumAttributeKind,
5    LLVMGetStringAttributeKind, LLVMGetStringAttributeValue, LLVMIsEnumAttribute, LLVMIsStringAttribute,
6};
7#[llvm_versions(13.0..=latest)]
8use llvm_sys::core::{LLVMGetTypeAttributeValue, LLVMIsTypeAttribute};
9use llvm_sys::prelude::LLVMAttributeRef;
10
11use std::ffi::CStr;
12
13#[llvm_versions(12.0..=latest)]
14use crate::types::AnyTypeEnum;
15
16// SubTypes: Attribute<Enum>, Attribute<String>
17// REVIEW: Should Attributes have a 'ctx lifetime?
18/// Functions, function parameters, and return types can have `Attribute`s to indicate
19/// how they should be treated by optimizations and code generation.
20#[derive(Clone, Copy, Debug, PartialEq, Eq)]
21pub struct Attribute {
22    pub(crate) attribute: LLVMAttributeRef,
23}
24
25impl Attribute {
26    /// Creates a new `Attribute` from a raw pointer.
27    pub unsafe fn new(attribute: LLVMAttributeRef) -> Self {
28        debug_assert!(!attribute.is_null());
29
30        Attribute { attribute }
31    }
32
33    /// Acquires the underlying raw pointer belonging to this `Attribute` type.
34    pub fn as_mut_ptr(&self) -> LLVMAttributeRef {
35        self.attribute
36    }
37
38    /// Determines whether or not an `Attribute` is an enum. This method will
39    /// likely be removed in the future in favor of `Attribute`s being generically
40    /// defined.
41    ///
42    /// # Example
43    ///
44    /// ```no_run
45    /// use inkwell::context::Context;
46    ///
47    /// let context = Context::create();
48    /// let enum_attribute = context.create_enum_attribute(0, 10);
49    ///
50    /// assert!(enum_attribute.is_enum());
51    /// ```
52    pub fn is_enum(self) -> bool {
53        unsafe { LLVMIsEnumAttribute(self.attribute) == 1 }
54    }
55
56    /// Determines whether or not an `Attribute` is a string. This method will
57    /// likely be removed in the future in favor of `Attribute`s being generically
58    /// defined.
59    ///
60    /// # Example
61    ///
62    /// ```no_run
63    /// use inkwell::context::Context;
64    ///
65    /// let context = Context::create();
66    /// let string_attribute = context.create_string_attribute("my_key_123", "my_val");
67    ///
68    /// assert!(string_attribute.is_string());
69    /// ```
70    pub fn is_string(self) -> bool {
71        unsafe { LLVMIsStringAttribute(self.attribute) == 1 }
72    }
73
74    /// Determines whether or not an `Attribute` is a type attribute. This method will
75    /// likely be removed in the future in favor of `Attribute`s being generically
76    /// defined.
77    ///
78    /// # Example
79    ///
80    /// ```no_run
81    /// use inkwell::context::Context;
82    /// use inkwell::attributes::Attribute;
83    ///
84    /// let context = Context::create();
85    /// let kind_id = Attribute::get_named_enum_kind_id("sret");
86    /// let type_attribute = context.create_type_attribute(
87    ///     kind_id,
88    ///     context.i32_type().into(),
89    /// );
90    ///
91    /// assert!(type_attribute.is_type());
92    /// ```
93    #[llvm_versions(13.0..=latest)]
94    pub fn is_type(self) -> bool {
95        unsafe { LLVMIsTypeAttribute(self.attribute) == 1 }
96    }
97
98    /// Gets the enum kind id associated with a builtin name.
99    ///
100    /// # Example
101    ///
102    /// ```no_run
103    /// use inkwell::attributes::Attribute;
104    ///
105    /// // This kind id doesn't exist:
106    /// assert_eq!(Attribute::get_named_enum_kind_id("foobar"), 0);
107    ///
108    /// // These are real kind ids:
109    /// assert_eq!(Attribute::get_named_enum_kind_id("align"), 1);
110    /// assert_eq!(Attribute::get_named_enum_kind_id("builtin"), 5);
111    /// ```
112    pub fn get_named_enum_kind_id(name: &str) -> u32 {
113        unsafe { LLVMGetEnumAttributeKindForName(name.as_ptr() as *const ::libc::c_char, name.len()) }
114    }
115
116    /// Gets the kind id associated with an enum `Attribute`.
117    ///
118    /// # Example
119    ///
120    /// ```no_run
121    /// use inkwell::context::Context;
122    ///
123    /// let context = Context::create();
124    /// let enum_attribute = context.create_enum_attribute(0, 10);
125    ///
126    /// assert_eq!(enum_attribute.get_enum_kind_id(), 0);
127    /// ```
128    #[llvm_versions(4.0..=11.0)]
129    pub fn get_enum_kind_id(self) -> u32 {
130        assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes
131
132        unsafe { LLVMGetEnumAttributeKind(self.attribute) }
133    }
134
135    /// Gets the kind id associated with an enum `Attribute`.
136    ///
137    /// # Example
138    ///
139    /// ```no_run
140    /// use inkwell::context::Context;
141    ///
142    /// let context = Context::create();
143    /// let enum_attribute = context.create_enum_attribute(0, 10);
144    ///
145    /// assert_eq!(enum_attribute.get_enum_kind_id(), 0);
146    /// ```
147    ///
148    /// This function also works for type `Attribute`s.
149    ///
150    /// ```no_run
151    /// use inkwell::context::Context;
152    /// use inkwell::attributes::Attribute;
153    /// use inkwell::types::AnyType;
154    ///
155    /// let context = Context::create();
156    /// let kind_id = Attribute::get_named_enum_kind_id("sret");
157    /// let any_type = context.i32_type().as_any_type_enum();
158    /// let type_attribute = context.create_type_attribute(
159    ///     kind_id,
160    ///     any_type,
161    /// );
162    ///
163    /// assert_eq!(type_attribute.get_enum_kind_id(), kind_id);
164    /// ```
165    #[llvm_versions(13.0..=latest)]
166    pub fn get_enum_kind_id(self) -> u32 {
167        assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes
168
169        unsafe { LLVMGetEnumAttributeKind(self.attribute) }
170    }
171
172    #[llvm_versions(4.0..=11.0)]
173    fn get_enum_kind_id_is_valid(self) -> bool {
174        self.is_enum()
175    }
176
177    #[llvm_versions(13.0..=latest)]
178    fn get_enum_kind_id_is_valid(self) -> bool {
179        self.is_enum() || self.is_type()
180    }
181
182    /// Gets the last enum kind id associated with builtin names.
183    ///
184    /// # Example
185    ///
186    /// ```no_run
187    /// use inkwell::attributes::Attribute;
188    ///
189    /// assert_eq!(Attribute::get_last_enum_kind_id(), 56);
190    /// ```
191    pub fn get_last_enum_kind_id() -> u32 {
192        unsafe { LLVMGetLastEnumAttributeKind() }
193    }
194
195    /// Gets the value associated with an enum `Attribute`.
196    ///
197    /// # Example
198    ///
199    /// ```no_run
200    /// use inkwell::context::Context;
201    ///
202    /// let context = Context::create();
203    /// let enum_attribute = context.create_enum_attribute(0, 10);
204    ///
205    /// assert_eq!(enum_attribute.get_enum_value(), 10);
206    /// ```
207    pub fn get_enum_value(self) -> u64 {
208        assert!(self.is_enum()); // FIXME: SubTypes
209
210        unsafe { LLVMGetEnumAttributeValue(self.attribute) }
211    }
212
213    /// Gets the string kind id associated with a string attribute.
214    ///
215    /// # Example
216    ///
217    /// ```no_run
218    /// use inkwell::context::Context;
219    ///
220    /// let context = Context::create();
221    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
222    ///
223    /// assert_eq!(string_attribute.get_string_kind_id().to_str(), Ok("my_key"));
224    /// ```
225    // TODO: Check if null, return option
226    pub fn get_string_kind_id(&self) -> &CStr {
227        assert!(self.is_string()); // FIXME: SubTypes
228
229        let mut length = 0;
230        let cstr_ptr = unsafe { LLVMGetStringAttributeKind(self.attribute, &mut length) };
231
232        unsafe { CStr::from_ptr(cstr_ptr) }
233    }
234
235    /// Gets the string value associated with a string attribute.
236    ///
237    /// # Example
238    ///
239    /// ```no_run
240    /// use inkwell::context::Context;
241    ///
242    /// let context = Context::create();
243    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
244    ///
245    /// assert_eq!(string_attribute.get_string_value().to_str(), Ok("my_val"));
246    /// ```
247    pub fn get_string_value(&self) -> &CStr {
248        assert!(self.is_string()); // FIXME: SubTypes
249
250        let mut length = 0;
251        let cstr_ptr = unsafe { LLVMGetStringAttributeValue(self.attribute, &mut length) };
252
253        unsafe { CStr::from_ptr(cstr_ptr) }
254    }
255
256    /// Gets the type associated with a type attribute.
257    ///
258    /// # Example
259    ///
260    /// ```no_run
261    /// use inkwell::context::Context;
262    /// use inkwell::attributes::Attribute;
263    /// use inkwell::types::AnyType;
264    ///
265    /// let context = Context::create();
266    /// let kind_id = Attribute::get_named_enum_kind_id("sret");
267    /// let any_type = context.i32_type().as_any_type_enum();
268    /// let type_attribute = context.create_type_attribute(
269    ///     kind_id,
270    ///     any_type,
271    /// );
272    ///
273    /// assert!(type_attribute.is_type());
274    /// assert_eq!(type_attribute.get_type_value(), any_type);
275    /// assert_ne!(type_attribute.get_type_value(), context.i64_type().as_any_type_enum());
276    /// ```
277    #[llvm_versions(13.0..=latest)]
278    pub fn get_type_value(&self) -> AnyTypeEnum {
279        assert!(self.is_type()); // FIXME: SubTypes
280
281        unsafe { AnyTypeEnum::new(LLVMGetTypeAttributeValue(self.attribute)) }
282    }
283}
284
285/// An `AttributeLoc` determines where on a function an attribute is assigned to.
286#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
287pub enum AttributeLoc {
288    /// Assign to the `FunctionValue`'s return type.
289    Return,
290    /// Assign to one of the `FunctionValue`'s params (0-indexed).
291    Param(u32),
292    /// Assign to the `FunctionValue` itself.
293    Function,
294}
295
296impl AttributeLoc {
297    pub(crate) fn get_index(self) -> u32 {
298        match self {
299            AttributeLoc::Return => 0,
300            AttributeLoc::Param(index) => {
301                assert!(
302                    index <= u32::max_value() - 2,
303                    "Param index must be <= u32::max_value() - 2"
304                );
305
306                index + 1
307            },
308            AttributeLoc::Function => u32::max_value(),
309        }
310    }
311}