1use llvm_sys::LLVMValue;
2use llvm_sys::analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction, LLVMViewFunctionCFG, LLVMViewFunctionCFGOnly};
3use llvm_sys::core::LLVMAppendExistingBasicBlock;
4use llvm_sys::core::{
5 LLVMAddAttributeAtIndex, LLVMGetAttributeCountAtIndex, LLVMGetEnumAttributeAtIndex, LLVMGetStringAttributeAtIndex,
6 LLVMRemoveEnumAttributeAtIndex, LLVMRemoveStringAttributeAtIndex,
7};
8use llvm_sys::core::{
9 LLVMCountBasicBlocks, LLVMCountParams, LLVMDeleteFunction, LLVMGetBasicBlocks, LLVMGetFirstBasicBlock,
10 LLVMGetFirstParam, LLVMGetFunctionCallConv, LLVMGetGC, LLVMGetIntrinsicID, LLVMGetLastBasicBlock, LLVMGetLastParam,
11 LLVMGetLinkage, LLVMGetNextFunction, LLVMGetNextParam, LLVMGetParam, LLVMGetParams, LLVMGetPreviousFunction,
12 LLVMIsAFunction, LLVMIsConstant, LLVMSetFunctionCallConv, LLVMSetGC, LLVMSetLinkage, LLVMSetParamAlignment,
13};
14use llvm_sys::core::{LLVMGetPersonalityFn, LLVMSetPersonalityFn};
15use llvm_sys::debuginfo::{LLVMGetSubprogram, LLVMSetSubprogram};
16#[llvm_versions(20..)]
17use llvm_sys::error::LLVMGetErrorMessage;
18use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef};
19#[llvm_versions(20..)]
20use llvm_sys::transforms::pass_builder::LLVMRunPassesOnFunction;
21
22use std::ffi::CStr;
23use std::fmt::{self, Display};
24use std::marker::PhantomData;
25use std::mem::forget;
26use std::ptr::NonNull;
27
28use crate::attributes::{Attribute, AttributeLoc};
29use crate::basic_block::BasicBlock;
30use crate::debug_info::DISubprogram;
31use crate::module::Linkage;
32#[llvm_versions(20..)]
33use crate::passes::PassBuilderOptions;
34#[llvm_versions(20..)]
35use crate::support::LLVMString;
36use crate::support::{assert_niche, to_c_str};
37#[llvm_versions(20..)]
38use crate::targets::TargetMachine;
39use crate::types::FunctionType;
40use crate::values::traits::{AnyValue, AsValueRef};
41use crate::values::{BasicValueEnum, GlobalValue, Value};
42
43#[repr(transparent)]
44#[derive(PartialEq, Eq, Clone, Copy, Hash)]
45pub struct FunctionValue<'ctx> {
46 fn_value: Value<'ctx>,
47}
48const _: () = assert_niche::<FunctionValue>();
49
50impl<'ctx> FunctionValue<'ctx> {
51 pub unsafe fn new(value: LLVMValueRef) -> Option<Self> {
57 unsafe {
58 if value.is_null() || LLVMIsAFunction(value).is_null() {
59 return None;
60 }
61
62 Some(FunctionValue {
63 fn_value: Value::new(value),
64 })
65 }
66 }
67
68 pub fn get_linkage(self) -> Linkage {
69 unsafe { LLVMGetLinkage(self.as_value_ref()).into() }
70 }
71
72 pub fn set_linkage(self, linkage: Linkage) {
73 unsafe { LLVMSetLinkage(self.as_value_ref(), linkage.into()) }
74 }
75
76 pub fn is_null(self) -> bool {
77 self.fn_value.is_null()
78 }
79
80 pub fn is_undef(self) -> bool {
81 self.fn_value.is_undef()
82 }
83
84 pub fn print_to_stderr(self) {
85 self.fn_value.print_to_stderr()
86 }
87
88 pub fn verify(self, print: bool) -> bool {
90 let action = if print {
91 LLVMVerifierFailureAction::LLVMPrintMessageAction
92 } else {
93 LLVMVerifierFailureAction::LLVMReturnStatusAction
94 };
95
96 let code = unsafe { LLVMVerifyFunction(self.fn_value.as_mut_ptr(), action) };
97
98 code != 1
99 }
100
101 pub fn get_next_function(self) -> Option<Self> {
103 unsafe { FunctionValue::new(LLVMGetNextFunction(self.as_value_ref())) }
104 }
105
106 pub fn get_previous_function(self) -> Option<Self> {
107 unsafe { FunctionValue::new(LLVMGetPreviousFunction(self.as_value_ref())) }
108 }
109
110 pub fn get_first_param(self) -> Option<BasicValueEnum<'ctx>> {
111 let param = unsafe { LLVMGetFirstParam(self.as_value_ref()) };
112
113 if param.is_null() {
114 return None;
115 }
116
117 unsafe { Some(BasicValueEnum::new(param)) }
118 }
119
120 pub fn get_last_param(self) -> Option<BasicValueEnum<'ctx>> {
121 let param = unsafe { LLVMGetLastParam(self.as_value_ref()) };
122
123 if param.is_null() {
124 return None;
125 }
126
127 unsafe { Some(BasicValueEnum::new(param)) }
128 }
129
130 pub fn get_first_basic_block(self) -> Option<BasicBlock<'ctx>> {
131 unsafe { BasicBlock::new(LLVMGetFirstBasicBlock(self.as_value_ref())) }
132 }
133
134 pub fn get_nth_param(self, nth: u32) -> Option<BasicValueEnum<'ctx>> {
135 let count = self.count_params();
136
137 if nth + 1 > count {
138 return None;
139 }
140
141 unsafe { Some(BasicValueEnum::new(LLVMGetParam(self.as_value_ref(), nth))) }
142 }
143
144 pub fn count_params(self) -> u32 {
145 unsafe { LLVMCountParams(self.fn_value.as_mut_ptr()) }
146 }
147
148 pub fn count_basic_blocks(self) -> u32 {
149 unsafe { LLVMCountBasicBlocks(self.as_value_ref()) }
150 }
151
152 pub fn get_basic_block_iter(self) -> BasicBlockIter<'ctx> {
153 BasicBlockIter(self.get_first_basic_block())
154 }
155
156 pub fn get_basic_blocks(self) -> Vec<BasicBlock<'ctx>> {
157 let count = self.count_basic_blocks();
158 let mut raw_vec: Vec<LLVMBasicBlockRef> = Vec::with_capacity(count as usize);
159 let ptr = raw_vec.as_mut_ptr();
160
161 forget(raw_vec);
162
163 let raw_vec = unsafe {
164 LLVMGetBasicBlocks(self.as_value_ref(), ptr);
165
166 Vec::from_raw_parts(ptr, count as usize, count as usize)
167 };
168
169 raw_vec
170 .iter()
171 .map(|val| unsafe { BasicBlock::new(*val).unwrap() })
172 .collect()
173 }
174
175 pub fn get_param_iter(self) -> ParamValueIter<'ctx> {
176 ParamValueIter {
177 param_iter_value: self.fn_value.value,
178 start: true,
179 _marker: PhantomData,
180 }
181 }
182
183 pub fn get_params(self) -> Vec<BasicValueEnum<'ctx>> {
184 let count = self.count_params();
185 let mut raw_vec: Vec<LLVMValueRef> = Vec::with_capacity(count as usize);
186 let ptr = raw_vec.as_mut_ptr();
187
188 forget(raw_vec);
189
190 let raw_vec = unsafe {
191 LLVMGetParams(self.as_value_ref(), ptr);
192
193 Vec::from_raw_parts(ptr, count as usize, count as usize)
194 };
195
196 raw_vec.iter().map(|val| unsafe { BasicValueEnum::new(*val) }).collect()
197 }
198
199 pub fn get_last_basic_block(self) -> Option<BasicBlock<'ctx>> {
200 unsafe { BasicBlock::new(LLVMGetLastBasicBlock(self.fn_value.as_mut_ptr())) }
201 }
202
203 pub fn get_name(&self) -> &CStr {
205 self.fn_value.get_name()
206 }
207
208 pub fn view_function_cfg(self) {
210 unsafe { LLVMViewFunctionCFG(self.as_value_ref()) }
211 }
212
213 pub fn view_function_cfg_only(self) {
215 unsafe { LLVMViewFunctionCFGOnly(self.as_value_ref()) }
216 }
217
218 pub unsafe fn delete(self) {
220 unsafe { LLVMDeleteFunction(self.as_value_ref()) }
221 }
222
223 pub fn get_type(self) -> FunctionType<'ctx> {
224 unsafe { FunctionType::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) }
225 }
226
227 pub fn has_personality_function(self) -> bool {
229 use llvm_sys::core::LLVMHasPersonalityFn;
230
231 unsafe { LLVMHasPersonalityFn(self.as_value_ref()) == 1 }
232 }
233
234 pub fn get_personality_function(self) -> Option<FunctionValue<'ctx>> {
235 if !self.has_personality_function() {
237 return None;
238 }
239
240 unsafe { FunctionValue::new(LLVMGetPersonalityFn(self.as_value_ref())) }
241 }
242
243 pub fn set_personality_function(self, personality_fn: FunctionValue<'ctx>) {
244 unsafe { LLVMSetPersonalityFn(self.as_value_ref(), personality_fn.as_value_ref()) }
245 }
246
247 pub fn get_intrinsic_id(self) -> u32 {
248 unsafe { LLVMGetIntrinsicID(self.as_value_ref()) }
249 }
250
251 pub fn get_call_conventions(self) -> u32 {
252 unsafe { LLVMGetFunctionCallConv(self.as_value_ref()) }
253 }
254
255 pub fn set_call_conventions(self, call_conventions: u32) {
256 unsafe { LLVMSetFunctionCallConv(self.as_value_ref(), call_conventions) }
257 }
258
259 pub fn get_gc(&self) -> &CStr {
260 unsafe { CStr::from_ptr(LLVMGetGC(self.as_value_ref())) }
261 }
262
263 pub fn set_gc(self, gc: &str) {
264 let c_string = to_c_str(gc);
265
266 unsafe { LLVMSetGC(self.as_value_ref(), c_string.as_ptr()) }
267 }
268
269 pub fn replace_all_uses_with(self, other: FunctionValue<'ctx>) {
270 self.fn_value.replace_all_uses_with(other.as_value_ref())
271 }
272
273 pub fn add_attribute(self, loc: AttributeLoc, attribute: Attribute) {
293 unsafe { LLVMAddAttributeAtIndex(self.as_value_ref(), loc.get_index(), attribute.as_mut_ptr()) }
294 }
295
296 pub fn count_attributes(self, loc: AttributeLoc) -> u32 {
318 unsafe { LLVMGetAttributeCountAtIndex(self.as_value_ref(), loc.get_index()) }
319 }
320
321 pub fn attributes(self, loc: AttributeLoc) -> Vec<Attribute> {
343 use llvm_sys::core::LLVMGetAttributesAtIndex;
344 use std::mem::{ManuallyDrop, MaybeUninit};
345
346 let count = self.count_attributes(loc) as usize;
347
348 let mut attribute_refs: Vec<MaybeUninit<Attribute>> = vec![MaybeUninit::uninit(); count];
350
351 unsafe {
353 LLVMGetAttributesAtIndex(
354 self.as_value_ref(),
355 loc.get_index(),
356 attribute_refs.as_mut_ptr() as *mut _,
357 )
358 }
359
360 unsafe {
362 let mut attribute_refs = ManuallyDrop::new(attribute_refs);
364
365 Vec::from_raw_parts(
366 attribute_refs.as_mut_ptr() as *mut Attribute,
367 attribute_refs.len(),
368 attribute_refs.capacity(),
369 )
370 }
371 }
372
373 pub fn remove_string_attribute(self, loc: AttributeLoc, key: &str) {
392 unsafe {
393 LLVMRemoveStringAttributeAtIndex(
394 self.as_value_ref(),
395 loc.get_index(),
396 key.as_ptr() as *const ::libc::c_char,
397 key.len() as u32,
398 )
399 }
400 }
401
402 pub fn remove_enum_attribute(self, loc: AttributeLoc, kind_id: u32) {
421 unsafe { LLVMRemoveEnumAttributeAtIndex(self.as_value_ref(), loc.get_index(), kind_id) }
422 }
423
424 pub fn get_enum_attribute(self, loc: AttributeLoc, kind_id: u32) -> Option<Attribute> {
445 let ptr = unsafe { LLVMGetEnumAttributeAtIndex(self.as_value_ref(), loc.get_index(), kind_id) };
446
447 if ptr.is_null() {
448 return None;
449 }
450
451 unsafe { Some(Attribute::new(ptr)) }
452 }
453
454 pub fn get_string_attribute(self, loc: AttributeLoc, key: &str) -> Option<Attribute> {
475 let ptr = unsafe {
476 LLVMGetStringAttributeAtIndex(
477 self.as_value_ref(),
478 loc.get_index(),
479 key.as_ptr() as *const ::libc::c_char,
480 key.len() as u32,
481 )
482 };
483
484 if ptr.is_null() {
485 return None;
486 }
487
488 unsafe { Some(Attribute::new(ptr)) }
489 }
490
491 pub fn set_param_alignment(self, param_index: u32, alignment: u32) {
492 if let Some(param) = self.get_nth_param(param_index) {
493 unsafe { LLVMSetParamAlignment(param.as_value_ref(), alignment) }
494 }
495 }
496
497 pub fn as_global_value(self) -> GlobalValue<'ctx> {
501 unsafe { GlobalValue::new(self.as_value_ref()) }
502 }
503
504 pub fn set_subprogram(self, subprogram: DISubprogram<'ctx>) {
506 unsafe { LLVMSetSubprogram(self.as_value_ref(), subprogram.as_mut_ptr()) }
507 }
508
509 pub fn get_subprogram(self) -> Option<DISubprogram<'ctx>> {
511 let metadata_ref = unsafe { LLVMGetSubprogram(self.as_value_ref()) };
512
513 Some(DISubprogram {
514 metadata_ref: NonNull::new(metadata_ref)?,
515 _marker: PhantomData,
516 })
517 }
518
519 pub fn get_section(&self) -> Option<&CStr> {
521 self.fn_value.get_section()
522 }
523
524 pub fn set_section(self, section: Option<&str>) {
526 self.fn_value.set_section(section)
527 }
528
529 pub fn append_existing_basic_block(&self, basic_block: BasicBlock<'ctx>) {
530 unsafe {
531 LLVMAppendExistingBasicBlock(self.as_value_ref(), basic_block.as_mut_ptr());
532 }
533 }
534
535 #[llvm_versions(20..)]
543 pub fn run_passes(
544 &self,
545 passes: &str,
546 machine: &TargetMachine,
547 options: PassBuilderOptions,
548 ) -> Result<(), LLVMString> {
549 unsafe {
550 let error = LLVMRunPassesOnFunction(
551 self.as_value_ref(),
552 to_c_str(passes).as_ptr(),
553 machine.target_machine.as_ptr(),
554 options.options_ref,
555 );
556 if error.is_null() {
557 Ok(())
558 } else {
559 let message = LLVMGetErrorMessage(error);
560 Err(LLVMString::new(message as *const libc::c_char))
561 }
562 }
563 }
564}
565
566unsafe impl AsValueRef for FunctionValue<'_> {
567 fn as_value_ref(&self) -> LLVMValueRef {
568 self.fn_value.as_mut_ptr()
569 }
570}
571
572impl Display for FunctionValue<'_> {
573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
574 write!(f, "{}", self.print_to_string())
575 }
576}
577
578impl fmt::Debug for FunctionValue<'_> {
579 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
580 let llvm_value = self.print_to_string();
581 let llvm_type = self.get_type();
582 let name = self.get_name();
583 let is_const = unsafe { LLVMIsConstant(self.fn_value.as_mut_ptr()) == 1 };
584 let is_null = self.is_null();
585
586 f.debug_struct("FunctionValue")
587 .field("name", &name)
588 .field("address", &self.as_value_ref())
589 .field("is_const", &is_const)
590 .field("is_null", &is_null)
591 .field("llvm_value", &llvm_value)
592 .field("llvm_type", &llvm_type.print_to_string())
593 .finish()
594 }
595}
596
597#[repr(transparent)]
599#[derive(Debug)]
600pub struct BasicBlockIter<'ctx>(Option<BasicBlock<'ctx>>);
601
602impl<'ctx> Iterator for BasicBlockIter<'ctx> {
603 type Item = BasicBlock<'ctx>;
604
605 fn next(&mut self) -> Option<Self::Item> {
606 if let Some(bb) = self.0 {
607 self.0 = bb.get_next_basic_block();
608 Some(bb)
609 } else {
610 None
611 }
612 }
613}
614
615#[derive(Debug)]
616pub struct ParamValueIter<'ctx> {
617 param_iter_value: NonNull<LLVMValue>,
618 start: bool,
619 _marker: PhantomData<&'ctx ()>,
620}
621const _: () = assert_niche::<ParamValueIter>();
622
623impl<'ctx> Iterator for ParamValueIter<'ctx> {
624 type Item = BasicValueEnum<'ctx>;
625
626 fn next(&mut self) -> Option<Self::Item> {
627 if self.start {
628 let first_value = unsafe { LLVMGetFirstParam(self.param_iter_value.as_ptr()) };
629
630 if first_value.is_null() {
631 return None;
632 }
633
634 self.start = false;
635
636 self.param_iter_value = unsafe { NonNull::new_unchecked(first_value) };
637
638 return unsafe { Some(Self::Item::new(first_value)) };
639 }
640
641 let next_value = unsafe { LLVMGetNextParam(self.param_iter_value.as_ptr()) };
642
643 if next_value.is_null() {
644 return None;
645 }
646
647 self.param_iter_value = unsafe { NonNull::new_unchecked(next_value) };
648
649 unsafe { Some(Self::Item::new(next_value)) }
650 }
651}