inkwell/values/
fn_value.rs

1use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction, LLVMViewFunctionCFG, LLVMViewFunctionCFGOnly};
2use llvm_sys::core::{
3    LLVMAddAttributeAtIndex, LLVMGetAttributeCountAtIndex, LLVMGetEnumAttributeAtIndex, LLVMGetStringAttributeAtIndex,
4    LLVMRemoveEnumAttributeAtIndex, LLVMRemoveStringAttributeAtIndex,
5};
6use llvm_sys::core::{
7    LLVMCountBasicBlocks, LLVMCountParams, LLVMDeleteFunction, LLVMGetBasicBlocks, LLVMGetFirstBasicBlock,
8    LLVMGetFirstParam, LLVMGetFunctionCallConv, LLVMGetGC, LLVMGetIntrinsicID, LLVMGetLastBasicBlock, LLVMGetLastParam,
9    LLVMGetLinkage, LLVMGetNextFunction, LLVMGetNextParam, LLVMGetParam, LLVMGetParams, LLVMGetPreviousFunction,
10    LLVMIsAFunction, LLVMIsConstant, LLVMSetFunctionCallConv, LLVMSetGC, LLVMSetLinkage, LLVMSetParamAlignment,
11};
12use llvm_sys::core::{LLVMGetPersonalityFn, LLVMSetPersonalityFn};
13#[llvm_versions(7..)]
14use llvm_sys::debuginfo::{LLVMGetSubprogram, LLVMSetSubprogram};
15use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
16
17use std::ffi::CStr;
18use std::fmt::{self, Display};
19use std::marker::PhantomData;
20use std::mem::forget;
21
22use crate::attributes::{Attribute, AttributeLoc};
23use crate::basic_block::BasicBlock;
24#[llvm_versions(7..)]
25use crate::debug_info::DISubprogram;
26use crate::module::Linkage;
27use crate::support::to_c_str;
28use crate::types::FunctionType;
29use crate::values::traits::{AnyValue, AsValueRef};
30use crate::values::{BasicValueEnum, GlobalValue, Value};
31
32#[derive(PartialEq, Eq, Clone, Copy, Hash)]
33pub struct FunctionValue<'ctx> {
34    fn_value: Value<'ctx>,
35}
36
37impl<'ctx> FunctionValue<'ctx> {
38    /// Get a value from an [LLVMValueRef].
39    ///
40    /// # Safety
41    ///
42    /// The ref must be valid and of type function.
43    pub unsafe fn new(value: LLVMValueRef) -> Option<Self> {
44        if value.is_null() || LLVMIsAFunction(value).is_null() {
45            return None;
46        }
47
48        Some(FunctionValue {
49            fn_value: Value::new(value),
50        })
51    }
52
53    pub fn get_linkage(self) -> Linkage {
54        unsafe { LLVMGetLinkage(self.as_value_ref()).into() }
55    }
56
57    pub fn set_linkage(self, linkage: Linkage) {
58        unsafe { LLVMSetLinkage(self.as_value_ref(), linkage.into()) }
59    }
60
61    pub fn is_null(self) -> bool {
62        self.fn_value.is_null()
63    }
64
65    pub fn is_undef(self) -> bool {
66        self.fn_value.is_undef()
67    }
68
69    pub fn print_to_stderr(self) {
70        self.fn_value.print_to_stderr()
71    }
72
73    // FIXME: Better error returns, code 1 is error
74    pub fn verify(self, print: bool) -> bool {
75        let action = if print {
76            LLVMVerifierFailureAction::LLVMPrintMessageAction
77        } else {
78            LLVMVerifierFailureAction::LLVMReturnStatusAction
79        };
80
81        let code = unsafe { LLVMVerifyFunction(self.fn_value.value, action) };
82
83        code != 1
84    }
85
86    // REVIEW: If there's a demand, could easily create a module.get_functions() -> Iterator
87    pub fn get_next_function(self) -> Option<Self> {
88        unsafe { FunctionValue::new(LLVMGetNextFunction(self.as_value_ref())) }
89    }
90
91    pub fn get_previous_function(self) -> Option<Self> {
92        unsafe { FunctionValue::new(LLVMGetPreviousFunction(self.as_value_ref())) }
93    }
94
95    pub fn get_first_param(self) -> Option<BasicValueEnum<'ctx>> {
96        let param = unsafe { LLVMGetFirstParam(self.as_value_ref()) };
97
98        if param.is_null() {
99            return None;
100        }
101
102        unsafe { Some(BasicValueEnum::new(param)) }
103    }
104
105    pub fn get_last_param(self) -> Option<BasicValueEnum<'ctx>> {
106        let param = unsafe { LLVMGetLastParam(self.as_value_ref()) };
107
108        if param.is_null() {
109            return None;
110        }
111
112        unsafe { Some(BasicValueEnum::new(param)) }
113    }
114
115    pub fn get_first_basic_block(self) -> Option<BasicBlock<'ctx>> {
116        unsafe { BasicBlock::new(LLVMGetFirstBasicBlock(self.as_value_ref())) }
117    }
118
119    pub fn get_nth_param(self, nth: u32) -> Option<BasicValueEnum<'ctx>> {
120        let count = self.count_params();
121
122        if nth + 1 > count {
123            return None;
124        }
125
126        unsafe { Some(BasicValueEnum::new(LLVMGetParam(self.as_value_ref(), nth))) }
127    }
128
129    pub fn count_params(self) -> u32 {
130        unsafe { LLVMCountParams(self.fn_value.value) }
131    }
132
133    pub fn count_basic_blocks(self) -> u32 {
134        unsafe { LLVMCountBasicBlocks(self.as_value_ref()) }
135    }
136
137    pub fn get_basic_block_iter(self) -> BasicBlockIter<'ctx> {
138        BasicBlockIter(self.get_first_basic_block())
139    }
140
141    pub fn get_basic_blocks(self) -> Vec<BasicBlock<'ctx>> {
142        let count = self.count_basic_blocks();
143        let mut raw_vec: Vec<LLVMBasicBlockRef> = Vec::with_capacity(count as usize);
144        let ptr = raw_vec.as_mut_ptr();
145
146        forget(raw_vec);
147
148        let raw_vec = unsafe {
149            LLVMGetBasicBlocks(self.as_value_ref(), ptr);
150
151            Vec::from_raw_parts(ptr, count as usize, count as usize)
152        };
153
154        raw_vec
155            .iter()
156            .map(|val| unsafe { BasicBlock::new(*val).unwrap() })
157            .collect()
158    }
159
160    pub fn get_param_iter(self) -> ParamValueIter<'ctx> {
161        ParamValueIter {
162            param_iter_value: self.fn_value.value,
163            start: true,
164            _marker: PhantomData,
165        }
166    }
167
168    pub fn get_params(self) -> Vec<BasicValueEnum<'ctx>> {
169        let count = self.count_params();
170        let mut raw_vec: Vec<LLVMValueRef> = Vec::with_capacity(count as usize);
171        let ptr = raw_vec.as_mut_ptr();
172
173        forget(raw_vec);
174
175        let raw_vec = unsafe {
176            LLVMGetParams(self.as_value_ref(), ptr);
177
178            Vec::from_raw_parts(ptr, count as usize, count as usize)
179        };
180
181        raw_vec.iter().map(|val| unsafe { BasicValueEnum::new(*val) }).collect()
182    }
183
184    pub fn get_last_basic_block(self) -> Option<BasicBlock<'ctx>> {
185        unsafe { BasicBlock::new(LLVMGetLastBasicBlock(self.fn_value.value)) }
186    }
187
188    /// Gets the name of a `FunctionValue`.
189    pub fn get_name(&self) -> &CStr {
190        self.fn_value.get_name()
191    }
192
193    /// View the control flow graph and produce a .dot file
194    pub fn view_function_cfg(self) {
195        unsafe { LLVMViewFunctionCFG(self.as_value_ref()) }
196    }
197
198    /// Only view the control flow graph
199    pub fn view_function_cfg_only(self) {
200        unsafe { LLVMViewFunctionCFGOnly(self.as_value_ref()) }
201    }
202
203    // TODO: Look for ways to prevent use after delete but maybe not possible
204    pub unsafe fn delete(self) {
205        LLVMDeleteFunction(self.as_value_ref())
206    }
207
208    #[llvm_versions(..=7)]
209    pub fn get_type(self) -> FunctionType<'ctx> {
210        use crate::types::PointerType;
211
212        let ptr_type = unsafe { PointerType::new(self.fn_value.get_type()) };
213
214        ptr_type.get_element_type().into_function_type()
215    }
216
217    #[llvm_versions(8..)]
218    pub fn get_type(self) -> FunctionType<'ctx> {
219        unsafe { FunctionType::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) }
220    }
221
222    // TODOC: How this works as an exception handler
223    pub fn has_personality_function(self) -> bool {
224        use llvm_sys::core::LLVMHasPersonalityFn;
225
226        unsafe { LLVMHasPersonalityFn(self.as_value_ref()) == 1 }
227    }
228
229    pub fn get_personality_function(self) -> Option<FunctionValue<'ctx>> {
230        // This prevents a segfault when not having a pfn
231        if !self.has_personality_function() {
232            return None;
233        }
234
235        unsafe { FunctionValue::new(LLVMGetPersonalityFn(self.as_value_ref())) }
236    }
237
238    pub fn set_personality_function(self, personality_fn: FunctionValue<'ctx>) {
239        unsafe { LLVMSetPersonalityFn(self.as_value_ref(), personality_fn.as_value_ref()) }
240    }
241
242    pub fn get_intrinsic_id(self) -> u32 {
243        unsafe { LLVMGetIntrinsicID(self.as_value_ref()) }
244    }
245
246    pub fn get_call_conventions(self) -> u32 {
247        unsafe { LLVMGetFunctionCallConv(self.as_value_ref()) }
248    }
249
250    pub fn set_call_conventions(self, call_conventions: u32) {
251        unsafe { LLVMSetFunctionCallConv(self.as_value_ref(), call_conventions) }
252    }
253
254    pub fn get_gc(&self) -> &CStr {
255        unsafe { CStr::from_ptr(LLVMGetGC(self.as_value_ref())) }
256    }
257
258    pub fn set_gc(self, gc: &str) {
259        let c_string = to_c_str(gc);
260
261        unsafe { LLVMSetGC(self.as_value_ref(), c_string.as_ptr()) }
262    }
263
264    pub fn replace_all_uses_with(self, other: FunctionValue<'ctx>) {
265        self.fn_value.replace_all_uses_with(other.as_value_ref())
266    }
267
268    /// Adds an `Attribute` to a particular location in this `FunctionValue`.
269    ///
270    /// # Example
271    ///
272    /// ```no_run
273    /// use inkwell::attributes::AttributeLoc;
274    /// use inkwell::context::Context;
275    ///
276    /// let context = Context::create();
277    /// let module = context.create_module("my_mod");
278    /// let void_type = context.void_type();
279    /// let fn_type = void_type.fn_type(&[], false);
280    /// let fn_value = module.add_function("my_fn", fn_type, None);
281    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
282    /// let enum_attribute = context.create_enum_attribute(1, 1);
283    ///
284    /// fn_value.add_attribute(AttributeLoc::Return, string_attribute);
285    /// fn_value.add_attribute(AttributeLoc::Return, enum_attribute);
286    /// ```
287    pub fn add_attribute(self, loc: AttributeLoc, attribute: Attribute) {
288        unsafe { LLVMAddAttributeAtIndex(self.as_value_ref(), loc.get_index(), attribute.attribute) }
289    }
290
291    /// Counts the number of `Attribute`s belonging to the specified location in this `FunctionValue`.
292    ///
293    /// # Example
294    ///
295    /// ```no_run
296    /// use inkwell::attributes::AttributeLoc;
297    /// use inkwell::context::Context;
298    ///
299    /// let context = Context::create();
300    /// let module = context.create_module("my_mod");
301    /// let void_type = context.void_type();
302    /// let fn_type = void_type.fn_type(&[], false);
303    /// let fn_value = module.add_function("my_fn", fn_type, None);
304    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
305    /// let enum_attribute = context.create_enum_attribute(1, 1);
306    ///
307    /// fn_value.add_attribute(AttributeLoc::Return, string_attribute);
308    /// fn_value.add_attribute(AttributeLoc::Return, enum_attribute);
309    ///
310    /// assert_eq!(fn_value.count_attributes(AttributeLoc::Return), 2);
311    /// ```
312    pub fn count_attributes(self, loc: AttributeLoc) -> u32 {
313        unsafe { LLVMGetAttributeCountAtIndex(self.as_value_ref(), loc.get_index()) }
314    }
315
316    /// Get all `Attribute`s belonging to the specified location in this `FunctionValue`.
317    ///
318    /// # Example
319    ///
320    /// ```no_run
321    /// use inkwell::attributes::AttributeLoc;
322    /// use inkwell::context::Context;
323    ///
324    /// let context = Context::create();
325    /// let module = context.create_module("my_mod");
326    /// let void_type = context.void_type();
327    /// let fn_type = void_type.fn_type(&[], false);
328    /// let fn_value = module.add_function("my_fn", fn_type, None);
329    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
330    /// let enum_attribute = context.create_enum_attribute(1, 1);
331    ///
332    /// fn_value.add_attribute(AttributeLoc::Return, string_attribute);
333    /// fn_value.add_attribute(AttributeLoc::Return, enum_attribute);
334    ///
335    /// assert_eq!(fn_value.attributes(AttributeLoc::Return), vec![string_attribute, enum_attribute]);
336    /// ```
337    pub fn attributes(self, loc: AttributeLoc) -> Vec<Attribute> {
338        use llvm_sys::core::LLVMGetAttributesAtIndex;
339        use std::mem::{ManuallyDrop, MaybeUninit};
340
341        let count = self.count_attributes(loc) as usize;
342
343        // initialize a vector, but leave each element uninitialized
344        let mut attribute_refs: Vec<MaybeUninit<Attribute>> = vec![MaybeUninit::uninit(); count];
345
346        // Safety: relies on `Attribute` having the same in-memory representation as `LLVMAttributeRef`
347        unsafe {
348            LLVMGetAttributesAtIndex(
349                self.as_value_ref(),
350                loc.get_index(),
351                attribute_refs.as_mut_ptr() as *mut _,
352            )
353        }
354
355        // Safety: all elements are initialized
356        unsafe {
357            // ensure the vector is not dropped
358            let mut attribute_refs = ManuallyDrop::new(attribute_refs);
359
360            Vec::from_raw_parts(
361                attribute_refs.as_mut_ptr() as *mut Attribute,
362                attribute_refs.len(),
363                attribute_refs.capacity(),
364            )
365        }
366    }
367
368    /// Removes a string `Attribute` belonging to the specified location in this `FunctionValue`.
369    ///
370    /// # Example
371    ///
372    /// ```no_run
373    /// use inkwell::attributes::AttributeLoc;
374    /// use inkwell::context::Context;
375    ///
376    /// let context = Context::create();
377    /// let module = context.create_module("my_mod");
378    /// let void_type = context.void_type();
379    /// let fn_type = void_type.fn_type(&[], false);
380    /// let fn_value = module.add_function("my_fn", fn_type, None);
381    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
382    ///
383    /// fn_value.add_attribute(AttributeLoc::Return, string_attribute);
384    /// fn_value.remove_string_attribute(AttributeLoc::Return, "my_key");
385    /// ```
386    pub fn remove_string_attribute(self, loc: AttributeLoc, key: &str) {
387        unsafe {
388            LLVMRemoveStringAttributeAtIndex(
389                self.as_value_ref(),
390                loc.get_index(),
391                key.as_ptr() as *const ::libc::c_char,
392                key.len() as u32,
393            )
394        }
395    }
396
397    /// Removes an enum `Attribute` belonging to the specified location in this `FunctionValue`.
398    ///
399    /// # Example
400    ///
401    /// ```no_run
402    /// use inkwell::attributes::AttributeLoc;
403    /// use inkwell::context::Context;
404    ///
405    /// let context = Context::create();
406    /// let module = context.create_module("my_mod");
407    /// let void_type = context.void_type();
408    /// let fn_type = void_type.fn_type(&[], false);
409    /// let fn_value = module.add_function("my_fn", fn_type, None);
410    /// let enum_attribute = context.create_enum_attribute(1, 1);
411    ///
412    /// fn_value.add_attribute(AttributeLoc::Return, enum_attribute);
413    /// fn_value.remove_enum_attribute(AttributeLoc::Return, 1);
414    /// ```
415    pub fn remove_enum_attribute(self, loc: AttributeLoc, kind_id: u32) {
416        unsafe { LLVMRemoveEnumAttributeAtIndex(self.as_value_ref(), loc.get_index(), kind_id) }
417    }
418
419    /// Gets an enum `Attribute` belonging to the specified location in this `FunctionValue`.
420    ///
421    /// # Example
422    ///
423    /// ```no_run
424    /// use inkwell::attributes::AttributeLoc;
425    /// use inkwell::context::Context;
426    ///
427    /// let context = Context::create();
428    /// let module = context.create_module("my_mod");
429    /// let void_type = context.void_type();
430    /// let fn_type = void_type.fn_type(&[], false);
431    /// let fn_value = module.add_function("my_fn", fn_type, None);
432    /// let enum_attribute = context.create_enum_attribute(1, 1);
433    ///
434    /// fn_value.add_attribute(AttributeLoc::Return, enum_attribute);
435    ///
436    /// assert_eq!(fn_value.get_enum_attribute(AttributeLoc::Return, 1), Some(enum_attribute));
437    /// ```
438    // SubTypes: -> Option<Attribute<Enum>>
439    pub fn get_enum_attribute(self, loc: AttributeLoc, kind_id: u32) -> Option<Attribute> {
440        let ptr = unsafe { LLVMGetEnumAttributeAtIndex(self.as_value_ref(), loc.get_index(), kind_id) };
441
442        if ptr.is_null() {
443            return None;
444        }
445
446        unsafe { Some(Attribute::new(ptr)) }
447    }
448
449    /// Gets a string `Attribute` belonging to the specified location in this `FunctionValue`.
450    ///
451    /// # Example
452    ///
453    /// ```no_run
454    /// use inkwell::attributes::AttributeLoc;
455    /// use inkwell::context::Context;
456    ///
457    /// let context = Context::create();
458    /// let module = context.create_module("my_mod");
459    /// let void_type = context.void_type();
460    /// let fn_type = void_type.fn_type(&[], false);
461    /// let fn_value = module.add_function("my_fn", fn_type, None);
462    /// let string_attribute = context.create_string_attribute("my_key", "my_val");
463    ///
464    /// fn_value.add_attribute(AttributeLoc::Return, string_attribute);
465    ///
466    /// assert_eq!(fn_value.get_string_attribute(AttributeLoc::Return, "my_key"), Some(string_attribute));
467    /// ```
468    // SubTypes: -> Option<Attribute<String>>
469    pub fn get_string_attribute(self, loc: AttributeLoc, key: &str) -> Option<Attribute> {
470        let ptr = unsafe {
471            LLVMGetStringAttributeAtIndex(
472                self.as_value_ref(),
473                loc.get_index(),
474                key.as_ptr() as *const ::libc::c_char,
475                key.len() as u32,
476            )
477        };
478
479        if ptr.is_null() {
480            return None;
481        }
482
483        unsafe { Some(Attribute::new(ptr)) }
484    }
485
486    pub fn set_param_alignment(self, param_index: u32, alignment: u32) {
487        if let Some(param) = self.get_nth_param(param_index) {
488            unsafe { LLVMSetParamAlignment(param.as_value_ref(), alignment) }
489        }
490    }
491
492    /// Gets the `GlobalValue` version of this `FunctionValue`. This allows
493    /// you to further inspect its global properties or even convert it to
494    /// a `PointerValue`.
495    pub fn as_global_value(self) -> GlobalValue<'ctx> {
496        unsafe { GlobalValue::new(self.as_value_ref()) }
497    }
498
499    /// Set the debug info descriptor
500    #[llvm_versions(7..)]
501    pub fn set_subprogram(self, subprogram: DISubprogram<'ctx>) {
502        unsafe { LLVMSetSubprogram(self.as_value_ref(), subprogram.metadata_ref) }
503    }
504
505    /// Get the debug info descriptor
506    #[llvm_versions(7..)]
507    pub fn get_subprogram(self) -> Option<DISubprogram<'ctx>> {
508        let metadata_ref = unsafe { LLVMGetSubprogram(self.as_value_ref()) };
509
510        if metadata_ref.is_null() {
511            None
512        } else {
513            Some(DISubprogram {
514                metadata_ref,
515                _marker: PhantomData,
516            })
517        }
518    }
519
520    /// Get the section to which this function belongs
521    pub fn get_section(&self) -> Option<&CStr> {
522        self.fn_value.get_section()
523    }
524
525    /// Set the section to which this function should belong
526    pub fn set_section(self, section: Option<&str>) {
527        self.fn_value.set_section(section)
528    }
529}
530
531unsafe impl AsValueRef for FunctionValue<'_> {
532    fn as_value_ref(&self) -> LLVMValueRef {
533        self.fn_value.value
534    }
535}
536
537impl Display for FunctionValue<'_> {
538    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
539        write!(f, "{}", self.print_to_string())
540    }
541}
542
543impl fmt::Debug for FunctionValue<'_> {
544    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545        let llvm_value = self.print_to_string();
546        let llvm_type = self.get_type();
547        let name = self.get_name();
548        let is_const = unsafe { LLVMIsConstant(self.fn_value.value) == 1 };
549        let is_null = self.is_null();
550
551        f.debug_struct("FunctionValue")
552            .field("name", &name)
553            .field("address", &self.as_value_ref())
554            .field("is_const", &is_const)
555            .field("is_null", &is_null)
556            .field("llvm_value", &llvm_value)
557            .field("llvm_type", &llvm_type.print_to_string())
558            .finish()
559    }
560}
561
562/// Iterate over all `BasicBlock`s in a function.
563#[derive(Debug)]
564pub struct BasicBlockIter<'ctx>(Option<BasicBlock<'ctx>>);
565
566impl<'ctx> Iterator for BasicBlockIter<'ctx> {
567    type Item = BasicBlock<'ctx>;
568
569    fn next(&mut self) -> Option<Self::Item> {
570        if let Some(bb) = self.0 {
571            self.0 = bb.get_next_basic_block();
572            Some(bb)
573        } else {
574            None
575        }
576    }
577}
578
579#[derive(Debug)]
580pub struct ParamValueIter<'ctx> {
581    param_iter_value: LLVMValueRef,
582    start: bool,
583    _marker: PhantomData<&'ctx ()>,
584}
585
586impl<'ctx> Iterator for ParamValueIter<'ctx> {
587    type Item = BasicValueEnum<'ctx>;
588
589    fn next(&mut self) -> Option<Self::Item> {
590        if self.start {
591            let first_value = unsafe { LLVMGetFirstParam(self.param_iter_value) };
592
593            if first_value.is_null() {
594                return None;
595            }
596
597            self.start = false;
598
599            self.param_iter_value = first_value;
600
601            return unsafe { Some(Self::Item::new(first_value)) };
602        }
603
604        let next_value = unsafe { LLVMGetNextParam(self.param_iter_value) };
605
606        if next_value.is_null() {
607            return None;
608        }
609
610        self.param_iter_value = next_value;
611
612        unsafe { Some(Self::Item::new(next_value)) }
613    }
614}