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(12..)]
8use llvm_sys::core::{LLVMGetTypeAttributeValue, LLVMIsTypeAttribute};
9use llvm_sys::prelude::LLVMAttributeRef;
10
11use std::ffi::CStr;
12
13#[llvm_versions(12..)]
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)]
21pub struct Attribute {
22 pub(crate) attribute: LLVMAttributeRef,
23}
24
25impl std::fmt::Debug for Attribute {
26 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27 if self.is_string() {
28 return f
29 .debug_struct("Attribute::String")
30 .field("ptr", &self.attribute)
31 .field("kind_id", &self.get_string_kind_id())
32 .field("value", &self.get_string_value())
33 .finish();
34 }
35
36 if self.is_enum() {
37 return f
38 .debug_struct("Attribute::Enum")
39 .field("ptr", &self.attribute)
40 .field("kind_id", &self.get_enum_kind_id())
41 .field("value", &self.get_enum_value())
42 .finish();
43 }
44
45 if self.is_type() {
46 return f
47 .debug_struct("Attribute::Type")
48 .field("ptr", &self.attribute)
49 .field("kind_id", &self.get_enum_kind_id())
50 .field("value", &self.get_type_value())
51 .finish();
52 }
53
54 unreachable!(
55 "attribute at {:?} is not a string, enum or type attribute",
56 self.attribute
57 );
58 }
59}
60
61impl Eq for Attribute {}
62
63impl PartialEq<Self> for Attribute {
64 fn eq(&self, other: &Self) -> bool {
65 if self.is_enum() && other.is_enum() {
66 return self.get_enum_kind_id() == other.get_enum_kind_id()
67 && self.get_enum_value() == other.get_enum_value();
68 }
69
70 if self.is_string() && other.is_string() {
71 return self.get_string_kind_id() == other.get_string_kind_id()
72 && self.get_string_value() == other.get_string_value();
73 }
74
75 if self.is_type() && other.is_type() {
76 // Seems to be some clippy bug here, but it's not clear why.
77 #[allow(clippy::unit_cmp)]
78 return self.get_enum_kind_id() == other.get_enum_kind_id()
79 && self.get_type_value() == other.get_type_value();
80 }
81
82 self.attribute == other.attribute
83 }
84}
85
86impl Attribute {
87 /// Creates a new `Attribute` from a raw pointer.
88 pub unsafe fn new(attribute: LLVMAttributeRef) -> Self {
89 debug_assert!(!attribute.is_null());
90
91 Attribute { attribute }
92 }
93
94 /// Acquires the underlying raw pointer belonging to this `Attribute` type.
95 pub fn as_mut_ptr(&self) -> LLVMAttributeRef {
96 self.attribute
97 }
98
99 /// Determines whether or not an `Attribute` is an enum. This method will
100 /// likely be removed in the future in favor of `Attribute`s being generically
101 /// defined.
102 ///
103 /// # Example
104 ///
105 /// ```no_run
106 /// use inkwell::context::Context;
107 ///
108 /// let context = Context::create();
109 /// let enum_attribute = context.create_enum_attribute(0, 10);
110 ///
111 /// assert!(enum_attribute.is_enum());
112 /// ```
113 pub fn is_enum(self) -> bool {
114 unsafe { LLVMIsEnumAttribute(self.attribute) == 1 }
115 }
116
117 /// Determines whether or not an `Attribute` is a string. This method will
118 /// likely be removed in the future in favor of `Attribute`s being generically
119 /// defined.
120 ///
121 /// # Example
122 ///
123 /// ```no_run
124 /// use inkwell::context::Context;
125 ///
126 /// let context = Context::create();
127 /// let string_attribute = context.create_string_attribute("my_key_123", "my_val");
128 ///
129 /// assert!(string_attribute.is_string());
130 /// ```
131 pub fn is_string(self) -> bool {
132 unsafe { LLVMIsStringAttribute(self.attribute) == 1 }
133 }
134
135 /// Determines whether or not an `Attribute` is a type attribute. This method will
136 /// likely be removed in the future in favor of `Attribute`s being generically
137 /// defined.
138 ///
139 /// # Example
140 ///
141 /// ```no_run
142 /// use inkwell::context::Context;
143 /// use inkwell::attributes::Attribute;
144 ///
145 /// let context = Context::create();
146 /// let kind_id = Attribute::get_named_enum_kind_id("sret");
147 /// let type_attribute = context.create_type_attribute(
148 /// kind_id,
149 /// context.i32_type().into(),
150 /// );
151 ///
152 /// assert!(type_attribute.is_type());
153 /// ```
154 #[llvm_versions(12..)]
155 pub fn is_type(self) -> bool {
156 unsafe { LLVMIsTypeAttribute(self.attribute) == 1 }
157 }
158
159 // private function to make code elsewhere easier
160 #[llvm_versions(..12)]
161 fn is_type(self) -> bool {
162 false
163 }
164
165 /// Gets the enum kind id associated with a builtin name.
166 ///
167 /// # Example
168 ///
169 /// ```no_run
170 /// use inkwell::attributes::Attribute;
171 ///
172 /// // This kind id doesn't exist:
173 /// assert_eq!(Attribute::get_named_enum_kind_id("foobar"), 0);
174 ///
175 /// // These are real kind ids:
176 /// assert_eq!(Attribute::get_named_enum_kind_id("align"), 1);
177 /// assert_eq!(Attribute::get_named_enum_kind_id("builtin"), 5);
178 /// ```
179 pub fn get_named_enum_kind_id(name: &str) -> u32 {
180 unsafe { LLVMGetEnumAttributeKindForName(name.as_ptr() as *const ::libc::c_char, name.len()) }
181 }
182
183 /// Gets the kind id associated with an enum `Attribute`.
184 ///
185 /// # Example
186 ///
187 /// ```no_run
188 /// use inkwell::context::Context;
189 ///
190 /// let context = Context::create();
191 /// let enum_attribute = context.create_enum_attribute(0, 10);
192 ///
193 /// assert_eq!(enum_attribute.get_enum_kind_id(), 0);
194 /// ```
195 #[cfg(feature = "llvm11-0")]
196 pub fn get_enum_kind_id(self) -> u32 {
197 assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes
198
199 unsafe { LLVMGetEnumAttributeKind(self.attribute) }
200 }
201
202 /// Gets the kind id associated with an enum `Attribute`.
203 ///
204 /// # Example
205 ///
206 /// ```no_run
207 /// use inkwell::context::Context;
208 ///
209 /// let context = Context::create();
210 /// let enum_attribute = context.create_enum_attribute(0, 10);
211 ///
212 /// assert_eq!(enum_attribute.get_enum_kind_id(), 0);
213 /// ```
214 ///
215 /// This function also works for type `Attribute`s.
216 ///
217 /// ```no_run
218 /// use inkwell::context::Context;
219 /// use inkwell::attributes::Attribute;
220 /// use inkwell::types::AnyType;
221 ///
222 /// let context = Context::create();
223 /// let kind_id = Attribute::get_named_enum_kind_id("sret");
224 /// let any_type = context.i32_type().as_any_type_enum();
225 /// let type_attribute = context.create_type_attribute(
226 /// kind_id,
227 /// any_type,
228 /// );
229 ///
230 /// assert_eq!(type_attribute.get_enum_kind_id(), kind_id);
231 /// ```
232 #[llvm_versions(12..)]
233 pub fn get_enum_kind_id(self) -> u32 {
234 assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes
235
236 unsafe { LLVMGetEnumAttributeKind(self.attribute) }
237 }
238
239 #[cfg(feature = "llvm11-0")]
240 fn get_enum_kind_id_is_valid(self) -> bool {
241 self.is_enum()
242 }
243
244 #[llvm_versions(12..)]
245 fn get_enum_kind_id_is_valid(self) -> bool {
246 self.is_enum() || self.is_type()
247 }
248
249 /// Gets the last enum kind id associated with builtin names.
250 ///
251 /// # Example
252 ///
253 /// ```no_run
254 /// use inkwell::attributes::Attribute;
255 ///
256 /// assert_eq!(Attribute::get_last_enum_kind_id(), 56);
257 /// ```
258 pub fn get_last_enum_kind_id() -> u32 {
259 unsafe { LLVMGetLastEnumAttributeKind() }
260 }
261
262 /// Gets the value associated with an enum `Attribute`.
263 ///
264 /// # Example
265 ///
266 /// ```no_run
267 /// use inkwell::context::Context;
268 ///
269 /// let context = Context::create();
270 /// let enum_attribute = context.create_enum_attribute(0, 10);
271 ///
272 /// assert_eq!(enum_attribute.get_enum_value(), 10);
273 /// ```
274 pub fn get_enum_value(self) -> u64 {
275 assert!(self.is_enum()); // FIXME: SubTypes
276
277 unsafe { LLVMGetEnumAttributeValue(self.attribute) }
278 }
279
280 /// Gets the string kind id associated with a string attribute.
281 ///
282 /// # Example
283 ///
284 /// ```no_run
285 /// use inkwell::context::Context;
286 ///
287 /// let context = Context::create();
288 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
289 ///
290 /// assert_eq!(string_attribute.get_string_kind_id().to_str(), Ok("my_key"));
291 /// ```
292 // TODO: Check if null, return option
293 pub fn get_string_kind_id(&self) -> &CStr {
294 assert!(self.is_string()); // FIXME: SubTypes
295
296 let mut length = 0;
297 let cstr_ptr = unsafe { LLVMGetStringAttributeKind(self.attribute, &mut length) };
298
299 unsafe { CStr::from_ptr(cstr_ptr) }
300 }
301
302 /// Gets the string value associated with a string attribute.
303 ///
304 /// # Example
305 ///
306 /// ```no_run
307 /// use inkwell::context::Context;
308 ///
309 /// let context = Context::create();
310 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
311 ///
312 /// assert_eq!(string_attribute.get_string_value().to_str(), Ok("my_val"));
313 /// ```
314 pub fn get_string_value(&self) -> &CStr {
315 assert!(self.is_string()); // FIXME: SubTypes
316
317 let mut length = 0;
318 let cstr_ptr = unsafe { LLVMGetStringAttributeValue(self.attribute, &mut length) };
319
320 unsafe { CStr::from_ptr(cstr_ptr) }
321 }
322
323 /// Gets the type associated with a type attribute.
324 ///
325 /// # Example
326 ///
327 /// ```no_run
328 /// use inkwell::context::Context;
329 /// use inkwell::attributes::Attribute;
330 /// use inkwell::types::AnyType;
331 ///
332 /// let context = Context::create();
333 /// let kind_id = Attribute::get_named_enum_kind_id("sret");
334 /// let any_type = context.i32_type().as_any_type_enum();
335 /// let type_attribute = context.create_type_attribute(
336 /// kind_id,
337 /// any_type,
338 /// );
339 ///
340 /// assert!(type_attribute.is_type());
341 /// assert_eq!(type_attribute.get_type_value(), any_type);
342 /// assert_ne!(type_attribute.get_type_value(), context.i64_type().as_any_type_enum());
343 /// ```
344 #[llvm_versions(12..)]
345 pub fn get_type_value(&self) -> AnyTypeEnum<'_> {
346 assert!(self.is_type()); // FIXME: SubTypes
347
348 unsafe { AnyTypeEnum::new(LLVMGetTypeAttributeValue(self.attribute)) }
349 }
350
351 // private function to make code elsewhere easier
352 #[llvm_versions(..12)]
353 fn get_type_value(&self) {
354 unreachable!("not implemented in this version")
355 }
356}
357
358/// An `AttributeLoc` determines where on a function an attribute is assigned to.
359#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
360pub enum AttributeLoc {
361 /// Assign to the `FunctionValue`'s return type.
362 Return,
363 /// Assign to one of the `FunctionValue`'s params (0-indexed).
364 Param(u32),
365 /// Assign to the `FunctionValue` itself.
366 Function,
367}
368
369impl AttributeLoc {
370 pub(crate) fn get_index(self) -> u32 {
371 match self {
372 AttributeLoc::Return => 0,
373 AttributeLoc::Param(index) => {
374 assert!(index <= u32::MAX - 2, "Param index must be <= u32::MAX - 2");
375 index + 1
376 },
377 AttributeLoc::Function => u32::MAX,
378 }
379 }
380}