/rust/registry/src/index.crates.io-6f17d22bba15001f/inkwell-0.1.1/src/attributes.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! `Attribute`s are optional modifiers to functions, function parameters, and return types. |
2 | | |
3 | | use llvm_sys::core::{ |
4 | | LLVMGetEnumAttributeKind, LLVMGetEnumAttributeKindForName, LLVMGetEnumAttributeValue, LLVMGetLastEnumAttributeKind, |
5 | | LLVMGetStringAttributeKind, LLVMGetStringAttributeValue, LLVMIsEnumAttribute, LLVMIsStringAttribute, |
6 | | }; |
7 | | #[llvm_versions(12.0..=latest)] |
8 | | use llvm_sys::core::{LLVMGetTypeAttributeValue, LLVMIsTypeAttribute}; |
9 | | use llvm_sys::prelude::LLVMAttributeRef; |
10 | | |
11 | | use std::ffi::CStr; |
12 | | |
13 | | #[llvm_versions(12.0..=latest)] |
14 | | use 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)] |
21 | | pub struct Attribute { |
22 | | pub(crate) attribute: LLVMAttributeRef, |
23 | | } |
24 | | |
25 | | impl Attribute { |
26 | | /// Creates a new `Attribute` from a raw pointer. |
27 | 1.03M | pub unsafe fn new(attribute: LLVMAttributeRef) -> Self { |
28 | 1.03M | debug_assert!(!attribute.is_null()); |
29 | | |
30 | 1.03M | Attribute { attribute } |
31 | 1.03M | } |
32 | | |
33 | | /// Acquires the underlying raw pointer belonging to this `Attribute` type. |
34 | 0 | pub fn as_mut_ptr(&self) -> LLVMAttributeRef { |
35 | 0 | self.attribute |
36 | 0 | } |
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 | 0 | pub fn is_enum(self) -> bool { |
53 | 0 | unsafe { LLVMIsEnumAttribute(self.attribute) == 1 } |
54 | 0 | } |
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 | 0 | pub fn is_string(self) -> bool { |
71 | 0 | unsafe { LLVMIsStringAttribute(self.attribute) == 1 } |
72 | 0 | } |
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(12.0..=latest)] |
94 | 0 | pub fn is_type(self) -> bool { |
95 | 0 | unsafe { LLVMIsTypeAttribute(self.attribute) == 1 } |
96 | 0 | } |
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 | 1.02M | pub fn get_named_enum_kind_id(name: &str) -> u32 { |
113 | 1.02M | unsafe { LLVMGetEnumAttributeKindForName(name.as_ptr() as *const ::libc::c_char, name.len()) } |
114 | 1.02M | } |
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(12.0..=latest)] |
166 | 0 | pub fn get_enum_kind_id(self) -> u32 { |
167 | 0 | assert!(self.get_enum_kind_id_is_valid()); // FIXME: SubTypes |
168 | | |
169 | 0 | unsafe { LLVMGetEnumAttributeKind(self.attribute) } |
170 | 0 | } |
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(12.0..=latest)] |
178 | 0 | fn get_enum_kind_id_is_valid(self) -> bool { |
179 | 0 | self.is_enum() || self.is_type() |
180 | 0 | } |
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 | 0 | pub fn get_last_enum_kind_id() -> u32 { |
192 | 0 | unsafe { LLVMGetLastEnumAttributeKind() } |
193 | 0 | } |
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 | 0 | pub fn get_enum_value(self) -> u64 { |
208 | 0 | assert!(self.is_enum()); // FIXME: SubTypes |
209 | | |
210 | 0 | unsafe { LLVMGetEnumAttributeValue(self.attribute) } |
211 | 0 | } |
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 | 0 | pub fn get_string_kind_id(&self) -> &CStr { |
227 | 0 | assert!(self.is_string()); // FIXME: SubTypes |
228 | | |
229 | 0 | let mut length = 0; |
230 | 0 | let cstr_ptr = unsafe { LLVMGetStringAttributeKind(self.attribute, &mut length) }; |
231 | 0 |
|
232 | 0 | unsafe { CStr::from_ptr(cstr_ptr) } |
233 | 0 | } |
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 | 0 | pub fn get_string_value(&self) -> &CStr { |
248 | 0 | assert!(self.is_string()); // FIXME: SubTypes |
249 | | |
250 | 0 | let mut length = 0; |
251 | 0 | let cstr_ptr = unsafe { LLVMGetStringAttributeValue(self.attribute, &mut length) }; |
252 | 0 |
|
253 | 0 | unsafe { CStr::from_ptr(cstr_ptr) } |
254 | 0 | } |
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(12.0..=latest)] |
278 | 0 | pub fn get_type_value(&self) -> AnyTypeEnum { |
279 | 0 | assert!(self.is_type()); // FIXME: SubTypes |
280 | | |
281 | 0 | unsafe { AnyTypeEnum::new(LLVMGetTypeAttributeValue(self.attribute)) } |
282 | 0 | } |
283 | | } |
284 | | |
285 | | /// An `AttributeLoc` determines where on a function an attribute is assigned to. |
286 | | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] |
287 | | pub 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 | | |
296 | | impl AttributeLoc { |
297 | 1.26M | pub(crate) fn get_index(self) -> u32 { |
298 | 1.26M | match self { |
299 | 0 | AttributeLoc::Return => 0, |
300 | 819k | AttributeLoc::Param(index) => { |
301 | 819k | assert!( |
302 | 819k | index <= u32::max_value() - 2, |
303 | 0 | "Param index must be <= u32::max_value() - 2" |
304 | | ); |
305 | | |
306 | 819k | index + 1 |
307 | | }, |
308 | 446k | AttributeLoc::Function => u32::max_value(), |
309 | | } |
310 | 1.26M | } |
311 | | } |