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}