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}