llvm_plugin_inkwell/values/call_site_value.rs
1use std::fmt::{self, Display};
2
3use either::Either;
4use llvm_sys::core::{
5 LLVMGetInstructionCallConv, LLVMGetTypeKind, LLVMIsTailCall, LLVMSetInstrParamAlignment,
6 LLVMSetInstructionCallConv, LLVMSetTailCall, LLVMTypeOf,
7};
8use llvm_sys::prelude::LLVMValueRef;
9use llvm_sys::LLVMTypeKind;
10
11use crate::attributes::{Attribute, AttributeLoc};
12use crate::values::{AsValueRef, BasicValueEnum, FunctionValue, InstructionValue, Value};
13
14use super::AnyValue;
15
16/// A value resulting from a function call. It may have function attributes applied to it.
17///
18/// This struct may be removed in the future in favor of an `InstructionValue<CallSite>` type.
19#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
20pub struct CallSiteValue<'ctx>(Value<'ctx>);
21
22impl<'ctx> CallSiteValue<'ctx> {
23 pub(crate) unsafe fn new(value: LLVMValueRef) -> Self {
24 CallSiteValue(Value::new(value))
25 }
26
27 /// Sets whether or not this call is a tail call.
28 ///
29 /// # Example
30 ///
31 /// ```no_run
32 /// use inkwell::context::Context;
33 ///
34 /// let context = Context::create();
35 /// let builder = context.create_builder();
36 /// let module = context.create_module("my_mod");
37 /// let void_type = context.void_type();
38 /// let fn_type = void_type.fn_type(&[], false);
39 /// let fn_value = module.add_function("my_fn", fn_type, None);
40 /// let entry_bb = context.append_basic_block(fn_value, "entry");
41 ///
42 /// builder.position_at_end(entry_bb);
43 ///
44 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
45 ///
46 /// call_site_value.set_tail_call(true);
47 /// ```
48 pub fn set_tail_call(self, tail_call: bool) {
49 unsafe { LLVMSetTailCall(self.as_value_ref(), tail_call as i32) }
50 }
51
52 /// Determines whether or not this call is a tail call.
53 ///
54 /// # Example
55 ///
56 /// ```no_run
57 /// use inkwell::context::Context;
58 ///
59 /// let context = Context::create();
60 /// let builder = context.create_builder();
61 /// let module = context.create_module("my_mod");
62 /// let void_type = context.void_type();
63 /// let fn_type = void_type.fn_type(&[], false);
64 /// let fn_value = module.add_function("my_fn", fn_type, None);
65 /// let entry_bb = context.append_basic_block(fn_value, "entry");
66 ///
67 /// builder.position_at_end(entry_bb);
68 ///
69 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
70 ///
71 /// call_site_value.set_tail_call(true);
72 ///
73 /// assert!(call_site_value.is_tail_call());
74 /// ```
75 pub fn is_tail_call(self) -> bool {
76 unsafe { LLVMIsTailCall(self.as_value_ref()) == 1 }
77 }
78
79 /// Try to convert this `CallSiteValue` to a `BasicValueEnum` if not a void return type.
80 ///
81 /// # Example
82 ///
83 /// ```no_run
84 /// use inkwell::context::Context;
85 ///
86 /// let context = Context::create();
87 /// let builder = context.create_builder();
88 /// let module = context.create_module("my_mod");
89 /// let void_type = context.void_type();
90 /// let fn_type = void_type.fn_type(&[], false);
91 /// let fn_value = module.add_function("my_fn", fn_type, None);
92 /// let entry_bb = context.append_basic_block(fn_value, "entry");
93 ///
94 /// builder.position_at_end(entry_bb);
95 ///
96 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
97 ///
98 /// assert!(call_site_value.try_as_basic_value().is_right());
99 /// ```
100 pub fn try_as_basic_value(self) -> Either<BasicValueEnum<'ctx>, InstructionValue<'ctx>> {
101 unsafe {
102 match LLVMGetTypeKind(LLVMTypeOf(self.as_value_ref())) {
103 LLVMTypeKind::LLVMVoidTypeKind => Either::Right(InstructionValue::new(self.as_value_ref())),
104 _ => Either::Left(BasicValueEnum::new(self.as_value_ref())),
105 }
106 }
107 }
108
109 /// Adds an `Attribute` to this `CallSiteValue`.
110 ///
111 /// # Example
112 ///
113 /// ```no_run
114 /// use inkwell::attributes::AttributeLoc;
115 /// use inkwell::context::Context;
116 ///
117 /// let context = Context::create();
118 /// let builder = context.create_builder();
119 /// let module = context.create_module("my_mod");
120 /// let void_type = context.void_type();
121 /// let fn_type = void_type.fn_type(&[], false);
122 /// let fn_value = module.add_function("my_fn", fn_type, None);
123 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
124 /// let enum_attribute = context.create_enum_attribute(1, 1);
125 /// let entry_bb = context.append_basic_block(fn_value, "entry");
126 ///
127 /// builder.position_at_end(entry_bb);
128 ///
129 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
130 ///
131 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
132 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
133 /// ```
134 pub fn add_attribute(self, loc: AttributeLoc, attribute: Attribute) {
135 use llvm_sys::core::LLVMAddCallSiteAttribute;
136
137 unsafe { LLVMAddCallSiteAttribute(self.as_value_ref(), loc.get_index(), attribute.attribute) }
138 }
139
140 /// Gets the `FunctionValue` this `CallSiteValue` is based on.
141 ///
142 /// # Example
143 ///
144 /// ```no_run
145 /// use inkwell::context::Context;
146 ///
147 /// let context = Context::create();
148 /// let builder = context.create_builder();
149 /// let module = context.create_module("my_mod");
150 /// let void_type = context.void_type();
151 /// let fn_type = void_type.fn_type(&[], false);
152 /// let fn_value = module.add_function("my_fn", fn_type, None);
153 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
154 /// let enum_attribute = context.create_enum_attribute(1, 1);
155 /// let entry_bb = context.append_basic_block(fn_value, "entry");
156 ///
157 /// builder.position_at_end(entry_bb);
158 ///
159 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
160 ///
161 /// assert_eq!(call_site_value.get_called_fn_value(), fn_value);
162 /// ```
163 pub fn get_called_fn_value(self) -> FunctionValue<'ctx> {
164 use llvm_sys::core::LLVMGetCalledValue;
165
166 unsafe { FunctionValue::new(LLVMGetCalledValue(self.as_value_ref())).expect("This should never be null?") }
167 }
168
169 /// Counts the number of `Attribute`s on this `CallSiteValue` at an index.
170 ///
171 /// # Example
172 ///
173 /// ```no_run
174 /// use inkwell::attributes::AttributeLoc;
175 /// use inkwell::context::Context;
176 ///
177 /// let context = Context::create();
178 /// let builder = context.create_builder();
179 /// let module = context.create_module("my_mod");
180 /// let void_type = context.void_type();
181 /// let fn_type = void_type.fn_type(&[], false);
182 /// let fn_value = module.add_function("my_fn", fn_type, None);
183 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
184 /// let enum_attribute = context.create_enum_attribute(1, 1);
185 /// let entry_bb = context.append_basic_block(fn_value, "entry");
186 ///
187 /// builder.position_at_end(entry_bb);
188 ///
189 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
190 ///
191 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
192 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
193 ///
194 /// assert_eq!(call_site_value.count_attributes(AttributeLoc::Return), 2);
195 /// ```
196 pub fn count_attributes(self, loc: AttributeLoc) -> u32 {
197 use llvm_sys::core::LLVMGetCallSiteAttributeCount;
198
199 unsafe { LLVMGetCallSiteAttributeCount(self.as_value_ref(), loc.get_index()) }
200 }
201
202 /// Get all `Attribute`s on this `CallSiteValue` at an index.
203 ///
204 /// # Example
205 ///
206 /// ```no_run
207 /// use inkwell::attributes::AttributeLoc;
208 /// use inkwell::context::Context;
209 ///
210 /// let context = Context::create();
211 /// let builder = context.create_builder();
212 /// let module = context.create_module("my_mod");
213 /// let void_type = context.void_type();
214 /// let fn_type = void_type.fn_type(&[], false);
215 /// let fn_value = module.add_function("my_fn", fn_type, None);
216 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
217 /// let enum_attribute = context.create_enum_attribute(1, 1);
218 /// let entry_bb = context.append_basic_block(fn_value, "entry");
219 ///
220 /// builder.position_at_end(entry_bb);
221 ///
222 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
223 ///
224 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
225 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
226 ///
227 /// assert_eq!(call_site_value.attributes(AttributeLoc::Return), vec![ string_attribute, enum_attribute ]);
228 /// ```
229 pub fn attributes(self, loc: AttributeLoc) -> Vec<Attribute> {
230 use llvm_sys::core::LLVMGetCallSiteAttributes;
231 use std::mem::{ManuallyDrop, MaybeUninit};
232
233 let count = self.count_attributes(loc) as usize;
234
235 // initialize a vector, but leave each element uninitialized
236 let mut attribute_refs: Vec<MaybeUninit<Attribute>> = vec![MaybeUninit::uninit(); count];
237
238 // Safety: relies on `Attribute` having the same in-memory representation as `LLVMAttributeRef`
239 unsafe {
240 LLVMGetCallSiteAttributes(
241 self.as_value_ref(),
242 loc.get_index(),
243 attribute_refs.as_mut_ptr() as *mut _,
244 )
245 }
246
247 // Safety: all elements are initialized
248 unsafe {
249 // ensure the vector is not dropped
250 let mut attribute_refs = ManuallyDrop::new(attribute_refs);
251
252 Vec::from_raw_parts(
253 attribute_refs.as_mut_ptr() as *mut Attribute,
254 attribute_refs.len(),
255 attribute_refs.capacity(),
256 )
257 }
258 }
259
260 /// Gets an enum `Attribute` on this `CallSiteValue` at an index and kind id.
261 ///
262 /// # Example
263 ///
264 /// ```no_run
265 /// use inkwell::attributes::AttributeLoc;
266 /// use inkwell::context::Context;
267 ///
268 /// let context = Context::create();
269 /// let builder = context.create_builder();
270 /// let module = context.create_module("my_mod");
271 /// let void_type = context.void_type();
272 /// let fn_type = void_type.fn_type(&[], false);
273 /// let fn_value = module.add_function("my_fn", fn_type, None);
274 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
275 /// let enum_attribute = context.create_enum_attribute(1, 1);
276 /// let entry_bb = context.append_basic_block(fn_value, "entry");
277 ///
278 /// builder.position_at_end(entry_bb);
279 ///
280 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
281 ///
282 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
283 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
284 ///
285 /// assert_eq!(call_site_value.get_enum_attribute(AttributeLoc::Return, 1).unwrap(), enum_attribute);
286 /// ```
287 // SubTypes: -> Attribute<Enum>
288 pub fn get_enum_attribute(self, loc: AttributeLoc, kind_id: u32) -> Option<Attribute> {
289 use llvm_sys::core::LLVMGetCallSiteEnumAttribute;
290
291 let ptr = unsafe { LLVMGetCallSiteEnumAttribute(self.as_value_ref(), loc.get_index(), kind_id) };
292
293 if ptr.is_null() {
294 return None;
295 }
296
297 unsafe { Some(Attribute::new(ptr)) }
298 }
299
300 /// Gets a string `Attribute` on this `CallSiteValue` at an index and key.
301 ///
302 /// # Example
303 ///
304 /// ```no_run
305 /// use inkwell::attributes::AttributeLoc;
306 /// use inkwell::context::Context;
307 ///
308 /// let context = Context::create();
309 /// let builder = context.create_builder();
310 /// let module = context.create_module("my_mod");
311 /// let void_type = context.void_type();
312 /// let fn_type = void_type.fn_type(&[], false);
313 /// let fn_value = module.add_function("my_fn", fn_type, None);
314 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
315 /// let enum_attribute = context.create_enum_attribute(1, 1);
316 /// let entry_bb = context.append_basic_block(fn_value, "entry");
317 ///
318 /// builder.position_at_end(entry_bb);
319 ///
320 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
321 ///
322 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
323 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
324 ///
325 /// assert_eq!(call_site_value.get_string_attribute(AttributeLoc::Return, "my_key").unwrap(), string_attribute);
326 /// ```
327 // SubTypes: -> Attribute<String>
328 pub fn get_string_attribute(self, loc: AttributeLoc, key: &str) -> Option<Attribute> {
329 use llvm_sys::core::LLVMGetCallSiteStringAttribute;
330
331 let ptr = unsafe {
332 LLVMGetCallSiteStringAttribute(
333 self.as_value_ref(),
334 loc.get_index(),
335 key.as_ptr() as *const ::libc::c_char,
336 key.len() as u32,
337 )
338 };
339
340 if ptr.is_null() {
341 return None;
342 }
343
344 unsafe { Some(Attribute::new(ptr)) }
345 }
346
347 /// Removes an enum `Attribute` on this `CallSiteValue` at an index and kind id.
348 ///
349 /// # Example
350 ///
351 /// ```no_run
352 /// use inkwell::attributes::AttributeLoc;
353 /// use inkwell::context::Context;
354 ///
355 /// let context = Context::create();
356 /// let builder = context.create_builder();
357 /// let module = context.create_module("my_mod");
358 /// let void_type = context.void_type();
359 /// let fn_type = void_type.fn_type(&[], false);
360 /// let fn_value = module.add_function("my_fn", fn_type, None);
361 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
362 /// let enum_attribute = context.create_enum_attribute(1, 1);
363 /// let entry_bb = context.append_basic_block(fn_value, "entry");
364 ///
365 /// builder.position_at_end(entry_bb);
366 ///
367 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
368 ///
369 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
370 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
371 /// call_site_value.remove_enum_attribute(AttributeLoc::Return, 1);
372 ///
373 /// assert_eq!(call_site_value.get_enum_attribute(AttributeLoc::Return, 1), None);
374 /// ```
375 pub fn remove_enum_attribute(self, loc: AttributeLoc, kind_id: u32) {
376 use llvm_sys::core::LLVMRemoveCallSiteEnumAttribute;
377
378 unsafe { LLVMRemoveCallSiteEnumAttribute(self.as_value_ref(), loc.get_index(), kind_id) }
379 }
380
381 /// Removes a string `Attribute` on this `CallSiteValue` at an index and key.
382 ///
383 /// # Example
384 ///
385 /// ```no_run
386 /// use inkwell::attributes::AttributeLoc;
387 /// use inkwell::context::Context;
388 ///
389 /// let context = Context::create();
390 /// let builder = context.create_builder();
391 /// let module = context.create_module("my_mod");
392 /// let void_type = context.void_type();
393 /// let fn_type = void_type.fn_type(&[], false);
394 /// let fn_value = module.add_function("my_fn", fn_type, None);
395 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
396 /// let enum_attribute = context.create_enum_attribute(1, 1);
397 /// let entry_bb = context.append_basic_block(fn_value, "entry");
398 ///
399 /// builder.position_at_end(entry_bb);
400 ///
401 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
402 ///
403 /// call_site_value.add_attribute(AttributeLoc::Return, string_attribute);
404 /// call_site_value.add_attribute(AttributeLoc::Return, enum_attribute);
405 /// call_site_value.remove_string_attribute(AttributeLoc::Return, "my_key");
406 ///
407 /// assert_eq!(call_site_value.get_string_attribute(AttributeLoc::Return, "my_key"), None);
408 /// ```
409 pub fn remove_string_attribute(self, loc: AttributeLoc, key: &str) {
410 use llvm_sys::core::LLVMRemoveCallSiteStringAttribute;
411
412 unsafe {
413 LLVMRemoveCallSiteStringAttribute(
414 self.as_value_ref(),
415 loc.get_index(),
416 key.as_ptr() as *const ::libc::c_char,
417 key.len() as u32,
418 )
419 }
420 }
421
422 /// Counts the number of arguments this `CallSiteValue` was called with.
423 ///
424 /// # Example
425 ///
426 /// ```no_run
427 /// use inkwell::attributes::AttributeLoc;
428 /// use inkwell::context::Context;
429 ///
430 /// let context = Context::create();
431 /// let builder = context.create_builder();
432 /// let module = context.create_module("my_mod");
433 /// let void_type = context.void_type();
434 /// let fn_type = void_type.fn_type(&[], false);
435 /// let fn_value = module.add_function("my_fn", fn_type, None);
436 /// let string_attribute = context.create_string_attribute("my_key", "my_val");
437 /// let enum_attribute = context.create_enum_attribute(1, 1);
438 /// let entry_bb = context.append_basic_block(fn_value, "entry");
439 ///
440 /// builder.position_at_end(entry_bb);
441 ///
442 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
443 ///
444 /// assert_eq!(call_site_value.count_arguments(), 0);
445 /// ```
446 pub fn count_arguments(self) -> u32 {
447 use llvm_sys::core::LLVMGetNumArgOperands;
448
449 unsafe { LLVMGetNumArgOperands(self.as_value_ref()) }
450 }
451
452 /// Gets the calling convention for this `CallSiteValue`.
453 ///
454 /// # Example
455 ///
456 /// ```no_run
457 /// use inkwell::context::Context;
458 ///
459 /// let context = Context::create();
460 /// let builder = context.create_builder();
461 /// let module = context.create_module("my_mod");
462 /// let void_type = context.void_type();
463 /// let fn_type = void_type.fn_type(&[], false);
464 /// let fn_value = module.add_function("my_fn", fn_type, None);
465 /// let entry_bb = context.append_basic_block(fn_value, "entry");
466 ///
467 /// builder.position_at_end(entry_bb);
468 ///
469 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
470 ///
471 /// assert_eq!(call_site_value.get_call_convention(), 0);
472 /// ```
473 pub fn get_call_convention(self) -> u32 {
474 unsafe { LLVMGetInstructionCallConv(self.as_value_ref()) }
475 }
476
477 /// Sets the calling convention for this `CallSiteValue`.
478 ///
479 /// # Example
480 ///
481 /// ```no_run
482 /// use inkwell::context::Context;
483 ///
484 /// let context = Context::create();
485 /// let builder = context.create_builder();
486 /// let module = context.create_module("my_mod");
487 /// let void_type = context.void_type();
488 /// let fn_type = void_type.fn_type(&[], false);
489 /// let fn_value = module.add_function("my_fn", fn_type, None);
490 /// let entry_bb = context.append_basic_block(fn_value, "entry");
491 ///
492 /// builder.position_at_end(entry_bb);
493 ///
494 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
495 ///
496 /// call_site_value.set_call_convention(2);
497 ///
498 /// assert_eq!(call_site_value.get_call_convention(), 2);
499 /// ```
500 pub fn set_call_convention(self, conv: u32) {
501 unsafe { LLVMSetInstructionCallConv(self.as_value_ref(), conv) }
502 }
503
504 /// Shortcut for setting the alignment `Attribute` for this `CallSiteValue`.
505 ///
506 /// # Panics
507 ///
508 /// When the alignment is not a power of 2.
509 ///
510 /// # Example
511 ///
512 /// ```no_run
513 /// use inkwell::attributes::AttributeLoc;
514 /// use inkwell::context::Context;
515 ///
516 /// let context = Context::create();
517 /// let builder = context.create_builder();
518 /// let module = context.create_module("my_mod");
519 /// let void_type = context.void_type();
520 /// let fn_type = void_type.fn_type(&[], false);
521 /// let fn_value = module.add_function("my_fn", fn_type, None);
522 /// let entry_bb = context.append_basic_block(fn_value, "entry");
523 ///
524 /// builder.position_at_end(entry_bb);
525 ///
526 /// let call_site_value = builder.build_call(fn_value, &[], "my_fn");
527 ///
528 /// call_site_value.set_alignment_attribute(AttributeLoc::Param(0), 2);
529 /// ```
530 pub fn set_alignment_attribute(self, loc: AttributeLoc, alignment: u32) {
531 assert_eq!(alignment.count_ones(), 1, "Alignment must be a power of two.");
532
533 unsafe { LLVMSetInstrParamAlignment(self.as_value_ref(), loc.get_index(), alignment) }
534 }
535}
536
537unsafe impl AsValueRef for CallSiteValue<'_> {
538 fn as_value_ref(&self) -> LLVMValueRef {
539 self.0.value
540 }
541}
542
543impl Display for CallSiteValue<'_> {
544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
545 write!(f, "{}", self.print_to_string())
546 }
547}