Skip to main content

inkwell/values/
fn_value.rs

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