1use crate::debugloc::{DebugLoc, HasDebugLoc};
2use crate::module::{Comdat, DLLStorageClass, Linkage, Visibility};
3use crate::types::{TypeRef, Typed, Types};
4use crate::{BasicBlock, ConstantRef, Name};
5
6#[derive(PartialEq, Clone, Debug, Hash)]
8pub struct Function {
9 pub name: String,
10 pub parameters: Vec<Parameter>,
11 pub is_var_arg: bool,
12 pub return_type: TypeRef,
13 pub basic_blocks: Vec<BasicBlock>,
14 pub function_attributes: Vec<FunctionAttribute>, pub return_attributes: Vec<ParameterAttribute>,
16 pub linkage: Linkage,
17 pub visibility: Visibility,
18 pub dll_storage_class: DLLStorageClass, pub calling_convention: CallingConvention,
20 pub section: Option<String>,
21 pub comdat: Option<Comdat>, pub alignment: u32,
23 pub garbage_collector_name: Option<String>,
25 pub personality_function: Option<ConstantRef>,
28 pub debugloc: Option<DebugLoc>,
29 }
31
32impl Typed for Function {
33 fn get_type(&self, types: &Types) -> TypeRef {
34 types.func_type(
35 self.return_type.clone(),
36 self.parameters.iter().map(|p| types.type_of(p)).collect(),
37 self.is_var_arg,
38 )
39 }
40}
41
42impl HasDebugLoc for Function {
43 fn get_debug_loc(&self) -> &Option<DebugLoc> {
44 &self.debugloc
45 }
46}
47
48impl Function {
49 pub fn get_bb_by_name(&self, name: &Name) -> Option<&BasicBlock> {
51 self.basic_blocks.iter().find(|bb| &bb.name == name)
52 }
53
54 pub fn new(name: impl Into<String>) -> Self {
56 Self {
57 name: name.into(),
58 parameters: vec![],
59 is_var_arg: false,
60 return_type: Types::blank_for_testing().void(),
61 basic_blocks: vec![],
62 function_attributes: vec![],
63 return_attributes: vec![],
64 linkage: Linkage::Private,
65 visibility: Visibility::Default,
66 dll_storage_class: DLLStorageClass::Default,
67 calling_convention: CallingConvention::C,
68 section: None,
69 comdat: None,
70 alignment: 4,
71 garbage_collector_name: None,
72 personality_function: None,
73 debugloc: None,
74 }
75 }
76}
77
78#[derive(PartialEq, Clone, Debug, Hash)]
80pub struct FunctionDeclaration {
81 pub name: String,
82 pub parameters: Vec<Parameter>,
83 pub is_var_arg: bool,
84 pub return_type: TypeRef,
85 pub return_attributes: Vec<ParameterAttribute>,
86 pub linkage: Linkage,
87 pub visibility: Visibility,
88 pub dll_storage_class: DLLStorageClass,
89 pub calling_convention: CallingConvention,
90 pub alignment: u32,
91 pub garbage_collector_name: Option<String>,
93 pub debugloc: Option<DebugLoc>,
94}
95
96#[derive(PartialEq, Clone, Debug, Hash)]
97pub struct Parameter {
98 pub name: Name,
99 pub ty: TypeRef,
100 pub attributes: Vec<ParameterAttribute>,
101}
102
103impl Typed for Parameter {
104 fn get_type(&self, _types: &Types) -> TypeRef {
105 self.ty.clone()
106 }
107}
108
109#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
111#[allow(non_camel_case_types)]
112pub enum CallingConvention {
113 C,
114 Fast,
115 Cold,
116 GHC,
117 HiPE,
118 WebKit_JS,
119 AnyReg,
120 PreserveMost,
121 PreserveAll,
122 Swift,
123 CXX_FastTLS,
124 X86_StdCall,
125 X86_FastCall,
126 X86_RegCall,
127 X86_ThisCall,
128 X86_VectorCall,
129 X86_Intr,
130 X86_64_SysV,
131 ARM_APCS,
132 ARM_AAPCS,
133 ARM_AAPCS_VFP,
134 MSP430_INTR,
135 MSP430_Builtin,
136 PTX_Kernel,
137 PTX_Device,
138 SPIR_FUNC,
139 SPIR_KERNEL,
140 Intel_OCL_BI,
141 Win64,
142 HHVM,
143 HHVM_C,
144 AVR_Intr,
145 AVR_Signal,
146 AVR_Builtin,
147 AMDGPU_CS,
148 AMDGPU_ES,
149 AMDGPU_GS,
150 AMDGPU_HS,
151 AMDGPU_LS,
152 AMDGPU_PS,
153 AMDGPU_VS,
154 AMDGPU_Kernel,
155 Numbered(u32),
158}
159
160#[derive(PartialEq, Eq, Clone, Debug, Hash)]
164pub enum MemoryEffect {
165 None,
166 Read,
167 Write,
168 ReadWrite
169}
170
171impl MemoryEffect {
172 pub(crate) fn from_llvm_bits(val : u64) -> Self {
174 match val {
175 0b00 => Self::None,
176 0b01 => Self::Read,
177 0b10 => Self::Write,
178 0b11 => Self::ReadWrite,
179 _ => panic!("Memory effect given unexpected bits {}", val)
180 }
181 }
182}
183
184#[derive(PartialEq, Eq, Clone, Debug, Hash)]
186pub enum FunctionAttribute {
187 AlignStack(u64),
188 AllocSize {
189 elt_size: u32,
190 num_elts: Option<u32>,
191 },
192 AlwaysInline,
193 Builtin,
194 Cold,
195 Convergent,
196 InaccessibleMemOnly,
197 InaccessibleMemOrArgMemOnly,
198 InlineHint,
199 JumpTable,
200 MinimizeSize,
201 Naked,
202 NoBuiltin,
203 NoCFCheck,
204 NoDuplicate,
205 NoFree,
206 NoImplicitFloat,
207 NoInline,
208 #[cfg(feature = "llvm-11-or-greater")]
209 NoMerge,
210 NonLazyBind,
211 NoRedZone,
212 NoReturn,
213 NoRecurse,
214 WillReturn,
215 ReturnsTwice,
216 NoSync,
217 NoUnwind,
218 #[cfg(feature = "llvm-11-or-greater")]
219 NullPointerIsValid,
220 OptForFuzzing,
221 OptNone,
222 OptSize,
223 ReadNone,
224 ReadOnly,
225 WriteOnly,
226 ArgMemOnly,
227 SafeStack,
228 SanitizeAddress,
229 SanitizeMemory,
230 SanitizeThread,
231 SanitizeHWAddress,
232 SanitizeMemTag,
233 ShadowCallStack,
234 SpeculativeLoadHardening,
235 Speculatable,
236 StackProtect,
237 StackProtectReq,
238 StackProtectStrong,
239 StrictFP,
240 UWTable,
241 #[cfg(feature = "llvm-16-or-greater")]
242 Memory {
243 default: MemoryEffect,
244 argmem: MemoryEffect,
245 inaccessible_mem: MemoryEffect
246 },
247 StringAttribute {
248 kind: String,
249 value: String, },
251 UnknownAttribute, }
253
254#[derive(PartialEq, Eq, Clone, Debug, Hash)]
257pub enum ParameterAttribute {
258 ZeroExt,
259 SignExt,
260 InReg,
261 #[cfg(feature = "llvm-11-or-lower")]
262 ByVal,
263 #[cfg(feature = "llvm-12-or-greater")]
264 ByVal(TypeRef),
265 #[cfg(feature = "llvm-11")]
266 Preallocated,
267 #[cfg(feature = "llvm-12-or-greater")]
268 Preallocated(TypeRef),
269 #[cfg(feature = "llvm-12-or-lower")]
270 InAlloca,
271 #[cfg(feature = "llvm-13-or-greater")]
272 InAlloca(TypeRef),
273 #[cfg(feature = "llvm-11-or-lower")]
274 SRet,
275 #[cfg(feature = "llvm-12-or-greater")]
276 SRet(TypeRef),
277 Alignment(u64),
278 NoAlias,
279 NoCapture,
280 NoFree,
281 Nest,
282 Returned,
283 NonNull,
284 Dereferenceable(u64),
285 DereferenceableOrNull(u64),
286 SwiftSelf,
287 SwiftError,
288 ImmArg,
289 #[cfg(feature = "llvm-11-or-greater")]
290 NoUndef,
291 StringAttribute {
292 kind: String,
293 value: String, },
295 UnknownAttribute, #[cfg(feature = "llvm-12-or-greater")]
297 UnknownTypeAttribute(TypeRef), }
299
300pub type GroupID = usize;
301
302use crate::constant::Constant;
307use crate::from_llvm::*;
308use crate::llvm_sys::*;
309use crate::module::ModuleContext;
310#[cfg(feature = "llvm-12-or-greater")]
311use crate::types::TypesBuilder;
312use llvm_sys::comdat::*;
313use llvm_sys::{LLVMAttributeFunctionIndex, LLVMAttributeReturnIndex};
314use std::collections::HashMap;
315use std::ffi::CString;
316
317pub(crate) struct FunctionContext<'a> {
320 #[allow(clippy::mutable_key_type)]
323 pub bb_names: &'a HashMap<LLVMBasicBlockRef, Name>,
324 #[allow(clippy::mutable_key_type)]
327 pub val_names: &'a HashMap<LLVMValueRef, Name>,
328 pub ctr: usize,
330}
331
332impl FunctionDeclaration {
333 pub(crate) fn from_llvm_ref(func: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
334 let func = unsafe { LLVMIsAFunction(func) };
335 assert!(!func.is_null());
336 debug!("Processing func {:?}", unsafe { get_value_name(func) });
337
338 let (decl, _) = FunctionDeclaration::from_llvm_ref_internal(func, ctx);
339 decl
340 }
341
342 fn from_llvm_ref_internal(func: LLVMValueRef, ctx: &mut ModuleContext) -> (Self, usize) {
347 #[cfg(feature = "llvm-14-or-lower")]
348 let functy = unsafe { LLVMGetElementType(LLVMTypeOf(func)) }; #[cfg(feature = "llvm-15-or-greater")]
350 let functy = unsafe { LLVMGlobalGetValueType(func) };
351 let mut local_ctr = 0; let decl = Self {
353 name: unsafe { get_value_name(func) },
354 parameters: {
355 let parameters: Vec<Parameter> = get_parameters(func)
356 .enumerate()
357 .map(|(i, p)| Parameter {
358 name: Name::name_or_num(unsafe { get_value_name(p) }, &mut local_ctr),
359 ty: ctx.types.type_from_llvm_ref(unsafe { LLVMTypeOf(p) }),
360 attributes: {
361 let param_num = i + 1; let num_attrs =
363 unsafe { LLVMGetAttributeCountAtIndex(func, param_num as u32) };
364 let mut attrs: Vec<LLVMAttributeRef> =
365 Vec::with_capacity(num_attrs as usize);
366 unsafe {
367 LLVMGetAttributesAtIndex(
368 func,
369 param_num as u32,
370 attrs.as_mut_ptr(),
371 );
372 attrs.set_len(num_attrs as usize);
373 };
374 attrs
375 .into_iter()
376 .map(|attr| {
377 ParameterAttribute::from_llvm_ref(
378 attr,
379 &ctx.attrsdata,
380 #[cfg(feature = "llvm-12-or-greater")]
381 &mut ctx.types,
382 )
383 })
384 .collect()
385 },
386 })
387 .collect();
388 debug!("Collected info on {} parameters", parameters.len());
389 parameters
390 },
391 is_var_arg: unsafe { LLVMIsFunctionVarArg(functy) } != 0,
392 return_type: ctx
393 .types
394 .type_from_llvm_ref(unsafe { LLVMGetReturnType(functy) }),
395 return_attributes: {
396 let num_attrs =
397 unsafe { LLVMGetAttributeCountAtIndex(func, LLVMAttributeReturnIndex) };
398 if num_attrs > 0 {
399 let mut attrs: Vec<LLVMAttributeRef> = Vec::with_capacity(num_attrs as usize);
400 unsafe {
401 LLVMGetAttributesAtIndex(
402 func,
403 LLVMAttributeReturnIndex,
404 attrs.as_mut_ptr(),
405 );
406 attrs.set_len(num_attrs as usize);
407 };
408 attrs
409 .into_iter()
410 .map(|attr| {
411 ParameterAttribute::from_llvm_ref(
412 attr,
413 &ctx.attrsdata,
414 #[cfg(feature = "llvm-12-or-greater")]
415 &mut ctx.types,
416 )
417 })
418 .collect()
419 } else {
420 vec![]
421 }
422 },
423 linkage: Linkage::from_llvm(unsafe { LLVMGetLinkage(func) }),
424 visibility: Visibility::from_llvm(unsafe { LLVMGetVisibility(func) }),
425 dll_storage_class: DLLStorageClass::from_llvm(unsafe { LLVMGetDLLStorageClass(func) }),
426 calling_convention: CallingConvention::from_u32(unsafe {
427 LLVMGetFunctionCallConv(func)
428 }),
429 alignment: unsafe { LLVMGetAlignment(func) },
430 garbage_collector_name: unsafe { get_gc(func) },
431 debugloc: DebugLoc::from_llvm_no_col(func),
432 };
433 (decl, local_ctr)
434 }
435}
436
437impl Function {
438 pub(crate) fn from_llvm_ref(func: LLVMValueRef, ctx: &mut ModuleContext) -> Self {
439 let func = unsafe { LLVMIsAFunction(func) };
440 assert!(!func.is_null());
441 debug!("Processing func {:?}", unsafe { get_value_name(func) });
442
443 let (decl, ctr_val_after_parameters) =
447 FunctionDeclaration::from_llvm_ref_internal(func, ctx);
448
449 let mut local_ctr = ctr_val_after_parameters; let bbresults: Vec<_> = get_basic_blocks(func)
458 .map(|bb| (bb, BasicBlock::first_pass_names(bb, &mut local_ctr)))
459 .collect();
460 #[allow(clippy::mutable_key_type)]
462 let bb_names: HashMap<LLVMBasicBlockRef, Name> = bbresults
463 .iter()
464 .map(|(bb, (bbname, _))| (*bb, bbname.clone()))
465 .collect();
466 debug!("Collected names of {} basic blocks", bb_names.len());
467 #[allow(clippy::mutable_key_type)]
469 let val_names: HashMap<LLVMValueRef, Name> = bbresults
470 .into_iter()
471 .flat_map(|(_, (_, namepairs))| namepairs.into_iter())
472 .chain(get_parameters(func).zip(decl.parameters.iter().map(|p| p.name.clone())))
473 .collect();
474 debug!("Collected names of {} values", val_names.len());
475 let mut func_ctx = FunctionContext {
476 bb_names: &bb_names,
477 val_names: &val_names,
478 ctr: ctr_val_after_parameters, };
480
481 Self {
482 name: decl.name,
483 parameters: decl.parameters,
484 is_var_arg: decl.is_var_arg,
485 return_type: decl.return_type,
486 basic_blocks: {
487 get_basic_blocks(func)
488 .map(|bb| BasicBlock::from_llvm_ref(bb, ctx, &mut func_ctx))
489 .collect()
490 },
491 function_attributes: {
492 let num_attrs =
493 unsafe { LLVMGetAttributeCountAtIndex(func, LLVMAttributeFunctionIndex) };
494 if num_attrs > 0 {
495 let mut attrs: Vec<LLVMAttributeRef> = Vec::with_capacity(num_attrs as usize);
496 unsafe {
497 LLVMGetAttributesAtIndex(
498 func,
499 LLVMAttributeFunctionIndex,
500 attrs.as_mut_ptr(),
501 );
502 attrs.set_len(num_attrs as usize);
503 };
504 attrs
505 .into_iter()
506 .map(|attr| FunctionAttribute::from_llvm_ref(attr, &ctx.attrsdata))
507 .collect()
508 } else {
509 vec![]
510 }
511 },
512 return_attributes: decl.return_attributes,
513 linkage: decl.linkage,
514 visibility: decl.visibility,
515 dll_storage_class: decl.dll_storage_class,
516 calling_convention: decl.calling_convention,
517 section: unsafe { get_section(func) },
518 comdat: {
519 let comdat = unsafe { LLVMGetComdat(func) };
520 if comdat.is_null() {
521 None
522 } else {
523 Some(Comdat::from_llvm_ref(comdat))
524 }
525 },
526 alignment: decl.alignment,
527 garbage_collector_name: decl.garbage_collector_name,
528 personality_function: {
529 if unsafe { LLVMHasPersonalityFn(func) } != 0 {
530 Some(Constant::from_llvm_ref(
531 unsafe { LLVMGetPersonalityFn(func) },
532 ctx,
533 ))
534 } else {
535 None
536 }
537 },
538 debugloc: decl.debugloc,
539 }
541 }
542}
543
544impl CallingConvention {
545 #[allow(clippy::cognitive_complexity)]
546 #[rustfmt::skip] pub(crate) fn from_u32(u: u32) -> Self {
548 use llvm_sys::LLVMCallConv;
549 match u {
550 _ if u == LLVMCallConv::LLVMCCallConv as u32 => CallingConvention::C,
551 _ if u == LLVMCallConv::LLVMFastCallConv as u32 => CallingConvention::Fast,
552 _ if u == LLVMCallConv::LLVMColdCallConv as u32 => CallingConvention::Cold,
553 _ if u == LLVMCallConv::LLVMGHCCallConv as u32 => CallingConvention::GHC,
554 _ if u == LLVMCallConv::LLVMHiPECallConv as u32 => CallingConvention::HiPE,
555 #[cfg(feature = "llvm-17-or-lower")]
556 _ if u == LLVMCallConv::LLVMWebKitJSCallConv as u32 => CallingConvention::WebKit_JS,
557 _ if u == LLVMCallConv::LLVMAnyRegCallConv as u32 => CallingConvention::AnyReg,
558 _ if u == LLVMCallConv::LLVMPreserveMostCallConv as u32 => CallingConvention::PreserveMost,
559 _ if u == LLVMCallConv::LLVMPreserveAllCallConv as u32 => CallingConvention::PreserveAll,
560 _ if u == LLVMCallConv::LLVMSwiftCallConv as u32 => CallingConvention::Swift,
561 _ if u == LLVMCallConv::LLVMCXXFASTTLSCallConv as u32 => CallingConvention::CXX_FastTLS,
562 _ if u == LLVMCallConv::LLVMX86StdcallCallConv as u32 => CallingConvention::X86_StdCall,
563 _ if u == LLVMCallConv::LLVMX86FastcallCallConv as u32 => CallingConvention::X86_FastCall,
564 _ if u == LLVMCallConv::LLVMX86RegCallCallConv as u32 => CallingConvention::X86_RegCall,
565 _ if u == LLVMCallConv::LLVMX86ThisCallCallConv as u32 => CallingConvention::X86_ThisCall,
566 _ if u == LLVMCallConv::LLVMX86VectorCallCallConv as u32 => CallingConvention::X86_VectorCall,
567 _ if u == LLVMCallConv::LLVMX86INTRCallConv as u32 => CallingConvention::X86_Intr,
568 _ if u == LLVMCallConv::LLVMX8664SysVCallConv as u32 => CallingConvention::X86_64_SysV,
569 _ if u == LLVMCallConv::LLVMARMAPCSCallConv as u32 => CallingConvention::ARM_APCS,
570 _ if u == LLVMCallConv::LLVMARMAAPCSCallConv as u32 => CallingConvention::ARM_AAPCS,
571 _ if u == LLVMCallConv::LLVMARMAAPCSVFPCallConv as u32 => CallingConvention::ARM_AAPCS_VFP,
572 _ if u == LLVMCallConv::LLVMMSP430INTRCallConv as u32 => CallingConvention::MSP430_INTR,
573 _ if u == LLVMCallConv::LLVMMSP430BUILTINCallConv as u32 => CallingConvention::MSP430_Builtin,
574 _ if u == LLVMCallConv::LLVMPTXKernelCallConv as u32 => CallingConvention::PTX_Kernel,
575 _ if u == LLVMCallConv::LLVMPTXDeviceCallConv as u32 => CallingConvention::PTX_Device,
576 _ if u == LLVMCallConv::LLVMSPIRFUNCCallConv as u32 => CallingConvention::SPIR_FUNC,
577 _ if u == LLVMCallConv::LLVMSPIRKERNELCallConv as u32 => CallingConvention::SPIR_KERNEL,
578 _ if u == LLVMCallConv::LLVMIntelOCLBICallConv as u32 => CallingConvention::Intel_OCL_BI,
579 _ if u == LLVMCallConv::LLVMWin64CallConv as u32 => CallingConvention::Win64,
580 _ if u == LLVMCallConv::LLVMHHVMCallConv as u32 => CallingConvention::HHVM,
581 _ if u == LLVMCallConv::LLVMHHVMCCallConv as u32 => CallingConvention::HHVM_C,
582 _ if u == LLVMCallConv::LLVMAVRINTRCallConv as u32 => CallingConvention::AVR_Intr,
583 _ if u == LLVMCallConv::LLVMAVRSIGNALCallConv as u32 => CallingConvention::AVR_Signal,
584 _ if u == LLVMCallConv::LLVMAVRBUILTINCallConv as u32 => CallingConvention::AVR_Builtin,
585 _ if u == LLVMCallConv::LLVMAMDGPUCSCallConv as u32 => CallingConvention::AMDGPU_CS,
586 _ if u == LLVMCallConv::LLVMAMDGPUESCallConv as u32 => CallingConvention::AMDGPU_ES,
587 _ if u == LLVMCallConv::LLVMAMDGPUGSCallConv as u32 => CallingConvention::AMDGPU_GS,
588 _ if u == LLVMCallConv::LLVMAMDGPUHSCallConv as u32 => CallingConvention::AMDGPU_HS,
589 _ if u == LLVMCallConv::LLVMAMDGPULSCallConv as u32 => CallingConvention::AMDGPU_LS,
590 _ if u == LLVMCallConv::LLVMAMDGPUPSCallConv as u32 => CallingConvention::AMDGPU_PS,
591 _ if u == LLVMCallConv::LLVMAMDGPUVSCallConv as u32 => CallingConvention::AMDGPU_VS,
592 _ if u == LLVMCallConv::LLVMAMDGPUKERNELCallConv as u32 => CallingConvention::AMDGPU_Kernel,
593 _ => CallingConvention::Numbered(u),
594 }
595 }
596}
597
598pub(crate) struct AttributesData {
599 function_attribute_names: HashMap<u32, String>,
600 param_attribute_names: HashMap<u32, String>,
601}
602
603impl AttributesData {
604 pub fn create() -> Self {
605 let function_attribute_names = [
606 "alignstack",
607 "allocsize",
608 "alwaysinline",
609 "builtin",
610 "cold",
611 "convergent",
612 #[cfg(feature = "llvm-15-or-lower")]
613 "inaccessiblememonly",
614 #[cfg(feature = "llvm-15-or-lower")]
615 "inaccessiblemem_or_argmemonly",
616 "inlinehint",
617 "jumptable",
618 "minsize",
619 "naked",
620 "nobuiltin",
621 "nocf_check",
622 "noduplicate",
623 "nofree",
624 "noimplicitfloat",
625 "noinline",
626 #[cfg(feature = "llvm-11-or-greater")]
627 "nomerge",
628 "nonlazybind",
629 "noredzone",
630 "noreturn",
631 "norecurse",
632 "willreturn",
633 "returns_twice",
634 "nosync",
635 "nounwind",
636 #[cfg(feature = "llvm-11-or-greater")]
637 "null_pointer_is_valid",
638 "optforfuzzing",
639 "optnone",
640 "optsize",
641 "readnone",
642 "readonly",
643 "writeonly",
644 #[cfg(feature = "llvm-15-or-lower")]
645 "argmemonly",
646 "safestack",
647 "sanitize_address",
648 "sanitize_memory",
649 "sanitize_thread",
650 "sanitize_hwaddress",
651 "sanitize_memtag",
652 "shadowcallstack",
653 "speculative_load_hardening",
654 "speculatable",
655 "ssp",
656 "sspreq",
657 "sspstrong",
658 "strictfp",
659 "uwtable",
660 #[cfg(feature = "llvm-16-or-greater")]
661 "memory"
662 ]
663 .iter()
664 .map(|&attrname| {
665 let cstr = CString::new(attrname).unwrap();
666 let kind = unsafe { LLVMGetEnumAttributeKindForName(cstr.as_ptr(), attrname.len()) };
667 assert_ne!(kind, 0, "Function attribute {:?} not found", attrname);
668 (kind, attrname.into())
669 })
670 .collect();
671 let param_attribute_names = [
672 "zeroext",
673 "signext",
674 "inreg",
675 "byval",
676 #[cfg(feature = "llvm-11-or-greater")]
677 "preallocated",
678 "inalloca",
679 "sret",
680 "align",
681 "noalias",
682 "nocapture",
683 "nofree",
684 "nest",
685 "returned",
686 "nonnull",
687 "dereferenceable",
688 "dereferenceable_or_null",
689 "swiftself",
690 "swifterror",
691 "immarg",
692 #[cfg(feature = "llvm-11-or-greater")]
693 "noundef",
694 ]
695 .iter()
696 .map(|&attrname| {
697 let cstr = CString::new(attrname).unwrap();
698 let kind = unsafe { LLVMGetEnumAttributeKindForName(cstr.as_ptr(), attrname.len()) };
699 assert_ne!(kind, 0, "Parameter attribute {:?} not found", attrname);
700 (kind, attrname.into())
701 })
702 .collect();
703 Self {
704 function_attribute_names,
705 param_attribute_names,
706 }
707 }
708
709 pub fn lookup_function_attr(&self, kind: u32) -> Option<&str> {
712 self.function_attribute_names.get(&kind).map(|s| s.as_str())
713 }
714
715 pub fn lookup_param_attr(&self, kind: u32) -> Option<&str> {
718 self.param_attribute_names.get(&kind).map(|s| s.as_str())
719 }
720}
721
722impl FunctionAttribute {
723 pub(crate) fn from_llvm_ref(a: LLVMAttributeRef, attrsdata: &AttributesData) -> Self {
724 if unsafe { LLVMIsEnumAttribute(a) } != 0 {
725 let kind = unsafe { LLVMGetEnumAttributeKind(a) };
726 match attrsdata.lookup_function_attr(kind) {
727 Some("alignstack") => Self::AlignStack(unsafe { LLVMGetEnumAttributeValue(a) }),
728 Some("allocsize") => {
729 let value = unsafe { LLVMGetEnumAttributeValue(a) };
730 let elt_size = (value >> 32) as u32;
735 let num_elts = match (value & 0xFFFF_FFFF) as u32 {
736 0xFFFF_FFFF => None,
737 val => Some(val),
738 };
739 Self::AllocSize { elt_size, num_elts }
740 },
741 Some("alwaysinline") => Self::AlwaysInline,
742 Some("builtin") => Self::Builtin,
743 Some("cold") => Self::Cold,
744 Some("convergent") => Self::Convergent,
745 Some("inaccessiblememonly") => Self::InaccessibleMemOnly,
746 Some("inaccessiblemem_or_argmemonly") => Self::InaccessibleMemOrArgMemOnly,
747 Some("inlinehint") => Self::InlineHint,
748 Some("jumptable") => Self::JumpTable,
749 Some("minsize") => Self::MinimizeSize,
750 Some("naked") => Self::Naked,
751 Some("nobuiltin") => Self::NoBuiltin,
752 Some("nocf_check") => Self::NoCFCheck,
753 Some("noduplicate") => Self::NoDuplicate,
754 Some("nofree") => Self::NoFree,
755 Some("noimplicitfloat") => Self::NoImplicitFloat,
756 Some("noinline") => Self::NoInline,
757 #[cfg(feature = "llvm-11-or-greater")]
758 Some("nomerge") => Self::NoMerge,
759 Some("nonlazybind") => Self::NonLazyBind,
760 Some("noredzone") => Self::NoRedZone,
761 Some("noreturn") => Self::NoReturn,
762 Some("norecurse") => Self::NoRecurse,
763 Some("willreturn") => Self::WillReturn,
764 Some("returns_twice") => Self::ReturnsTwice,
765 Some("nosync") => Self::NoSync,
766 Some("nounwind") => Self::NoUnwind,
767 #[cfg(feature = "llvm-11-or-greater")]
768 Some("null_pointer_is_valid") => Self::NullPointerIsValid,
769 Some("optforfuzzing") => Self::OptForFuzzing,
770 Some("optnone") => Self::OptNone,
771 Some("optsize") => Self::OptSize,
772 Some("readnone") => Self::ReadNone,
773 Some("readonly") => Self::ReadOnly,
774 Some("writeonly") => Self::WriteOnly,
775 Some("argmemonly") => Self::ArgMemOnly,
776 Some("safestack") => Self::SafeStack,
777 Some("sanitize_address") => Self::SanitizeAddress,
778 Some("sanitize_memory") => Self::SanitizeMemory,
779 Some("sanitize_thread") => Self::SanitizeThread,
780 Some("sanitize_hwaddress") => Self::SanitizeHWAddress,
781 Some("sanitize_memtag") => Self::SanitizeMemTag,
782 Some("shadowcallstack") => Self::ShadowCallStack,
783 Some("speculative_load_hardening") => Self::SpeculativeLoadHardening,
784 Some("speculatable") => Self::Speculatable,
785 Some("ssp") => Self::StackProtect,
786 Some("sspreq") => Self::StackProtectReq,
787 Some("sspstrong") => Self::StackProtectStrong,
788 Some("strictfp") => Self::StrictFP,
789 Some("uwtable") => Self::UWTable,
790 #[cfg(feature = "llvm-16-or-greater")]
791 Some("memory") => {
792 let value = unsafe { LLVMGetEnumAttributeValue(a) };
793
794 let encoded_argmem = (value >> 0) & 0b11;
800 let encoded_inaccessible_mem = (value >> 2) & 0b11;
801 let encoded_default_mem = (value >> 4) & 0b11;
802
803 Self::Memory {
804 default: MemoryEffect::from_llvm_bits(encoded_default_mem),
805 argmem: MemoryEffect::from_llvm_bits(encoded_argmem),
806 inaccessible_mem: MemoryEffect::from_llvm_bits(encoded_inaccessible_mem)
807 }
808 },
809 Some(s) => panic!("Unhandled value from lookup_function_attr: {:?}", s),
810 None => {
811 debug!("unknown enum function attr {}", kind);
812 Self::UnknownAttribute
813 },
814 }
815 } else if unsafe { LLVMIsStringAttribute(a) } != 0 {
816 Self::StringAttribute {
817 kind: unsafe { get_string_attribute_kind(a) },
818 value: unsafe { get_string_attribute_value(a) },
819 }
820 } else {
821 debug!("Encountered an unknown function attribute: neither enum nor string");
822 Self::UnknownAttribute
823 }
824 }
825}
826
827impl ParameterAttribute {
828 pub(crate) fn from_llvm_ref(
829 a: LLVMAttributeRef,
830 attrsdata: &AttributesData,
831 #[cfg(feature = "llvm-12-or-greater")] types: &mut TypesBuilder,
832 ) -> Self {
833 if unsafe { LLVMIsEnumAttribute(a) } != 0 {
834 let kind = unsafe { LLVMGetEnumAttributeKind(a) };
835 match attrsdata.lookup_param_attr(kind) {
836 Some("zeroext") => Self::ZeroExt,
837 Some("signext") => Self::SignExt,
838 Some("inreg") => Self::InReg,
839 #[cfg(feature = "llvm-11-or-lower")]
840 Some("byval") => Self::ByVal,
841 #[cfg(feature = "llvm-11")]
842 Some("preallocated") => Self::Preallocated,
843 #[cfg(feature = "llvm-12-or-lower")]
844 Some("inalloca") => Self::InAlloca,
845 #[cfg(feature = "llvm-11-or-lower")]
846 Some("sret") => Self::SRet,
847 Some("align") => Self::Alignment(unsafe { LLVMGetEnumAttributeValue(a) }),
848 Some("noalias") => Self::NoAlias,
849 Some("nocapture") => Self::NoCapture,
850 Some("nofree") => Self::NoFree,
851 Some("nest") => Self::Nest,
852 Some("returned") => Self::Returned,
853 Some("nonnull") => Self::NonNull,
854 Some("dereferenceable") => {
855 Self::Dereferenceable(unsafe { LLVMGetEnumAttributeValue(a) })
856 },
857 Some("dereferenceable_or_null") => {
858 Self::DereferenceableOrNull(unsafe { LLVMGetEnumAttributeValue(a) })
859 },
860 Some("swiftself") => Self::SwiftSelf,
861 Some("swifterror") => Self::SwiftError,
862 Some("immarg") => Self::ImmArg,
863 #[cfg(feature = "llvm-11-or-greater")]
864 Some("noundef") => Self::NoUndef,
865 Some(s) => panic!("Unhandled value from lookup_param_attr: {:?}", s),
866 None => {
867 debug!("unknown enum param attr {}", kind);
868 Self::UnknownAttribute
869 },
870 }
871 } else if unsafe { LLVMIsStringAttribute(a) } != 0 {
872 Self::StringAttribute {
873 kind: unsafe { get_string_attribute_kind(a) },
874 value: unsafe { get_string_attribute_value(a) },
875 }
876 } else if Self::is_type_attr(a) {
877 #[cfg(feature = "llvm-11-or-lower")]
878 {
879 debug!("Encountered a type attr, which shouldn't happen on LLVM 11 or lower");
880 Self::UnknownAttribute
881 }
882 #[cfg(feature = "llvm-12-or-greater")]
883 {
884 let kind = unsafe { LLVMGetEnumAttributeKind(a) };
885 let ty = types.type_from_llvm_ref(unsafe { LLVMGetTypeAttributeValue(a) });
886 match attrsdata.lookup_param_attr(kind) {
887 Some("byval") => Self::ByVal(ty),
888 Some("preallocated") => Self::Preallocated(ty),
889 #[cfg(feature = "llvm-13-or-greater")]
890 Some("inalloca") => Self::InAlloca(ty),
891 Some("sret") => Self::SRet(ty),
892 Some(s) => panic!("Unhandled value from lookup_param_attr: {:?}", s),
893 None => {
894 debug!("unknown type param attr {}", kind);
895 Self::UnknownTypeAttribute(ty)
896 },
897 }
898 }
899 } else {
900 debug!("Encountered an unknown parameter attribute: neither enum, string, nor type");
901 Self::UnknownAttribute
902 }
903 }
904
905 #[cfg(feature = "llvm-11-or-lower")]
906 fn is_type_attr(_a: LLVMAttributeRef) -> bool {
907 false
908 }
909 #[cfg(feature = "llvm-12-or-greater")]
910 fn is_type_attr(a: LLVMAttributeRef) -> bool {
911 unsafe { LLVMIsTypeAttribute(a) != 0 }
912 }
913}