├── .gitignore ├── .vscode └── settings.json ├── Cargo.toml ├── LICENSE ├── makefile ├── readme.md ├── rustfmt.toml ├── src ├── context.rs ├── lib.rs ├── module.rs ├── types │ ├── array.rs │ ├── float.rs │ ├── function.rs │ ├── generic.rs │ ├── int.rs │ ├── macros.rs │ ├── mod.rs │ ├── pointer.rs │ ├── struc.rs │ ├── traits.rs │ ├── types.rs │ ├── vector.rs │ └── void.rs ├── utils │ ├── macros.rs │ ├── mdkind_ids.rs │ ├── mem_buffer.rs │ ├── mod.rs │ ├── string.rs │ ├── support.rs │ └── traits.rs └── values │ ├── argument.rs │ ├── block.rs │ ├── constant │ ├── array.rs │ ├── block_addr.rs │ ├── const_expr │ │ ├── binary.rs │ │ ├── const_expr.rs │ │ ├── fcmp.rs │ │ ├── gep.rs │ │ ├── icmp.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── traits.rs │ │ └── unary.rs │ ├── constant.rs │ ├── float.rs │ ├── int.rs │ ├── macros.rs │ ├── mod.rs │ ├── null.rs │ ├── struc.rs │ ├── traits.rs │ ├── undef.rs │ └── vector.rs │ ├── function.rs │ ├── generic.rs │ ├── global.rs │ ├── inline_asm.rs │ ├── instruction │ ├── alloca.rs │ ├── binary.rs │ ├── br.rs │ ├── call.rs │ ├── call_br.rs │ ├── extract_value.rs │ ├── fcmp.rs │ ├── gep.rs │ ├── icmp.rs │ ├── indir_br.rs │ ├── insert_value.rs │ ├── instr.rs │ ├── load.rs │ ├── macros.rs │ ├── mod.rs │ ├── opcode.rs │ ├── phi.rs │ ├── ret.rs │ ├── select.rs │ ├── store.rs │ ├── switch.rs │ ├── traits.rs │ ├── unary.rs │ └── unreachable.rs │ ├── macros.rs │ ├── metadata │ ├── const_as_md.rs │ ├── di_expression.rs │ ├── di_label.rs │ ├── di_local_var.rs │ ├── di_location.rs │ ├── dist_md_op_ph.rs │ ├── generic_di_node.rs │ ├── local_as_md.rs │ ├── macros.rs │ ├── md_tuple.rs │ ├── metadata.rs │ ├── mod.rs │ └── traits.rs │ ├── mod.rs │ ├── operand.rs │ └── traits.rs └── tests ├── block_name.rs ├── c_files ├── argrel │ ├── argrel_1.c │ └── argrel_2.c ├── argval │ ├── argval_1.c │ ├── argval_2.c │ ├── argval_3.c │ └── argval_uses.c ├── basic │ ├── example_1.c │ ├── example_2.c │ ├── example_3.c │ ├── example_4.c │ ├── example_5.c │ ├── example_6.c │ ├── example_7.c │ ├── exit_point.c │ ├── exit_point_2.c │ ├── loop.c │ ├── loop_2.c │ ├── recursive.c │ ├── struct_store.c │ └── struct_store_2.c ├── br │ └── br_1.c ├── causality │ ├── causality_1.c │ ├── causality_2.c │ ├── causality_3.c │ └── causality_bad_1.c ├── fn_ptr │ └── fn_ptr_1.c ├── free │ └── free_struct.c ├── git_fopen │ ├── git_fopen_1.c │ └── openssl_fopen.c ├── kernel │ ├── acpi_lpat_free_conversion_table.c │ ├── mce_amd.c │ ├── rhashtable_free_and_destroy.c │ └── rsi_probe.c ├── lock │ ├── lock_1.c │ ├── lock_2.c │ ├── lock_3.c │ ├── lock_4.c │ ├── lock_with_alias.c │ ├── lock_with_global.c │ └── lock_with_global_2.c ├── malloc │ ├── branch_malloc.c │ ├── dugraph_dup.c │ ├── dugraph_dup_2.c │ ├── indexed_1.c │ ├── kzalloc_1.c │ ├── kzalloc_2.c │ ├── kzalloc_3.c │ ├── malloc_check_against_var.c │ ├── malloc_test.c │ ├── malloc_wrapper.c │ ├── malloc_wrapper_2.c │ ├── multi_result.c │ ├── sem_malloc.c │ ├── sem_malloc_2.c │ └── struct_1.c ├── nested_loop │ └── nested_loop_1.c ├── path │ ├── path.c │ ├── path2.c │ ├── path3.c │ ├── path4.c │ └── path5.c ├── slice_reduction │ ├── slice_reduction_1.c │ └── slice_reduction_2.c ├── switch │ ├── switch_1.c │ ├── switch_2.c │ ├── switch_3.c │ ├── switch_4.c │ └── switch_dot_dot_dot.c ├── ty_cast │ └── ty_cast_1.c └── unreach │ └── unreach1.c ├── dbgmd.rs ├── debug_loc.rs ├── fn_ptr.rs ├── instr_structure.rs ├── intrinsic.rs ├── kernel.rs ├── load_bc.rs └── module_getters.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | /target 3 | Cargo.lock 4 | 5 | # C/LLVM Bytecode tests 6 | *.bc 7 | *.ll -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.watcherExclude": { 3 | "**/target/doc/**": true 4 | } 5 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "llir" 3 | version = "0.2.2" 4 | authors = ["Ziyang Li "] 5 | license = "MIT" 6 | description = "LLVM IR Binding" 7 | repository = "https://github.com/liby99/llir" 8 | keywords = ["llvm", "ir"] 9 | edition = "2018" 10 | 11 | [dependencies] 12 | llvm-sys = "100" 13 | libc = "0.2" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ziyang Li 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | WLLVM = @ wllvm 2 | LLVM_DIS = @ llvm-dis 3 | RM = @ rm -rf 4 | MV = @ mv 5 | 6 | TEST_C_FILES = $(shell find tests/ -type f -name '*.c') 7 | TEST_BC_FILES = $(patsubst tests/%.c, tests/%.bc, $(TEST_C_FILES)) 8 | 9 | all: tests 10 | 11 | tests: $(TEST_BC_FILES) 12 | 13 | tests/%.bc: tests/%.c 14 | $(WLLVM) -g -c "$<" 15 | $(RM) "./a.out" ".$(*F).o" "$(*F).o" 16 | $(MV) ".$(*F).o.bc" "$@" 17 | $(LLVM_DIS) "$@" 18 | 19 | clean: clean-tests 20 | 21 | clean-tests: 22 | $(RM) tests/c_files/**/*.bc tests/c_files/**/*.ll 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # LLVM IR Binding for Rust 2 | 3 | This LLVM IR Binding provides intuitive and well-organized safe Rust API for analyzing existing LLVM modules. 4 | Thus the whole library is thread-safe. This crate does not provide the functionality to produce new LLVM module 5 | or change existing module. 6 | 7 | ## How to use 8 | 9 | ``` rust 10 | use llir; 11 | 12 | // Create context 13 | let context = llir::Context::create(); 14 | 15 | // Specify path to the byte code 16 | let path = Path::new("path/to/your/llvm/bytecode.bc"); 17 | 18 | // Load the module with that path 19 | let module = context.load_module(path)?; 20 | 21 | // Iterate through functions, blocks, and instructions... 22 | for func in module.iter_functions() { 23 | for block in func.iter_blocks() { 24 | for instr in block.iter_instructions() { 25 | // Do things to instr... 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | ## Documentation 32 | 33 | The automatically generated documentation is hosted [on docs.rs](https://docs.rs/llir/) 34 | 35 | ## Include as a library 36 | 37 | Make sure you installed LLVM 10.0 on your machine and is visible via path. 38 | 39 | Then go to your `Cargo.toml` and add this line under your dependencies: 40 | 41 | ``` toml 42 | # Cargo.toml 43 | [dependencies] 44 | llir = "0.1" 45 | ``` -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 2 | max_width = 120 -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | #[allow(deprecated)] 2 | use llvm_sys::bit_reader::LLVMParseBitcodeInContext; 3 | use llvm_sys::core::*; 4 | use llvm_sys::prelude::LLVMContextRef; 5 | use std::mem::MaybeUninit; 6 | use std::path::Path; 7 | 8 | use super::utils::mem_buffer::MemoryBuffer; 9 | use super::utils::support::LLVMString; 10 | use super::Module; 11 | 12 | /// LLVM Context 13 | /// 14 | /// ``` 15 | /// # use llir::Context; 16 | /// let ctx = Context::create(); 17 | /// ``` 18 | #[derive(Debug, PartialEq, Eq)] 19 | pub struct Context(LLVMContextRef); 20 | 21 | unsafe impl Send for Context {} 22 | 23 | unsafe impl Sync for Context {} 24 | 25 | impl Context { 26 | pub(crate) fn new(context: LLVMContextRef) -> Self { 27 | Self(context) 28 | } 29 | 30 | /// Create a new context 31 | pub fn create() -> Self { 32 | let context = unsafe { LLVMContextCreate() }; 33 | Self::new(context) 34 | } 35 | 36 | /// Load a module 37 | /// 38 | /// ``` 39 | /// # use llir::Context; 40 | /// # let ctx = Context::create(); 41 | /// let module = ctx.load_module(Path::new("tests/c_files/basic/example_1.bc"))?; 42 | /// ``` 43 | pub fn load_module<'ctx, P>(&'ctx self, path: P) -> Result, String> 44 | where 45 | P: AsRef, 46 | { 47 | let buffer = MemoryBuffer::create_from_file(path.as_ref())?; 48 | let mut module = MaybeUninit::uninit(); 49 | let mut err_string = MaybeUninit::uninit(); 50 | #[allow(deprecated)] 51 | let success = unsafe { 52 | LLVMParseBitcodeInContext( 53 | self.0, 54 | buffer.memory_buffer, 55 | module.as_mut_ptr(), 56 | err_string.as_mut_ptr(), 57 | ) 58 | }; 59 | if success != 0 { 60 | let err_string = unsafe { err_string.assume_init() }; 61 | return Err(LLVMString::new(err_string).to_string()); 62 | } 63 | 64 | let module = unsafe { module.assume_init() }; 65 | 66 | Ok(Module::new(module)) 67 | } 68 | } 69 | 70 | impl Drop for Context { 71 | fn drop(&mut self) { 72 | unsafe { LLVMContextDispose(self.0) } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # LLVM IR Binding for Rust 2 | //! 3 | //! This LLVM IR Binding provides intuitive and well-organized safe Rust API for analyzing existing LLVM modules. 4 | //! Thus the whole library is thread-safe. This crate does not provide the functionality to produce new LLVM module 5 | //! or change existing module. 6 | //! 7 | //! ## Getting started 8 | //! 9 | //! ``` rust 10 | //! use llir; 11 | //! 12 | //! // Create context 13 | //! let context = llir::Context::create(); 14 | //! 15 | //! // Specify path to the byte code 16 | //! let path = Path::new("path/to/your/llvm/bytecode.bc"); 17 | //! 18 | //! // Load the module with that path 19 | //! let module = context.load_module(path)?; 20 | //! 21 | //! // Iterate through functions, blocks, and instructions... 22 | //! for func in module.iter_functions() { 23 | //! for block in func.iter_blocks() { 24 | //! for instr in block.iter_instructions() { 25 | //! // Do things to instr... 26 | //! } 27 | //! } 28 | //! } 29 | //! ``` 30 | //! 31 | //! Other than context and module, the crate mainly consists of LLVM values and types. Checkout each 32 | //! submodule for more information. 33 | 34 | #[macro_use] 35 | mod utils; 36 | 37 | mod context; 38 | mod module; 39 | pub mod types; 40 | pub mod values; 41 | 42 | pub use context::*; 43 | pub use module::*; 44 | pub use utils::traits::*; 45 | -------------------------------------------------------------------------------- /src/module.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::{LLVMModuleRef, LLVMValueRef}; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// LLVM Module 9 | pub struct Module<'ctx>(LLVMModuleRef, PhantomData<&'ctx ()>); 10 | 11 | impl_send_sync!(Module); 12 | 13 | impl<'ctx> Module<'ctx> { 14 | pub(crate) fn new(ptr: LLVMModuleRef) -> Self { 15 | Self(ptr, PhantomData) 16 | } 17 | 18 | /// Iterate all functions inside the module 19 | /// 20 | /// ``` 21 | /// # use llir::*; 22 | /// # use std::path::*; 23 | /// # let ctx = Context::create(); 24 | /// # let module = ctx.load_module(PathBuf::from("tests/c_files/basic/example_1.bc")); 25 | /// for func in module.iter_functions() { 26 | /// // Do things with func 27 | /// } 28 | /// ``` 29 | pub fn iter_functions(&self) -> ValueIterator<'ctx, Function<'ctx>> { 30 | ValueIterator { 31 | curr_value: unsafe { LLVMGetFirstFunction(self.0) }, 32 | next_fn: next_function, 33 | marker: PhantomData 34 | } 35 | } 36 | 37 | /// Get the function by name 38 | pub fn get_function(&self, name: &str) -> Option> { 39 | let zero_appended = format!("{}\0", name); 40 | let fn_ptr = unsafe { LLVMGetNamedFunction(self.0, zero_appended.as_ptr() as *const i8) }; 41 | if fn_ptr.is_null() { None } else { Some(Function::from_llvm(fn_ptr)) } 42 | } 43 | 44 | /// Iterate all globals variables 45 | /// 46 | /// ``` 47 | /// for glob in module.iter_global_variables() { 48 | /// // Do things with glob 49 | /// } 50 | /// ``` 51 | pub fn iter_global_variables(&self) -> ValueIterator<'ctx, GlobalVariable<'ctx>> { 52 | ValueIterator { 53 | curr_value: unsafe { LLVMGetFirstGlobal(self.0) }, 54 | next_fn: next_global, 55 | marker: PhantomData 56 | } 57 | } 58 | 59 | /// Get global variable by name 60 | pub fn get_global_variable(&self, name: &str) -> Option> { 61 | let zero_appended = format!("{}\0", name); 62 | let gv_ptr = unsafe { LLVMGetNamedGlobal(self.0, zero_appended.as_ptr() as *const i8) }; 63 | if gv_ptr.is_null() { None } else { Some(GlobalVariable::from_llvm(gv_ptr)) } 64 | } 65 | 66 | /// Iterate all global aliases 67 | /// 68 | /// ``` 69 | /// for glob_alias in module.iter_global_aliases() { 70 | /// // Do things with global alias 71 | /// } 72 | /// ``` 73 | pub fn iter_global_aliases(&self) -> ValueIterator<'ctx, GlobalAlias<'ctx>> { 74 | ValueIterator { 75 | curr_value: unsafe { LLVMGetFirstGlobalAlias(self.0) }, 76 | next_fn: next_global_alias, 77 | marker: PhantomData, 78 | } 79 | } 80 | 81 | /// Get global alias by name 82 | pub fn get_global_alias(&self, name: &str) -> Option> { 83 | let ga_ptr = unsafe { LLVMGetNamedGlobalAlias(self.0, name.as_ptr() as *const i8, name.len()) }; 84 | if ga_ptr.is_null() { None } else { Some(GlobalAlias::from_llvm(ga_ptr)) } 85 | } 86 | 87 | /// Iterate all globals, including global variables and global aliases 88 | /// 89 | /// ``` rust 90 | /// for glob in module.iter_globals() { 91 | /// match glob { 92 | /// Global::Variable(v) => { /* ... */ }, 93 | /// Global::Alias(a) => { /* ... */ }, 94 | /// } 95 | /// } 96 | /// ``` 97 | pub fn iter_globals(&self) -> GlobalIterator<'ctx> { 98 | GlobalIterator { 99 | var_iter: self.iter_global_variables(), 100 | alias_iter: self.iter_global_aliases(), 101 | } 102 | } 103 | } 104 | 105 | fn next_function(ptr: LLVMValueRef) -> LLVMValueRef { 106 | unsafe { LLVMGetNextFunction(ptr) } 107 | } 108 | 109 | fn next_global(ptr: LLVMValueRef) -> LLVMValueRef { 110 | unsafe { LLVMGetNextGlobal(ptr) } 111 | } 112 | 113 | fn next_global_alias(ptr: LLVMValueRef) -> LLVMValueRef { 114 | unsafe { LLVMGetNextGlobalAlias(ptr) } 115 | } 116 | 117 | #[doc(hidden)] 118 | pub struct ValueIterator<'ctx, T> where T : FromLLVMValue { 119 | curr_value: LLVMValueRef, 120 | next_fn: fn(LLVMValueRef) -> LLVMValueRef, 121 | marker: PhantomData<&'ctx T>, 122 | } 123 | 124 | impl<'ctx, T> Iterator for ValueIterator<'ctx, T> where T : FromLLVMValue { 125 | type Item = T; 126 | 127 | fn next(&mut self) -> Option { 128 | if self.curr_value.is_null() { 129 | None 130 | } else { 131 | let result = Some(T::from_llvm(self.curr_value)); 132 | self.curr_value = (self.next_fn)(self.curr_value); 133 | result 134 | } 135 | } 136 | } 137 | 138 | #[doc(hidden)] 139 | pub struct GlobalIterator<'ctx> { 140 | var_iter: ValueIterator<'ctx, GlobalVariable<'ctx>>, 141 | alias_iter: ValueIterator<'ctx, GlobalAlias<'ctx>>, 142 | } 143 | 144 | impl<'ctx> Iterator for GlobalIterator<'ctx> { 145 | type Item = Global<'ctx>; 146 | 147 | fn next(&mut self) -> Option { 148 | match self.var_iter.next() { 149 | Some(gv) => Some(gv.as_global()), 150 | None => match self.alias_iter.next() { 151 | Some(ga) => Some(ga.as_global()), 152 | None => None 153 | } 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /src/types/array.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetArrayLength, LLVMGetElementType}; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::{FromLLVMType, TypeRef}; 7 | 8 | /// [Array Type](https://llvm.org/docs/LangRef.html#array-type) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct ArrayType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(ArrayType); 13 | 14 | impl<'ctx> ArrayType<'ctx> { 15 | /// Get the element_type of the Array Type 16 | pub fn element_type(&self) -> Type<'ctx> { 17 | Type::from_llvm(unsafe { LLVMGetElementType(self.0) }) 18 | } 19 | 20 | /// Get the number of elements in the Array Type 21 | pub fn num_elements(&self) -> usize { 22 | unsafe { LLVMGetArrayLength(self.0) as usize } 23 | } 24 | } 25 | 26 | impl<'ctx> AsType<'ctx> for ArrayType<'ctx> { 27 | fn as_type(&self) -> Type<'ctx> { 28 | Type::Array(self.clone()) 29 | } 30 | } 31 | 32 | impl_positional_type_ref!(ArrayType, 0); 33 | 34 | impl_positional_from_llvm_type!(ArrayType); 35 | -------------------------------------------------------------------------------- /src/types/float.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetTypeKind; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use llvm_sys::LLVMTypeKind; 4 | use std::marker::PhantomData; 5 | 6 | use crate::types::*; 7 | use crate::{FromLLVMType, TypeRef}; 8 | 9 | /// The type kind for Float Type 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | #[allow(non_camel_case_types)] 12 | pub enum FloatTypeKind { 13 | /// 16-bit 14 | Half, 15 | /// 32-bit 16 | Single, 17 | /// 64-bit 18 | Double, 19 | /// 128-bit 20 | FP128, 21 | /// 80-bit for X86 22 | X86_FP80, 23 | /// 128-bit for Power PC 24 | PPC_FP128, 25 | } 26 | 27 | impl FloatTypeKind { 28 | /// Get the bit-width of that type kind 29 | pub fn width(&self) -> u32 { 30 | match self { 31 | Self::Half => 16, 32 | Self::Single => 32, 33 | Self::Double => 64, 34 | Self::FP128 => 128, 35 | Self::X86_FP80 => 80, 36 | Self::PPC_FP128 => 128, 37 | } 38 | } 39 | 40 | pub(crate) fn from_llvm(tk: LLVMTypeKind) -> Option { 41 | use FloatTypeKind::*; 42 | use LLVMTypeKind::*; 43 | match tk { 44 | LLVMHalfTypeKind => Some(Half), 45 | LLVMFloatTypeKind => Some(Single), 46 | LLVMDoubleTypeKind => Some(Double), 47 | LLVMFP128TypeKind => Some(FP128), 48 | LLVMX86_FP80TypeKind => Some(X86_FP80), 49 | LLVMPPC_FP128TypeKind => Some(PPC_FP128), 50 | _ => None, 51 | } 52 | } 53 | } 54 | 55 | /// [Float Type](https://llvm.org/docs/LangRef.html#floating-point-types) 56 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 57 | pub struct FloatType<'ctx>(FloatTypeKind, LLVMTypeRef, PhantomData<&'ctx ()>); 58 | 59 | impl_send_sync!(FloatType); 60 | 61 | impl<'ctx> FloatType<'ctx> { 62 | /// Get the kind 63 | pub fn kind(&self) -> FloatTypeKind { 64 | self.0 65 | } 66 | 67 | /// Get the bit-width for this float type 68 | pub fn width(&self) -> u32 { 69 | self.0.width() 70 | } 71 | } 72 | 73 | impl<'ctx> AsType<'ctx> for FloatType<'ctx> { 74 | fn as_type(&self) -> Type<'ctx> { 75 | Type::Float(self.clone()) 76 | } 77 | } 78 | 79 | impl_positional_type_ref!(FloatType, 1); 80 | 81 | impl<'ctx> FromLLVMType for FloatType<'ctx> { 82 | fn from_llvm(ptr: LLVMTypeRef) -> Self { 83 | let kind = FloatTypeKind::from_llvm(unsafe { LLVMGetTypeKind(ptr) }).unwrap(); 84 | Self(kind, ptr, PhantomData) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/types/function.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::{FromLLVMType, TypeRef}; 7 | 8 | /// [Function Type](https://llvm.org/docs/LangRef.html#function-type) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct FunctionType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(FunctionType); 13 | 14 | impl<'ctx> FunctionType<'ctx> { 15 | /// Get the number of argument types 16 | pub fn num_argument_types(&self) -> usize { 17 | unsafe { LLVMCountParamTypes(self.0) as usize } 18 | } 19 | 20 | /// Get argument types in an array 21 | pub fn argument_types(&self) -> Vec> { 22 | let num_arg_types = self.num_argument_types(); 23 | let mut type_refs = Vec::with_capacity(num_arg_types); 24 | unsafe { 25 | LLVMGetParamTypes(self.0, type_refs.as_mut_ptr()); 26 | type_refs.set_len(num_arg_types); 27 | }; 28 | type_refs.into_iter().map(|t| Type::from_llvm(t)).collect() 29 | } 30 | 31 | /// Get the argument type at a given index 32 | pub fn argument_type(&self, index: usize) -> Option> { 33 | let types = self.argument_types(); 34 | if index < types.len() { 35 | Some(types[index]) 36 | } else { 37 | None 38 | } 39 | } 40 | 41 | /// Get the return type 42 | pub fn return_type(&self) -> Type<'ctx> { 43 | Type::from_llvm(unsafe { LLVMGetReturnType(self.0) }) 44 | } 45 | 46 | /// Check if the return type is not a void type 47 | pub fn has_return_type(&self) -> bool { 48 | match self.return_type() { 49 | Type::Void(_) => false, 50 | _ => true, 51 | } 52 | } 53 | 54 | /// Check if the function type is variable argument 55 | pub fn is_var_arg(&self) -> bool { 56 | unsafe { LLVMIsFunctionVarArg(self.0) != 0 } 57 | } 58 | } 59 | 60 | impl<'ctx> AsType<'ctx> for FunctionType<'ctx> { 61 | fn as_type(&self) -> Type<'ctx> { 62 | Type::Function(self.clone()) 63 | } 64 | } 65 | 66 | impl_positional_type_ref!(FunctionType, 0); 67 | 68 | impl_positional_from_llvm_type!(FunctionType); 69 | -------------------------------------------------------------------------------- /src/types/generic.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMTypeRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::{FromLLVMType, TypeRef}; 5 | 6 | /// A placeholder type; used when the type is not supported yet 7 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 8 | pub struct GenericType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 9 | 10 | impl_send_sync!(GenericType); 11 | 12 | impl_positional_type_ref!(GenericType, 0); 13 | 14 | impl_positional_from_llvm_type!(GenericType); -------------------------------------------------------------------------------- /src/types/int.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetIntTypeWidth; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::{FromLLVMType, TypeRef}; 7 | 8 | /// [Integer type](https://llvm.org/docs/LangRef.html#integer-type) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct IntType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(IntType); 13 | 14 | impl<'ctx> IntType<'ctx> { 15 | /// Get the bit-width 16 | pub fn width(&self) -> u32 { 17 | unsafe { LLVMGetIntTypeWidth(self.0) } 18 | } 19 | } 20 | 21 | impl<'ctx> AsType<'ctx> for IntType<'ctx> { 22 | fn as_type(&self) -> Type<'ctx> { 23 | Type::Int(self.clone()) 24 | } 25 | } 26 | 27 | impl_positional_type_ref!(IntType, 0); 28 | 29 | impl_positional_from_llvm_type!(IntType); -------------------------------------------------------------------------------- /src/types/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_positional_type_ref { 2 | ($id:ident, $pos:tt) => { 3 | impl<'ctx> TypeRef for $id<'ctx> { 4 | fn type_ref(&self) -> LLVMTypeRef { 5 | self.$pos 6 | } 7 | } 8 | } 9 | } 10 | 11 | macro_rules! impl_positional_from_llvm_type { 12 | ($id:ident) => { 13 | impl<'ctx> FromLLVMType for $id<'ctx> { 14 | fn from_llvm(ptr: LLVMTypeRef) -> Self { 15 | Self(ptr, PhantomData) 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/types/mod.rs: -------------------------------------------------------------------------------- 1 | //! LLVM Types 2 | //! 3 | //! The LLVM Types mainly follows the following hierarchy 4 | //! 5 | //! - [Type](enum.Type.html) 6 | //! - [Void](struct.VoidType.html) 7 | //! - [Int](struct.IntType.html) 8 | //! - [Float](struct.FloatType.html) 9 | //! - [Pointer](struct.PointerType.html) 10 | //! - [Array](struct.ArrayType.html) 11 | //! - [Vector](struct.VectorType.html) 12 | //! - [Struct](enum.StructType.html) 13 | //! - [Named Struct](struct.NamedStructType.html) 14 | //! - [Struct Literal](struct.LiteralStructType.html) 15 | //! - [Function](struct.FunctionType.html) 16 | //! 17 | //! ## How to use 18 | //! 19 | //! You can get a type from a valid value, for example a function 20 | //! 21 | //! ``` rust 22 | //! for func in module.iter_functions() { 23 | //! let func_pointer_type = func.get_type(); 24 | //! match func_pointer_type { 25 | //! Type::PointerType(p) => { 26 | //! match p.element_type() { 27 | //! Type::FunctionType(func_type) => { 28 | //! let return_type = func_type.return_type(); 29 | //! let argument_types = func_type.argument_types(); 30 | //! // Do things to function type... 31 | //! } 32 | //! _ => panic!("Type of a function should be a pointer to a function type") 33 | //! } 34 | //! } 35 | //! _ => panic!("Type of a function should be a pointer to a function type") 36 | //! } 37 | //! } 38 | //! ``` 39 | //! 40 | //! You can also get a type from globals, constants, arguments, and part of instructions. 41 | //! 42 | //! Note that instructions like `branch` doesn't contain a type. So we don't provide 43 | //! `get_type()` method for every instruction. 44 | 45 | #[macro_use] 46 | mod macros; 47 | pub use macros::*; 48 | 49 | mod types; 50 | mod void; 51 | mod int; 52 | mod float; 53 | mod pointer; 54 | mod array; 55 | mod vector; 56 | mod struc; 57 | mod function; 58 | mod traits; 59 | mod generic; 60 | 61 | pub use types::*; 62 | pub use void::*; 63 | pub use int::*; 64 | pub use float::*; 65 | pub use pointer::*; 66 | pub use array::*; 67 | pub use vector::*; 68 | pub use struc::*; 69 | pub use function::*; 70 | pub use traits::*; 71 | pub use generic::*; 72 | -------------------------------------------------------------------------------- /src/types/pointer.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetElementType; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::{FromLLVMType, TypeRef}; 7 | 8 | /// [Pointer type](https://llvm.org/docs/LangRef.html#pointer-type) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct PointerType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(PointerType); 13 | 14 | impl<'ctx> PointerType<'ctx> { 15 | /// Get the element type of the pointer type 16 | /// e.g. `"*i32".element_type() == "i32"` 17 | pub fn element_type(&self) -> Type<'ctx> { 18 | Type::from_llvm(unsafe { LLVMGetElementType(self.0) }) 19 | } 20 | } 21 | 22 | impl<'ctx> AsType<'ctx> for PointerType<'ctx> { 23 | fn as_type(&self) -> Type<'ctx> { 24 | Type::Pointer(self.clone()) 25 | } 26 | } 27 | 28 | impl_positional_type_ref!(PointerType, 0); 29 | 30 | impl_positional_from_llvm_type!(PointerType); -------------------------------------------------------------------------------- /src/types/struc.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMCountStructElementTypes, LLVMGetStructElementTypes, LLVMIsLiteralStruct}; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::utils::string_of_type; 7 | use crate::{FromLLVMType, TypeRef}; 8 | 9 | /// [Struct type](https://llvm.org/docs/LangRef.html#structure-type) 10 | /// 11 | /// Could either be named or a literal 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 13 | pub enum StructType<'ctx> { 14 | NamedStruct(NamedStructType<'ctx>), 15 | LiteralStruct(LiteralStructType<'ctx>), 16 | } 17 | 18 | /// The struct type API applicable to every struct type 19 | pub trait StructTypeTrait<'ctx>: TypeRef { 20 | /// Get the number of element types in the Struct 21 | fn num_element_types(&self) -> usize { 22 | unsafe { LLVMCountStructElementTypes(self.type_ref()) as usize } 23 | } 24 | 25 | /// Get the element types in vector 26 | fn element_types(&self) -> Vec> { 27 | let num_elems = self.num_element_types(); 28 | let mut type_refs = Vec::with_capacity(num_elems); 29 | unsafe { 30 | LLVMGetStructElementTypes(self.type_ref(), type_refs.as_mut_ptr()); 31 | type_refs.set_len(num_elems); 32 | }; 33 | type_refs.into_iter().map(|t| Type::from_llvm(t)).collect() 34 | } 35 | 36 | /// Get the element type at a given index 37 | fn element_type(&self, index: usize) -> Option> { 38 | let types = self.element_types(); 39 | if index < types.len() { 40 | Some(types[index]) 41 | } else { 42 | None 43 | } 44 | } 45 | } 46 | 47 | impl<'ctx> StructType<'ctx> { 48 | /// Check if the struct type is named 49 | pub fn is_named(&self) -> bool { 50 | match self { 51 | Self::NamedStruct(_) => true, 52 | Self::LiteralStruct(_) => false, 53 | } 54 | } 55 | 56 | /// Get the struct name 57 | pub fn name(&self) -> Option { 58 | match self { 59 | Self::NamedStruct(ns) => Some(ns.name()), 60 | _ => None, 61 | } 62 | } 63 | } 64 | 65 | impl<'ctx> StructTypeTrait<'ctx> for StructType<'ctx> {} 66 | 67 | impl<'ctx> AsType<'ctx> for StructType<'ctx> { 68 | fn as_type(&self) -> Type<'ctx> { 69 | Type::Struct(self.clone()) 70 | } 71 | } 72 | 73 | impl<'ctx> TypeRef for StructType<'ctx> { 74 | fn type_ref(&self) -> LLVMTypeRef { 75 | match self { 76 | Self::NamedStruct(ns) => ns.type_ref(), 77 | Self::LiteralStruct(ls) => ls.type_ref(), 78 | } 79 | } 80 | } 81 | 82 | impl<'ctx> FromLLVMType for StructType<'ctx> { 83 | fn from_llvm(ptr: LLVMTypeRef) -> Self { 84 | if unsafe { LLVMIsLiteralStruct(ptr) } != 0 { 85 | Self::LiteralStruct(LiteralStructType::from_llvm(ptr)) 86 | } else { 87 | Self::NamedStruct(NamedStructType::from_llvm(ptr)) 88 | } 89 | } 90 | } 91 | 92 | /// A struct literal without name 93 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 94 | pub struct LiteralStructType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 95 | 96 | impl_send_sync!(LiteralStructType); 97 | 98 | impl<'ctx> StructTypeTrait<'ctx> for LiteralStructType<'ctx> {} 99 | 100 | impl<'ctx> AsType<'ctx> for LiteralStructType<'ctx> { 101 | fn as_type(&self) -> Type<'ctx> { 102 | Type::Struct(StructType::LiteralStruct(self.clone())) 103 | } 104 | } 105 | 106 | impl_positional_type_ref!(LiteralStructType, 0); 107 | 108 | impl_positional_from_llvm_type!(LiteralStructType); 109 | 110 | /// A named struct type that you can get name from 111 | /// 112 | /// Named struct allows recursive type definition 113 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 114 | pub struct NamedStructType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 115 | 116 | impl_send_sync!(NamedStructType); 117 | 118 | impl<'ctx> StructTypeTrait<'ctx> for NamedStructType<'ctx> {} 119 | 120 | impl<'ctx> NamedStructType<'ctx> { 121 | /// Get the name of the named struct 122 | pub fn name(&self) -> String { 123 | string_of_type(self.0) 124 | } 125 | } 126 | 127 | impl<'ctx> AsType<'ctx> for NamedStructType<'ctx> { 128 | fn as_type(&self) -> Type<'ctx> { 129 | Type::Struct(StructType::NamedStruct(self.clone())) 130 | } 131 | } 132 | 133 | impl_positional_type_ref!(NamedStructType, 0); 134 | 135 | impl_positional_from_llvm_type!(NamedStructType); -------------------------------------------------------------------------------- /src/types/traits.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | /// Turn every type's child classes into a type container enum 4 | pub trait AsType<'ctx> { 5 | fn as_type(&self) -> Type<'ctx>; 6 | } 7 | -------------------------------------------------------------------------------- /src/types/types.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetTypeKind; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use llvm_sys::LLVMTypeKind; 4 | 5 | use super::*; 6 | use crate::{FromLLVMType, TypeRef}; 7 | 8 | /// [Type](https://llvm.org/docs/LangRef.html#type-system) 9 | /// 10 | /// Super class for all LLVM types 11 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 12 | pub enum Type<'ctx> { 13 | Void(VoidType<'ctx>), 14 | Int(IntType<'ctx>), 15 | Float(FloatType<'ctx>), 16 | Pointer(PointerType<'ctx>), 17 | Array(ArrayType<'ctx>), 18 | Vector(VectorType<'ctx>), 19 | Struct(StructType<'ctx>), 20 | Function(FunctionType<'ctx>), 21 | Other(GenericType<'ctx>), 22 | } 23 | 24 | impl<'ctx> Type<'ctx> { 25 | /// Check if the type is a void type 26 | pub fn is_void_type(&self) -> bool { 27 | match self { 28 | Self::Void(_) => true, 29 | _ => false, 30 | } 31 | } 32 | } 33 | 34 | impl<'ctx> FromLLVMType for Type<'ctx> { 35 | fn from_llvm(ptr: LLVMTypeRef) -> Self { 36 | use LLVMTypeKind::*; 37 | match unsafe { LLVMGetTypeKind(ptr) } { 38 | LLVMVoidTypeKind => Self::Void(VoidType::from_llvm(ptr)), 39 | LLVMIntegerTypeKind => Self::Int(IntType::from_llvm(ptr)), 40 | LLVMPointerTypeKind => Self::Pointer(PointerType::from_llvm(ptr)), 41 | LLVMArrayTypeKind => Self::Array(ArrayType::from_llvm(ptr)), 42 | LLVMVectorTypeKind => Self::Vector(VectorType::from_llvm(ptr)), 43 | LLVMStructTypeKind => Self::Struct(StructType::from_llvm(ptr)), 44 | LLVMFunctionTypeKind => Self::Function(FunctionType::from_llvm(ptr)), 45 | f if FloatTypeKind::from_llvm(f).is_some() => Self::Float(FloatType::from_llvm(ptr)), 46 | _ => Self::Other(GenericType::from_llvm(ptr)), 47 | } 48 | } 49 | } 50 | 51 | impl<'ctx> TypeRef for Type<'ctx> { 52 | fn type_ref(&self) -> LLVMTypeRef { 53 | match self { 54 | Self::Void(v) => v.type_ref(), 55 | Self::Int(i) => i.type_ref(), 56 | Self::Float(f) => f.type_ref(), 57 | Self::Pointer(p) => p.type_ref(), 58 | Self::Array(a) => a.type_ref(), 59 | Self::Vector(v) => v.type_ref(), 60 | Self::Struct(s) => s.type_ref(), 61 | Self::Function(f) => f.type_ref(), 62 | Self::Other(o) => o.type_ref(), 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/types/vector.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetElementType, LLVMGetVectorSize}; 2 | use llvm_sys::prelude::LLVMTypeRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::{FromLLVMType, TypeRef}; 7 | 8 | /// [Vector type](https://llvm.org/docs/LangRef.html#vector-type) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct VectorType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(VectorType); 13 | 14 | impl<'ctx> VectorType<'ctx> { 15 | /// Get the element type inside the vector type 16 | pub fn element_type(&self) -> Type<'ctx> { 17 | Type::from_llvm(unsafe { LLVMGetElementType(self.0) }) 18 | } 19 | 20 | /// Get the number of elements in the vector type 21 | pub fn num_elements(&self) -> usize { 22 | unsafe { LLVMGetVectorSize(self.0) as usize } 23 | } 24 | } 25 | 26 | impl<'ctx> AsType<'ctx> for VectorType<'ctx> { 27 | fn as_type(&self) -> Type<'ctx> { 28 | Type::Vector(self.clone()) 29 | } 30 | } 31 | 32 | impl<'ctx> TypeRef for VectorType<'ctx> { 33 | fn type_ref(&self) -> LLVMTypeRef { 34 | self.0 35 | } 36 | } 37 | 38 | impl<'ctx> FromLLVMType for VectorType<'ctx> { 39 | fn from_llvm(ptr: LLVMTypeRef) -> Self { 40 | Self(ptr, PhantomData) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/types/void.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMTypeRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::types::*; 5 | use crate::{FromLLVMType, TypeRef}; 6 | 7 | /// [Void type](https://llvm.org/docs/LangRef.html#void-type) 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct VoidType<'ctx>(LLVMTypeRef, PhantomData<&'ctx ()>); 10 | 11 | impl_send_sync!(VoidType); 12 | 13 | impl<'ctx> AsType<'ctx> for VoidType<'ctx> { 14 | fn as_type(&self) -> Type<'ctx> { 15 | Type::Void(self.clone()) 16 | } 17 | } 18 | 19 | impl_positional_type_ref!(VoidType, 0); 20 | 21 | impl_positional_from_llvm_type!(VoidType); -------------------------------------------------------------------------------- /src/utils/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_send_sync { 2 | ($id:ident) => { 3 | unsafe impl<'ctx> Send for $id<'ctx> {} 4 | 5 | unsafe impl<'ctx> Sync for $id<'ctx> {} 6 | } 7 | } -------------------------------------------------------------------------------- /src/utils/mdkind_ids.rs: -------------------------------------------------------------------------------- 1 | use libc::{c_char, c_uint}; 2 | use llvm_sys::core::*; 3 | use llvm_sys::prelude::*; 4 | 5 | pub fn mdkind_id(name: &str) -> c_uint { 6 | let len = name.len(); 7 | let ptr = name.as_ptr(); 8 | unsafe { LLVMGetMDKindID(ptr as *const c_char, len as c_uint) } 9 | } 10 | 11 | pub fn dbg_mdkind_id() -> c_uint { 12 | mdkind_id("dbg") 13 | } 14 | 15 | pub fn loop_mdkind_id() -> c_uint { 16 | mdkind_id("llvm.loop") 17 | } 18 | 19 | pub fn dbg_metadata(val: LLVMValueRef) -> Option { 20 | let ptr = unsafe { LLVMGetMetadata(val, dbg_mdkind_id()) }; 21 | if ptr.is_null() { 22 | None 23 | } else { 24 | Some(ptr) 25 | } 26 | } 27 | 28 | pub fn loop_metadata(val: LLVMValueRef) -> Option { 29 | let ptr = unsafe { LLVMGetMetadata(val, loop_mdkind_id()) }; 30 | if ptr.is_null() { 31 | None 32 | } else { 33 | Some(ptr) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/utils/mem_buffer.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMCreateMemoryBufferWithContentsOfFile, LLVMDisposeMemoryBuffer}; 2 | use llvm_sys::prelude::LLVMMemoryBufferRef; 3 | 4 | use super::support::{to_c_str, LLVMString}; 5 | 6 | use std::mem::MaybeUninit; 7 | use std::path::Path; 8 | use std::ptr; 9 | 10 | #[derive(Debug)] 11 | pub struct MemoryBuffer { 12 | pub(crate) memory_buffer: LLVMMemoryBufferRef, 13 | } 14 | 15 | impl MemoryBuffer { 16 | pub(crate) fn new(memory_buffer: LLVMMemoryBufferRef) -> Self { 17 | assert!(!memory_buffer.is_null()); 18 | 19 | MemoryBuffer { memory_buffer } 20 | } 21 | 22 | pub fn create_from_file(path: &Path) -> Result { 23 | let path = to_c_str(path.to_str().expect("Did not find a valid Unicode path string")); 24 | let mut memory_buffer = ptr::null_mut(); 25 | let mut err_string = MaybeUninit::uninit(); 26 | 27 | let return_code = unsafe { 28 | LLVMCreateMemoryBufferWithContentsOfFile( 29 | path.as_ptr() as *const ::libc::c_char, 30 | &mut memory_buffer, 31 | err_string.as_mut_ptr(), 32 | ) 33 | }; 34 | 35 | if return_code == 1 { 36 | let err_str = unsafe { err_string.assume_init() }; 37 | return Err(LLVMString::new(err_str).to_string()); 38 | } 39 | 40 | Ok(MemoryBuffer::new(memory_buffer)) 41 | } 42 | } 43 | 44 | impl Drop for MemoryBuffer { 45 | fn drop(&mut self) { 46 | unsafe { 47 | LLVMDisposeMemoryBuffer(self.memory_buffer); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | 4 | pub mod mem_buffer; 5 | pub mod support; 6 | mod string; 7 | pub mod mdkind_ids; 8 | pub mod traits; 9 | 10 | pub use string::*; 11 | -------------------------------------------------------------------------------- /src/utils/string.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::*; 3 | use std::ffi::CStr; 4 | use std::os::raw::c_char; 5 | 6 | pub unsafe fn raw_to_string(raw: *const c_char) -> String { 7 | let cstr = CStr::from_ptr(raw); 8 | cstr.to_str().expect("Failed to convert CStr").to_owned() 9 | } 10 | 11 | pub fn string_of_value(ptr: LLVMValueRef) -> String { 12 | let mut len = 0; 13 | let ptr = unsafe { LLVMGetValueName2(ptr, &mut len) }; 14 | unsafe { raw_to_string(ptr) } 15 | } 16 | 17 | pub fn string_of_type(ptr: LLVMTypeRef) -> String { 18 | let ptr = unsafe { LLVMGetStructName(ptr) }; 19 | unsafe { raw_to_string(ptr) } 20 | } 21 | 22 | pub fn string_of_debugloc_filename(ptr: LLVMValueRef) -> Option { 23 | let mut len = 0; 24 | let ptr = unsafe { LLVMGetDebugLocFilename(ptr, &mut len) }; 25 | if len == 0 || ptr.is_null() { 26 | None 27 | } else { 28 | Some(unsafe { raw_to_string(ptr) }) 29 | } 30 | } 31 | 32 | pub fn string_of_debugloc_directory(ptr: LLVMValueRef) -> Option { 33 | let mut len = 0; 34 | let ptr = unsafe { LLVMGetDebugLocDirectory(ptr, &mut len) }; 35 | if len == 0 || ptr.is_null() { 36 | None 37 | } else { 38 | Some(unsafe { raw_to_string(ptr) }) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/utils/support.rs: -------------------------------------------------------------------------------- 1 | use libc::c_char; 2 | use llvm_sys::core::LLVMDisposeMessage; 3 | 4 | use std::borrow::Cow; 5 | use std::error::Error; 6 | use std::ffi::{CStr, CString}; 7 | use std::fmt::{self, Debug, Display, Formatter}; 8 | use std::ops::Deref; 9 | 10 | #[derive(Eq)] 11 | pub struct LLVMString { 12 | pub(crate) ptr: *const c_char, 13 | } 14 | 15 | impl LLVMString { 16 | pub(crate) fn new(ptr: *const c_char) -> Self { 17 | LLVMString { ptr } 18 | } 19 | 20 | /// This is a convenience method for creating a Rust `String`, 21 | /// however; it *will* reallocate. `LLVMString` should be used 22 | /// as much as possible to save memory since it is allocated by 23 | /// LLVM. It's essentially a `CString` with a custom LLVM 24 | /// deallocator 25 | pub fn to_string(&self) -> String { 26 | (*self).to_string_lossy().into_owned() 27 | } 28 | } 29 | 30 | impl Deref for LLVMString { 31 | type Target = CStr; 32 | 33 | fn deref(&self) -> &Self::Target { 34 | unsafe { CStr::from_ptr(self.ptr) } 35 | } 36 | } 37 | 38 | impl Debug for LLVMString { 39 | fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 40 | write!(f, "{:?}", self.deref()) 41 | } 42 | } 43 | 44 | impl Display for LLVMString { 45 | fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { 46 | write!(f, "{:?}", self.deref()) 47 | } 48 | } 49 | 50 | impl PartialEq for LLVMString { 51 | fn eq(&self, other: &LLVMString) -> bool { 52 | **self == **other 53 | } 54 | } 55 | 56 | impl Error for LLVMString { 57 | fn description(&self) -> &str { 58 | self 59 | .to_str() 60 | .expect("Could not convert LLVMString to str (likely invalid unicode)") 61 | } 62 | 63 | fn cause(&self) -> Option<&dyn Error> { 64 | None 65 | } 66 | } 67 | 68 | impl Drop for LLVMString { 69 | fn drop(&mut self) { 70 | unsafe { 71 | LLVMDisposeMessage(self.ptr as *mut _); 72 | } 73 | } 74 | } 75 | 76 | /// This function takes in a Rust string and either: 77 | /// 78 | /// A) Finds a terminating null byte in the Rust string and can reference it directly like a C string. 79 | /// 80 | /// B) Finds no null byte and allocates a new C string based on the input Rust string. 81 | pub(crate) fn to_c_str<'s>(mut s: &'s str) -> Cow<'s, CStr> { 82 | if s.is_empty() { 83 | s = "\0"; 84 | } 85 | 86 | // Start from the end of the string as it's the most likely place to find a null byte 87 | if s.chars().rev().find(|&ch| ch == '\0').is_none() { 88 | return Cow::from(CString::new(s).expect("unreachable since null bytes are checked")); 89 | } 90 | 91 | unsafe { Cow::from(CStr::from_ptr(s.as_ptr() as *const _)) } 92 | } 93 | -------------------------------------------------------------------------------- /src/utils/traits.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMTypeRef, LLVMValueRef}; 2 | 3 | #[doc(hidden)] 4 | pub trait ValueRef { 5 | fn value_ref(&self) -> LLVMValueRef; 6 | } 7 | 8 | #[doc(hidden)] 9 | pub trait BlockRef { 10 | fn block_ref(&self) -> LLVMBasicBlockRef; 11 | } 12 | 13 | #[doc(hidden)] 14 | pub trait TypeRef { 15 | fn type_ref(&self) -> LLVMTypeRef; 16 | } 17 | 18 | #[doc(hidden)] 19 | pub trait FromLLVMValue: Sized { 20 | fn from_llvm(ptr: LLVMValueRef) -> Self; 21 | } 22 | 23 | #[doc(hidden)] 24 | pub trait FromLLVMBlock: Sized { 25 | fn from_llvm(ptr: LLVMBasicBlockRef) -> Self; 26 | } 27 | 28 | #[doc(hidden)] 29 | pub trait FromLLVMType: Sized { 30 | fn from_llvm(ptr: LLVMTypeRef) -> Self; 31 | } 32 | -------------------------------------------------------------------------------- /src/values/argument.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetParamParent; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// Function argument value 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct Argument<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(Argument); 13 | 14 | impl<'ctx> Argument<'ctx> { 15 | /// Get the parent function that this argument belongs to 16 | pub fn parent(&self) -> Function<'ctx> { 17 | Function::from_llvm(unsafe { LLVMGetParamParent(self.0) }) 18 | } 19 | 20 | /// Get the index of this argument wrt the parent function 21 | pub fn index(&self) -> usize { 22 | let parent = Function::from_llvm(unsafe { LLVMGetParamParent(self.0) }); 23 | let index = parent.arguments().iter().position(|&a| a.0 == self.0).unwrap(); 24 | index 25 | } 26 | } 27 | 28 | impl_positional_value_ref!(Argument, 0); 29 | 30 | impl_positional_from_llvm_value!(Argument); 31 | 32 | impl<'ctx> AsOperand<'ctx> for Argument<'ctx> { 33 | fn as_operand(&self) -> Operand<'ctx> { 34 | Operand::Argument(self.clone()) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/values/block.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::{LLVMBasicBlockRef, LLVMValueRef}; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// A block inside of function 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct Block<'ctx>(LLVMBasicBlockRef, PhantomData<&'ctx ()>); 11 | 12 | impl<'ctx> std::fmt::Debug for Block<'ctx> { 13 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 14 | f.debug_tuple("Block").field(&self.0).finish() 15 | } 16 | } 17 | 18 | impl_send_sync!(Block); 19 | 20 | impl<'ctx> GetDebugMetadata<'ctx> for Block<'ctx> {} 21 | 22 | impl<'ctx> Block<'ctx> { 23 | /// Get the function containing this block 24 | pub fn parent_function(&self) -> Function<'ctx> { 25 | let func_ptr = unsafe { LLVMGetBasicBlockParent(self.0) }; 26 | Function::from_llvm(func_ptr) 27 | } 28 | 29 | /// Iterate the instructions inside this block 30 | /// 31 | /// ``` 32 | /// for instr in blk.iter_instructions() { 33 | /// // Do things to instr... 34 | /// } 35 | /// ``` 36 | pub fn iter_instructions(&self) -> BlockInstructionIterator<'ctx> { 37 | let first_instr = unsafe { LLVMGetFirstInstruction(self.0) }; 38 | if first_instr.is_null() { 39 | BlockInstructionIterator { 40 | curr_instr: None, 41 | marker: PhantomData, 42 | } 43 | } else { 44 | BlockInstructionIterator { 45 | curr_instr: Some(first_instr), 46 | marker: PhantomData, 47 | } 48 | } 49 | } 50 | 51 | /// Get the first instruction inside this block 52 | pub fn first_instruction(&self) -> Option> { 53 | let first_instr = unsafe { LLVMGetFirstInstruction(self.0) }; 54 | if first_instr.is_null() { 55 | None 56 | } else { 57 | Some(Instruction::from_llvm(first_instr)) 58 | } 59 | } 60 | 61 | /// Get the last instruction inside this block 62 | pub fn last_instruction(&self) -> Option> { 63 | let last_instr = unsafe { LLVMGetLastInstruction(self.0) }; 64 | if last_instr.is_null() { 65 | None 66 | } else { 67 | Some(Instruction::from_llvm(last_instr)) 68 | } 69 | } 70 | 71 | /// Get the name of the block 72 | pub fn name(&self) -> String { 73 | unsafe { utils::raw_to_string(LLVMGetBasicBlockName(self.0)) } 74 | } 75 | 76 | /// Get the destination blocks that can be reached 77 | pub fn destination_blocks(&self) -> Vec> { 78 | if let Some(term) = self.last_instruction() { 79 | match term { 80 | Instruction::Branch(br) => br.destinations(), 81 | Instruction::Switch(sw) => sw.destinations(), 82 | _ => vec![], 83 | } 84 | } else { 85 | vec![] 86 | } 87 | } 88 | 89 | /// Checking if a block is a loop entry block 90 | /// 91 | /// Will iterate through all blocks inside the function and see if there is an 92 | /// loop based unconditional branch going to this block. This function is relying 93 | /// on the debug symbol `llvm.loop` 94 | pub fn is_loop_entry_block(&self) -> bool { 95 | for blk in self.parent_function().iter_blocks() { 96 | match blk.last_instruction() { 97 | Some(Instruction::Branch(BranchInstruction::Unconditional(un))) => { 98 | if let Some(is_loop_jump) = un.is_loop_jump() { 99 | if is_loop_jump && un.destination() == *self { 100 | return true; 101 | } 102 | } 103 | } 104 | _ => {} 105 | } 106 | } 107 | return false; 108 | } 109 | } 110 | 111 | impl<'ctx> BlockRef for Block<'ctx> { 112 | fn block_ref(&self) -> LLVMBasicBlockRef { 113 | self.0 114 | } 115 | } 116 | 117 | impl<'ctx> ValueRef for Block<'ctx> { 118 | fn value_ref(&self) -> LLVMValueRef { 119 | unsafe { LLVMBasicBlockAsValue(self.0) } 120 | } 121 | } 122 | 123 | impl<'ctx> FromLLVMBlock for Block<'ctx> { 124 | fn from_llvm(ptr: LLVMBasicBlockRef) -> Self { 125 | Block(ptr, PhantomData) 126 | } 127 | } 128 | 129 | #[doc(hidden)] 130 | pub struct BlockInstructionIterator<'ctx> { 131 | curr_instr: Option, 132 | marker: PhantomData<&'ctx ()>, 133 | } 134 | 135 | impl<'ctx> Iterator for BlockInstructionIterator<'ctx> { 136 | type Item = Instruction<'ctx>; 137 | 138 | fn next(&mut self) -> Option { 139 | match self.curr_instr { 140 | Some(curr_instr_ptr) => { 141 | let result = Some(Instruction::from_llvm(curr_instr_ptr)); 142 | let next_ptr = unsafe { LLVMGetNextInstruction(curr_instr_ptr) }; 143 | if next_ptr.is_null() { 144 | self.curr_instr = None; 145 | } else { 146 | self.curr_instr = Some(next_ptr); 147 | } 148 | result 149 | } 150 | None => None, 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/values/constant/array.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetArrayLength, LLVMGetOperand, LLVMTypeOf}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use super::Constant; 6 | use crate::types::*; 7 | use crate::values::*; 8 | use crate::*; 9 | 10 | /// [Array constant](https://llvm.org/docs/LangRef.html#complex-constants) 11 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 12 | pub struct ArrayConstant<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 13 | 14 | impl_send_sync!(ArrayConstant); 15 | 16 | impl<'ctx> GetType<'ctx> for ArrayConstant<'ctx> {} 17 | 18 | impl<'ctx> ArrayConstant<'ctx> { 19 | /// Get the number of elements used to construct the array constant 20 | pub fn num_elements(&self) -> usize { 21 | unsafe { LLVMGetArrayLength(LLVMTypeOf(self.0)) as usize } 22 | } 23 | 24 | /// Get the elements used to construct the array constant 25 | pub fn elements(&self) -> Vec> { 26 | (0..self.num_elements() as u32) 27 | .map(|i| Constant::from_llvm(unsafe { LLVMGetOperand(self.0, i) })) 28 | .collect() 29 | } 30 | 31 | /// Get directly the array type 32 | pub fn get_array_type(&self) -> ArrayType<'ctx> { 33 | ArrayType::from_llvm(self.get_type().type_ref()) 34 | } 35 | } 36 | 37 | impl_positional_value_ref!(ArrayConstant, 0); 38 | 39 | impl_positional_from_llvm_value!(ArrayConstant); 40 | 41 | impl<'ctx> AsConstant<'ctx> for ArrayConstant<'ctx> { 42 | fn as_constant(&self) -> Constant<'ctx> { 43 | Constant::Array(self.clone()) 44 | } 45 | } 46 | 47 | impl_as_operand_for_constant!(ArrayConstant); -------------------------------------------------------------------------------- /src/values/constant/block_addr.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Block Address](https://llvm.org/docs/LangRef.html#addresses-of-basic-blocks) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct BlockAddress<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(BlockAddress); 13 | 14 | impl<'ctx> GetType<'ctx> for BlockAddress<'ctx> {} 15 | 16 | impl<'ctx> BlockAddress<'ctx> { 17 | pub fn function(&self) -> Function<'ctx> { 18 | Function::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 19 | } 20 | 21 | pub fn block(&self) -> Block<'ctx> { 22 | Block::from_llvm(unsafe { LLVMValueAsBasicBlock(LLVMGetOperand(self.0, 1)) }) 23 | } 24 | } 25 | 26 | impl_positional_value_ref!(BlockAddress, 0); 27 | 28 | impl_positional_from_llvm_value!(BlockAddress); 29 | 30 | impl<'ctx> AsConstant<'ctx> for BlockAddress<'ctx> { 31 | fn as_constant(&self) -> Constant<'ctx> { 32 | Constant::BlockAddress(self.clone()) 33 | } 34 | } 35 | 36 | impl_as_operand_for_constant!(BlockAddress); 37 | -------------------------------------------------------------------------------- /src/values/constant/const_expr/binary.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetConstOpcode, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// Binary constant expression 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct BinaryConstExpr<'ctx>(BinaryOpcode, LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(BinaryConstExpr); 13 | 14 | impl<'ctx> BinaryConstExpr<'ctx> { 15 | /// Get the opcode 16 | pub fn opcode(&self) -> BinaryOpcode { 17 | self.0 18 | } 19 | 20 | pub fn op0(&self) -> Constant<'ctx> { 21 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 22 | } 23 | 24 | pub fn op1(&self) -> Constant<'ctx> { 25 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 1) }) 26 | } 27 | } 28 | 29 | impl<'ctx> GetType<'ctx> for BinaryConstExpr<'ctx> {} 30 | 31 | impl<'ctx> ConstExprTrait<'ctx> for BinaryConstExpr<'ctx> {} 32 | 33 | impl_positional_value_ref!(BinaryConstExpr, 1); 34 | 35 | impl_op_from_llvm_value!(BinaryConstExpr, BinaryOpcode, LLVMGetConstOpcode); 36 | 37 | impl<'ctx> AsConstExpr<'ctx> for BinaryConstExpr<'ctx> { 38 | fn as_const_expr(&self) -> ConstExpr<'ctx> { 39 | ConstExpr::Binary(self.clone()) 40 | } 41 | } 42 | 43 | impl_const_expr_debug!(BinaryConstExpr); 44 | 45 | impl_as_constant_and_as_operand_for_const_expr!(BinaryConstExpr); -------------------------------------------------------------------------------- /src/values/constant/const_expr/const_expr.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetConstOpcode; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMOpcode; 4 | 5 | use super::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Constant expression](https://llvm.org/docs/LangRef.html#constant-expressions) 10 | /// 11 | /// Super class for all constant expressions 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 13 | pub enum ConstExpr<'ctx> { 14 | Binary(BinaryConstExpr<'ctx>), 15 | Unary(UnaryConstExpr<'ctx>), 16 | ICmp(ICmpConstExpr<'ctx>), 17 | FCmp(FCmpConstExpr<'ctx>), 18 | GetElementPtr(GetElementPtrConstExpr<'ctx>), 19 | Other(GenericValue<'ctx>), 20 | } 21 | 22 | impl<'ctx> GetType<'ctx> for ConstExpr<'ctx> {} 23 | 24 | impl<'ctx> ConstExprTrait<'ctx> for ConstExpr<'ctx> {} 25 | 26 | impl<'ctx> FromLLVMValue for ConstExpr<'ctx> { 27 | fn from_llvm(ptr: LLVMValueRef) -> Self { 28 | use LLVMOpcode::*; 29 | match unsafe { LLVMGetConstOpcode(ptr) } { 30 | LLVMGetElementPtr => Self::GetElementPtr(GetElementPtrConstExpr::from_llvm(ptr)), 31 | LLVMICmp => Self::ICmp(ICmpConstExpr::from_llvm(ptr)), 32 | LLVMFCmp => Self::FCmp(FCmpConstExpr::from_llvm(ptr)), 33 | o if BinaryOpcode::from_llvm(o).is_some() => Self::Binary(BinaryConstExpr::from_llvm(ptr)), 34 | o if UnaryOpcode::from_llvm(o).is_some() => Self::Unary(UnaryConstExpr::from_llvm(ptr)), 35 | _ => Self::Other(GenericValue::from_llvm(ptr)), 36 | } 37 | } 38 | } 39 | 40 | impl<'ctx> ValueRef for ConstExpr<'ctx> { 41 | fn value_ref(&self) -> LLVMValueRef { 42 | match self { 43 | Self::Binary(b) => b.value_ref(), 44 | Self::Unary(u) => u.value_ref(), 45 | Self::GetElementPtr(g) => g.value_ref(), 46 | Self::ICmp(i) => i.value_ref(), 47 | Self::FCmp(f) => f.value_ref(), 48 | Self::Other(g) => g.value_ref(), 49 | } 50 | } 51 | } 52 | 53 | impl<'ctx> AsConstExpr<'ctx> for ConstExpr<'ctx> { 54 | fn as_const_expr(&self) -> ConstExpr<'ctx> { 55 | self.clone() 56 | } 57 | } 58 | 59 | impl_as_constant_and_as_operand_for_const_expr!(ConstExpr); -------------------------------------------------------------------------------- /src/values/constant/const_expr/fcmp.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetFCmpPredicate, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// FCmp constant expression 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct FCmpConstExpr<'ctx>(FCmpPredicate, LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(FCmpConstExpr); 13 | 14 | impl<'ctx> FCmpConstExpr<'ctx> { 15 | /// Get the fcmp predicate 16 | pub fn predicate(&self) -> FCmpPredicate { 17 | self.0 18 | } 19 | 20 | /// Get the lhs operand in constant 21 | pub fn op0(&self) -> Constant<'ctx> { 22 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 23 | } 24 | 25 | /// Get the rhs operand in constant 26 | pub fn op1(&self) -> Constant<'ctx> { 27 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 1) }) 28 | } 29 | } 30 | 31 | impl<'ctx> GetType<'ctx> for FCmpConstExpr<'ctx> {} 32 | 33 | impl<'ctx> ConstExprTrait<'ctx> for FCmpConstExpr<'ctx> {} 34 | 35 | impl_cmp_from_llvm_value!(FCmpConstExpr, FCmpPredicate, LLVMGetFCmpPredicate); 36 | 37 | impl_positional_value_ref!(FCmpConstExpr, 1); 38 | 39 | impl<'ctx> AsConstExpr<'ctx> for FCmpConstExpr<'ctx> { 40 | fn as_const_expr(&self) -> ConstExpr<'ctx> { 41 | ConstExpr::FCmp(self.clone()) 42 | } 43 | } 44 | 45 | impl_const_expr_debug!(FCmpConstExpr); 46 | 47 | impl_as_constant_and_as_operand_for_const_expr!(FCmpConstExpr); -------------------------------------------------------------------------------- /src/values/constant/const_expr/gep.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMGetValueKind}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMValueKind; 4 | use std::marker::PhantomData; 5 | 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// Get element pointer constant expression 10 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct GetElementPtrConstExpr<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_send_sync!(GetElementPtrConstExpr); 14 | 15 | impl<'ctx> GetElementPtrConstExpr<'ctx> { 16 | /// Get the base location constant 17 | pub fn location(&self) -> Constant<'ctx> { 18 | Constant::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 19 | } 20 | 21 | /// Get the number of indices used to get the element pointer 22 | pub fn num_indices(&self) -> usize { 23 | (unsafe { LLVMGetNumOperands(self.0) as usize }) - 1 24 | } 25 | 26 | /// Get the indices in Constant Vector format 27 | pub fn indices(&self) -> Vec> { 28 | (0..self.num_indices() as u32) 29 | .map(|i| Constant::from_llvm(unsafe { LLVMGetOperand(self.0, i + 1) })) 30 | .collect() 31 | } 32 | 33 | /// Get the indices in Integer Constant Vector format, since the constants used 34 | /// in a GEP Const Expr can only be integer constant 35 | pub fn int_indices(&self) -> Vec> { 36 | (0..self.num_indices() as u32) 37 | .map(|i| { 38 | let operand = unsafe { LLVMGetOperand(self.0, i + 1) }; 39 | assert_eq!( 40 | unsafe { LLVMGetValueKind(operand) }, 41 | LLVMValueKind::LLVMConstantIntValueKind 42 | ); 43 | IntConstant::from_llvm(operand) 44 | }) 45 | .collect() 46 | } 47 | } 48 | 49 | impl<'ctx> GetType<'ctx> for GetElementPtrConstExpr<'ctx> {} 50 | 51 | impl<'ctx> ConstExprTrait<'ctx> for GetElementPtrConstExpr<'ctx> {} 52 | 53 | impl_positional_value_ref!(GetElementPtrConstExpr, 0); 54 | 55 | impl_positional_from_llvm_value!(GetElementPtrConstExpr); 56 | 57 | impl<'ctx> AsConstExpr<'ctx> for GetElementPtrConstExpr<'ctx> { 58 | fn as_const_expr(&self) -> ConstExpr<'ctx> { 59 | ConstExpr::GetElementPtr(self.clone()) 60 | } 61 | } 62 | 63 | impl_const_expr_debug!(GetElementPtrConstExpr); 64 | 65 | impl_as_constant_and_as_operand_for_const_expr!(GetElementPtrConstExpr); -------------------------------------------------------------------------------- /src/values/constant/const_expr/icmp.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetICmpPredicate, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// ICmp constant expression 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct ICmpConstExpr<'ctx>(ICmpPredicate, LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(ICmpConstExpr); 13 | 14 | impl<'ctx> ICmpConstExpr<'ctx> { 15 | /// Get the icmp predicate 16 | pub fn predicate(&self) -> ICmpPredicate { 17 | self.0 18 | } 19 | 20 | /// Get the lhs operand 21 | pub fn op0(&self) -> Constant<'ctx> { 22 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 23 | } 24 | 25 | /// Get the rhs operand 26 | pub fn op1(&self) -> Constant<'ctx> { 27 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 1) }) 28 | } 29 | } 30 | 31 | impl<'ctx> GetType<'ctx> for ICmpConstExpr<'ctx> {} 32 | 33 | impl<'ctx> ConstExprTrait<'ctx> for ICmpConstExpr<'ctx> {} 34 | 35 | impl_cmp_from_llvm_value!(ICmpConstExpr, ICmpPredicate, LLVMGetICmpPredicate); 36 | 37 | impl_positional_value_ref!(ICmpConstExpr, 1); 38 | 39 | impl<'ctx> AsConstExpr<'ctx> for ICmpConstExpr<'ctx> { 40 | fn as_const_expr(&self) -> ConstExpr<'ctx> { 41 | ConstExpr::ICmp(self.clone()) 42 | } 43 | } 44 | 45 | impl_const_expr_debug!(ICmpConstExpr); 46 | 47 | impl_as_constant_and_as_operand_for_const_expr!(ICmpConstExpr); -------------------------------------------------------------------------------- /src/values/constant/const_expr/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_const_expr_debug { 2 | ($id:ident) => { 3 | impl<'ctx> std::fmt::Debug for $id<'ctx> { 4 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 5 | f.debug_tuple(stringify!($id)).field(&self.to_string()).finish() 6 | } 7 | } 8 | }; 9 | } 10 | 11 | macro_rules! impl_as_constant_and_as_operand_for_const_expr { 12 | ($id:ident) => { 13 | impl<'ctx> AsConstant<'ctx> for $id<'ctx> { 14 | fn as_constant(&self) -> Constant<'ctx> { 15 | Constant::ConstExpr(self.as_const_expr()) 16 | } 17 | } 18 | 19 | impl<'ctx> AsOperand<'ctx> for $id<'ctx> { 20 | fn as_operand(&self) -> Operand<'ctx> { 21 | Operand::Constant(self.as_constant()) 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/values/constant/const_expr/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | pub use macros::*; 4 | 5 | mod traits; 6 | mod const_expr; 7 | mod binary; 8 | mod unary; 9 | mod gep; 10 | mod icmp; 11 | mod fcmp; 12 | 13 | pub use traits::*; 14 | pub use const_expr::*; 15 | pub use binary::*; 16 | pub use unary::*; 17 | pub use gep::*; 18 | pub use icmp::*; 19 | pub use fcmp::*; 20 | -------------------------------------------------------------------------------- /src/values/constant/const_expr/traits.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | 3 | use crate::*; 4 | use crate::values::*; 5 | 6 | pub trait ConstExprTrait<'ctx>: ValueRef { 7 | /// Get the number of operands used in this instruction 8 | fn num_operands(&self) -> usize { 9 | unsafe { LLVMGetNumOperands(self.value_ref()) as usize } 10 | } 11 | 12 | /// Get the operand at a given index 13 | fn operand(&self, index: usize) -> Option> { 14 | if index < self.num_operands() { 15 | Some(Constant::from_llvm(unsafe { 16 | LLVMGetOperand(self.value_ref(), index as u32) 17 | })) 18 | } else { 19 | None 20 | } 21 | } 22 | 23 | /// Get the string representation of the instruction 24 | fn to_string(&self) -> String { 25 | unsafe { crate::utils::raw_to_string(LLVMPrintValueToString(self.value_ref())) } 26 | } 27 | } 28 | 29 | /// Turn constant expression subclass into a ConstExpr enum 30 | pub trait AsConstExpr<'ctx> { 31 | fn as_const_expr(&self) -> ConstExpr<'ctx>; 32 | } 33 | -------------------------------------------------------------------------------- /src/values/constant/const_expr/unary.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetConstOpcode, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// Unary constant expression 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct UnaryConstExpr<'ctx>(UnaryOpcode, LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(UnaryConstExpr); 13 | 14 | impl<'ctx> UnaryConstExpr<'ctx> { 15 | /// Get the unary opcode 16 | pub fn opcode(&self) -> UnaryOpcode { 17 | self.0 18 | } 19 | 20 | /// Get the operand constant 21 | pub fn op0(&self) -> Constant<'ctx> { 22 | Constant::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 23 | } 24 | } 25 | 26 | impl<'ctx> GetType<'ctx> for UnaryConstExpr<'ctx> {} 27 | 28 | impl<'ctx> ConstExprTrait<'ctx> for UnaryConstExpr<'ctx> {} 29 | 30 | impl_op_from_llvm_value!(UnaryConstExpr, UnaryOpcode, LLVMGetConstOpcode); 31 | 32 | impl_positional_value_ref!(UnaryConstExpr, 1); 33 | 34 | impl<'ctx> AsConstExpr<'ctx> for UnaryConstExpr<'ctx> { 35 | fn as_const_expr(&self) -> ConstExpr<'ctx> { 36 | ConstExpr::Unary(self.clone()) 37 | } 38 | } 39 | 40 | impl_const_expr_debug!(UnaryConstExpr); 41 | 42 | impl_as_constant_and_as_operand_for_const_expr!(UnaryConstExpr); -------------------------------------------------------------------------------- /src/values/constant/constant.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetValueKind; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMValueKind; 4 | 5 | use super::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Constants](https://llvm.org/docs/LangRef.html#constants) 10 | /// 11 | /// Int, Float, and Null are [Simple Constants](https://llvm.org/docs/LangRef.html#simple-constants) 12 | /// 13 | /// Struct, Array, and Vector are [Complex Constants](https://llvm.org/docs/LangRef.html#complex-constants) 14 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 15 | pub enum Constant<'ctx> { 16 | Int(IntConstant<'ctx>), 17 | Float(FloatConstant<'ctx>), 18 | Null(NullConstant<'ctx>), 19 | Struct(StructConstant<'ctx>), 20 | Array(ArrayConstant<'ctx>), 21 | Vector(VectorConstant<'ctx>), 22 | BlockAddress(BlockAddress<'ctx>), 23 | Undef(Undef<'ctx>), 24 | Global(Global<'ctx>), 25 | Function(Function<'ctx>), 26 | ConstExpr(ConstExpr<'ctx>), 27 | Other(GenericValue<'ctx>), 28 | } 29 | 30 | impl<'ctx> Constant<'ctx> { 31 | /// Turn constant into an operand 32 | pub fn as_operand(&self) -> Operand<'ctx> { 33 | Operand::Constant(*self) 34 | } 35 | } 36 | 37 | impl<'ctx> GetType<'ctx> for Constant<'ctx> {} 38 | 39 | impl<'ctx> ValueRef for Constant<'ctx> { 40 | fn value_ref(&self) -> LLVMValueRef { 41 | match self { 42 | Self::Int(ic) => ic.value_ref(), 43 | Self::Float(fc) => fc.value_ref(), 44 | Self::Null(nc) => nc.value_ref(), 45 | Self::Struct(sc) => sc.value_ref(), 46 | Self::Array(ac) => ac.value_ref(), 47 | Self::Vector(vc) => vc.value_ref(), 48 | Self::BlockAddress(ba) => ba.value_ref(), 49 | Self::Undef(ud) => ud.value_ref(), 50 | Self::Global(gc) => gc.value_ref(), 51 | Self::Function(fc) => fc.value_ref(), 52 | Self::ConstExpr(cec) => cec.value_ref(), 53 | Self::Other(oc) => oc.value_ref(), 54 | } 55 | } 56 | } 57 | 58 | impl<'ctx> FromLLVMValue for Constant<'ctx> { 59 | fn from_llvm(ptr: LLVMValueRef) -> Self { 60 | use LLVMValueKind::*; 61 | match unsafe { LLVMGetValueKind(ptr) } { 62 | LLVMConstantIntValueKind => Self::Int(IntConstant::from_llvm(ptr)), 63 | LLVMConstantFPValueKind => Self::Float(FloatConstant::from_llvm(ptr)), 64 | LLVMConstantPointerNullValueKind => Self::Null(NullConstant::from_llvm(ptr)), 65 | LLVMConstantStructValueKind => Self::Struct(StructConstant::from_llvm(ptr)), 66 | LLVMConstantArrayValueKind => Self::Array(ArrayConstant::from_llvm(ptr)), 67 | LLVMConstantDataArrayValueKind => Self::Array(ArrayConstant::from_llvm(ptr)), 68 | LLVMConstantVectorValueKind => Self::Vector(VectorConstant::from_llvm(ptr)), 69 | LLVMConstantDataVectorValueKind => Self::Vector(VectorConstant::from_llvm(ptr)), 70 | LLVMBlockAddressValueKind => Self::BlockAddress(BlockAddress::from_llvm(ptr)), 71 | LLVMUndefValueValueKind => Self::Undef(Undef::from_llvm(ptr)), 72 | LLVMGlobalIFuncValueKind | LLVMFunctionValueKind => Self::Function(Function::from_llvm(ptr)), 73 | LLVMGlobalAliasValueKind | LLVMGlobalVariableValueKind => Self::Global(Global::from_llvm(ptr)), 74 | LLVMConstantExprValueKind => Self::ConstExpr(ConstExpr::from_llvm(ptr)), 75 | _ => Self::Other(GenericValue::from_llvm(ptr)), 76 | } 77 | } 78 | } 79 | 80 | impl<'ctx> AsConstant<'ctx> for Constant<'ctx> { 81 | fn as_constant(&self) -> Constant<'ctx> { 82 | self.clone() 83 | } 84 | } 85 | 86 | impl_as_operand_for_constant!(Constant); 87 | -------------------------------------------------------------------------------- /src/values/constant/float.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMConstRealGetDouble; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Float constant](https://llvm.org/docs/LangRef.html#simple-constants) 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct FloatConstant<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_send_sync!(FloatConstant); 14 | 15 | impl<'ctx> GetType<'ctx> for FloatConstant<'ctx> {} 16 | 17 | impl<'ctx> FloatConstant<'ctx> { 18 | /// Get the floating point value in double form (f64) 19 | pub fn double_value(&self) -> f64 { 20 | unsafe { 21 | let mut b = 0; 22 | let b_ptr: *mut std::os::raw::c_int = &mut b; 23 | LLVMConstRealGetDouble(self.0, b_ptr) 24 | } 25 | } 26 | 27 | /// Get directly the float type 28 | pub fn get_float_type(&self) -> FloatType<'ctx> { 29 | FloatType::from_llvm(self.get_type().type_ref()) 30 | } 31 | } 32 | 33 | impl_positional_value_ref!(FloatConstant, 0); 34 | 35 | impl_positional_from_llvm_value!(FloatConstant); 36 | 37 | impl<'ctx> AsConstant<'ctx> for FloatConstant<'ctx> { 38 | fn as_constant(&self) -> Constant<'ctx> { 39 | Constant::Float(self.clone()) 40 | } 41 | } 42 | 43 | impl_as_operand_for_constant!(FloatConstant); 44 | -------------------------------------------------------------------------------- /src/values/constant/int.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMConstIntGetSExtValue, LLVMConstIntGetZExtValue}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Integer constant](https://llvm.org/docs/LangRef.html#simple-constants) 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct IntConstant<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_send_sync!(IntConstant); 14 | 15 | impl<'ctx> GetType<'ctx> for IntConstant<'ctx> {} 16 | 17 | impl<'ctx> IntConstant<'ctx> { 18 | /// Zero extended value (u64) 19 | pub fn zext_value(&self) -> u64 { 20 | let val = unsafe { LLVMConstIntGetZExtValue(self.0) }; 21 | val as u64 22 | } 23 | 24 | /// Sign extended value (i64) 25 | pub fn sext_value(&self) -> i64 { 26 | let val = unsafe { LLVMConstIntGetSExtValue(self.0) }; 27 | val as i64 28 | } 29 | 30 | /// Get directly the integer type 31 | pub fn get_int_type(&self) -> IntType<'ctx> { 32 | IntType::from_llvm(self.get_type().type_ref()) 33 | } 34 | } 35 | 36 | impl_positional_value_ref!(IntConstant, 0); 37 | 38 | impl_positional_from_llvm_value!(IntConstant); 39 | 40 | impl<'ctx> AsConstant<'ctx> for IntConstant<'ctx> { 41 | fn as_constant(&self) -> Constant<'ctx> { 42 | Constant::Int(self.clone()) 43 | } 44 | } 45 | 46 | impl_as_operand_for_constant!(IntConstant); 47 | -------------------------------------------------------------------------------- /src/values/constant/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_as_operand_for_constant { 2 | ($id:ident) => { 3 | impl<'ctx> AsOperand<'ctx> for $id<'ctx> { 4 | fn as_operand(&self) -> Operand<'ctx> { 5 | Operand::Constant(self.as_constant()) 6 | } 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/values/constant/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | pub use macros::*; 4 | 5 | #[macro_use] 6 | mod const_expr; 7 | pub use const_expr::*; 8 | 9 | mod traits; 10 | mod block_addr; 11 | mod constant; 12 | mod int; 13 | mod float; 14 | mod null; 15 | mod struc; 16 | mod array; 17 | mod vector; 18 | mod undef; 19 | 20 | pub use traits::*; 21 | pub use block_addr::*; 22 | pub use constant::*; 23 | pub use int::*; 24 | pub use float::*; 25 | pub use null::*; 26 | pub use struc::*; 27 | pub use array::*; 28 | pub use vector::*; 29 | pub use undef::*; 30 | -------------------------------------------------------------------------------- /src/values/constant/null.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::types::*; 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Null constant](https://llvm.org/docs/LangRef.html#simple-constants) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct NullConstant<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_send_sync!(NullConstant); 13 | 14 | impl<'ctx> GetType<'ctx> for NullConstant<'ctx> {} 15 | 16 | impl<'ctx> NullConstant<'ctx> { 17 | /// Get directly the pointer type of this null constant 18 | pub fn get_pointer_type(&self) -> PointerType<'ctx> { 19 | PointerType::from_llvm(self.get_type().type_ref()) 20 | } 21 | } 22 | 23 | impl_positional_value_ref!(NullConstant, 0); 24 | 25 | impl_positional_from_llvm_value!(NullConstant); 26 | 27 | impl<'ctx> AsConstant<'ctx> for NullConstant<'ctx> { 28 | fn as_constant(&self) -> Constant<'ctx> { 29 | Constant::Null(self.clone()) 30 | } 31 | } 32 | 33 | impl_as_operand_for_constant!(NullConstant); 34 | -------------------------------------------------------------------------------- /src/values/constant/struc.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMCountStructElementTypes, LLVMGetOperand, LLVMTypeOf}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Struct constant](https://llvm.org/docs/LangRef.html#complex-constants) 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct StructConstant<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_send_sync!(StructConstant); 14 | 15 | impl<'ctx> GetType<'ctx> for StructConstant<'ctx> {} 16 | 17 | impl<'ctx> StructConstant<'ctx> { 18 | /// Get the number of elements used to construct the struct 19 | pub fn num_elements(&self) -> usize { 20 | unsafe { LLVMCountStructElementTypes(LLVMTypeOf(self.0)) as usize } 21 | } 22 | 23 | /// Get the elements used to construct the struct 24 | pub fn elements(&self) -> Vec> { 25 | (0..self.num_elements() as u32) 26 | .map(|i| Constant::from_llvm(unsafe { LLVMGetOperand(self.0, i) })) 27 | .collect() 28 | } 29 | 30 | /// Get directly the struct type 31 | pub fn get_struct_type(&self) -> StructType<'ctx> { 32 | StructType::from_llvm(self.get_type().type_ref()) 33 | } 34 | } 35 | 36 | impl_positional_value_ref!(StructConstant, 0); 37 | 38 | impl_positional_from_llvm_value!(StructConstant); 39 | 40 | impl<'ctx> AsConstant<'ctx> for StructConstant<'ctx> { 41 | fn as_constant(&self) -> Constant<'ctx> { 42 | Constant::Struct(self.clone()) 43 | } 44 | } 45 | 46 | impl_as_operand_for_constant!(StructConstant); 47 | -------------------------------------------------------------------------------- /src/values/constant/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::values::*; 2 | 3 | /// Turn constant subclass into a constant enum 4 | pub trait AsConstant<'ctx> { 5 | fn as_constant(&self) -> Constant<'ctx>; 6 | } 7 | -------------------------------------------------------------------------------- /src/values/constant/undef.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// [Undefined value](https://llvm.org/docs/LangRef.html#undefined-values) 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct Undef<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_send_sync!(Undef); 12 | 13 | impl<'ctx> GetType<'ctx> for Undef<'ctx> {} 14 | 15 | impl_positional_value_ref!(Undef, 0); 16 | 17 | impl_positional_from_llvm_value!(Undef); 18 | 19 | impl<'ctx> AsConstant<'ctx> for Undef<'ctx> { 20 | fn as_constant(&self) -> Constant<'ctx> { 21 | Constant::Undef(self.clone()) 22 | } 23 | } 24 | 25 | impl_as_operand_for_constant!(Undef); 26 | -------------------------------------------------------------------------------- /src/values/constant/vector.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Vector Constant](https://llvm.org/docs/LangRef.html#complex-constants) 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct VectorConstant<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_send_sync!(VectorConstant); 14 | 15 | impl<'ctx> GetType<'ctx> for VectorConstant<'ctx> {} 16 | 17 | impl<'ctx> VectorConstant<'ctx> { 18 | /// Get the number of elements inside this constant vector 19 | pub fn num_elements(&self) -> usize { 20 | unsafe { LLVMGetNumOperands(self.0) as usize } 21 | } 22 | 23 | /// Get the constant elements in a vector 24 | pub fn elements(&self) -> Vec> { 25 | (0..self.num_elements() as u32) 26 | .map(|i| Constant::from_llvm(unsafe { LLVMGetOperand(self.0, i) })) 27 | .collect() 28 | } 29 | 30 | /// Since vector constant definitely has vector type, we have a function to 31 | /// get directly the vector type 32 | pub fn get_vector_type(&self) -> VectorType<'ctx> { 33 | VectorType::from_llvm(self.get_type().type_ref()) 34 | } 35 | } 36 | 37 | impl_positional_value_ref!(VectorConstant, 0); 38 | 39 | impl_positional_from_llvm_value!(VectorConstant); 40 | 41 | impl<'ctx> AsConstant<'ctx> for VectorConstant<'ctx> { 42 | fn as_constant(&self) -> Constant<'ctx> { 43 | Constant::Vector(self.clone()) 44 | } 45 | } 46 | 47 | impl_as_operand_for_constant!(VectorConstant); 48 | -------------------------------------------------------------------------------- /src/values/generic.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::utils::*; 5 | use crate::*; 6 | 7 | /// A placeholder value; used when the value kind is not supported yet 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct GenericValue<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_send_sync!(GenericValue); 12 | 13 | impl<'ctx> GenericValue<'ctx> { 14 | pub(crate) fn new(ptr: LLVMValueRef) -> Self { 15 | Self(ptr, PhantomData) 16 | } 17 | 18 | /// Get the name of the generic value. It might or might not have one 19 | pub fn name(&self) -> Option { 20 | let s = string_of_value(self.0); 21 | if s.len() == 0 { 22 | None 23 | } else { 24 | Some(s) 25 | } 26 | } 27 | } 28 | 29 | impl_positional_value_ref!(GenericValue, 0); 30 | 31 | impl_positional_from_llvm_value!(GenericValue); 32 | -------------------------------------------------------------------------------- /src/values/global.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMValueKind; 4 | use std::marker::PhantomData; 5 | 6 | use crate::utils::string_of_value; 7 | use crate::values::*; 8 | use crate::*; 9 | 10 | /// Global container enum 11 | /// 12 | /// A global could be either a [normal variable](https://llvm.org/docs/LangRef.html#global-variables) 13 | /// or an [alias](https://llvm.org/docs/LangRef.html#aliases) 14 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 15 | pub enum Global<'ctx> { 16 | /// Global variable 17 | Variable(GlobalVariable<'ctx>), 18 | /// Global alias 19 | Alias(GlobalAlias<'ctx>), 20 | } 21 | 22 | pub trait GlobalValueTrait<'ctx>: ValueRef { 23 | /// Get the name of this global 24 | fn name(&self) -> String { 25 | string_of_value(self.value_ref()) 26 | } 27 | 28 | /// Global value can be turned into a Global enum 29 | fn as_global(&self) -> Global<'ctx>; 30 | } 31 | 32 | /// A global variable has a type 33 | impl<'ctx> GetType<'ctx> for Global<'ctx> {} 34 | 35 | /// Global variable implements the trait for global value 36 | impl<'ctx> GlobalValueTrait<'ctx> for Global<'ctx> { 37 | fn as_global(&self) -> Self { self.clone() } 38 | } 39 | 40 | impl<'ctx> Global<'ctx> { 41 | /// Check if a global variable is alias 42 | pub fn is_alias(&self) -> bool { 43 | match self { 44 | Self::Variable(_) => false, 45 | _ => true, 46 | } 47 | } 48 | 49 | /// Get the aliasee 50 | pub fn aliasee(&self) -> Option> { 51 | match self { 52 | Self::Alias(a) => Some(a.aliasee()), 53 | _ => None, 54 | } 55 | } 56 | } 57 | 58 | impl<'ctx> FromLLVMValue for Global<'ctx> { 59 | fn from_llvm(ptr: LLVMValueRef) -> Self { 60 | use LLVMValueKind::*; 61 | match unsafe { LLVMGetValueKind(ptr) } { 62 | LLVMGlobalVariableValueKind => Self::Variable(GlobalVariable::from_llvm(ptr)), 63 | LLVMGlobalAliasValueKind => Self::Alias(GlobalAlias::from_llvm(ptr)), 64 | x => panic!("Not global variable kind {:?}", x), 65 | } 66 | } 67 | } 68 | 69 | impl<'ctx> ValueRef for Global<'ctx> { 70 | fn value_ref(&self) -> LLVMValueRef { 71 | match self { 72 | Self::Variable(v) => v.value_ref(), 73 | Self::Alias(a) => a.value_ref(), 74 | } 75 | } 76 | } 77 | 78 | /// We can turn a Global into a Global Alias Constant 79 | impl<'ctx> AsConstant<'ctx> for Global<'ctx> { 80 | fn as_constant(&self) -> Constant<'ctx> { 81 | Constant::Global(self.clone()) 82 | } 83 | } 84 | 85 | impl_as_operand_for_constant!(Global); 86 | 87 | /// [Global variable](https://llvm.org/docs/LangRef.html#global-variables) 88 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 89 | pub struct GlobalVariable<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 90 | 91 | impl<'ctx> std::fmt::Debug for GlobalVariable<'ctx> { 92 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 93 | f.debug_tuple("GlobalVariable").field(&self.name()).finish() 94 | } 95 | } 96 | 97 | impl_send_sync!(GlobalVariable); 98 | 99 | /// A global value has a type 100 | impl<'ctx> GetType<'ctx> for GlobalVariable<'ctx> {} 101 | 102 | /// Global value implements the trait for global value 103 | impl<'ctx> GlobalValueTrait<'ctx> for GlobalVariable<'ctx> { 104 | fn as_global(&self) -> Global<'ctx> { 105 | Global::Variable(self.clone()) 106 | } 107 | } 108 | 109 | impl_positional_value_ref!(GlobalVariable, 0); 110 | 111 | impl_positional_from_llvm_value!(GlobalVariable); 112 | 113 | /// We can turn Global Variable into a Global Alias Constant 114 | impl<'ctx> AsConstant<'ctx> for GlobalVariable<'ctx> { 115 | fn as_constant(&self) -> Constant<'ctx> { 116 | Constant::Global(Global::Variable(self.clone())) 117 | } 118 | } 119 | 120 | impl_as_operand_for_constant!(GlobalVariable); 121 | 122 | /// [Global alias](https://llvm.org/docs/LangRef.html#aliases) 123 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 124 | pub struct GlobalAlias<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 125 | 126 | impl<'ctx> std::fmt::Debug for GlobalAlias<'ctx> { 127 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 128 | f.debug_tuple("GlobalAlias").field(&self.name()).finish() 129 | } 130 | } 131 | 132 | impl_send_sync!(GlobalAlias); 133 | 134 | /// A global alias has a type 135 | impl<'ctx> GetType<'ctx> for GlobalAlias<'ctx> {} 136 | 137 | /// Global alias implements the trait for global value 138 | impl<'ctx> GlobalValueTrait<'ctx> for GlobalAlias<'ctx> { 139 | fn as_global(&self) -> Global<'ctx> { 140 | Global::Alias(self.clone()) 141 | } 142 | } 143 | 144 | impl<'ctx> GlobalAlias<'ctx> { 145 | /// Get the aliasee of the global alias 146 | pub fn aliasee(&self) -> Constant<'ctx> { 147 | Constant::from_llvm(unsafe { LLVMAliasGetAliasee(self.0) }) 148 | } 149 | } 150 | 151 | impl_positional_value_ref!(GlobalAlias, 0); 152 | 153 | impl_positional_from_llvm_value!(GlobalAlias); 154 | 155 | /// We can turn Global Alias into a Global Alias Constant 156 | impl<'ctx> AsConstant<'ctx> for GlobalAlias<'ctx> { 157 | fn as_constant(&self) -> Constant<'ctx> { 158 | Constant::Global(Global::Alias(self.clone())) 159 | } 160 | } 161 | 162 | impl_as_operand_for_constant!(GlobalAlias); 163 | -------------------------------------------------------------------------------- /src/values/inline_asm.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// Inline Assembly value 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct InlineAsm<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_send_sync!(InlineAsm); 14 | 15 | impl<'ctx> InlineAsm<'ctx> { 16 | /// Get the type of this InlineAsm in function type form 17 | pub fn function_type(&self) -> FunctionType<'ctx> { 18 | FunctionType::from_llvm(unsafe { LLVMGetElementType(LLVMTypeOf(self.0)) }) 19 | } 20 | 21 | /// Get the whole string for inline asm 22 | /// 23 | /// General Format: 24 | /// {type} asm [[flags]] "{assembly_body}" "{constraints}" 25 | /// 26 | /// E.g. 27 | /// ``` llvm 28 | /// void (i64*, i8, i64*)* asm sideeffect ".pushsection .smp_locks,\22a\22\0A.balign 4\0A.long 671f - .\0A.popsection\0A671:\0A\09lock; orb $1,$0", "=*m,iq,*m,~{memory},~{dirflag},~{fpsr},~{flags}" 29 | /// ``` 30 | pub fn to_string(&self) -> String { 31 | unsafe { utils::raw_to_string(LLVMPrintValueToString(self.value_ref())) } 32 | } 33 | } 34 | 35 | impl<'ctx> AsOperand<'ctx> for InlineAsm<'ctx> { 36 | fn as_operand(&self) -> Operand<'ctx> { 37 | Operand::InlineAsm(self.clone()) 38 | } 39 | } 40 | 41 | impl_positional_value_ref!(InlineAsm, 0); 42 | 43 | impl_positional_from_llvm_value!(InlineAsm); 44 | -------------------------------------------------------------------------------- /src/values/instruction/alloca.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::types::*; 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Alloca instruction](https://llvm.org/docs/LangRef.html#alloca-instruction) 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct AllocaInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_instr_debug!(AllocaInstruction); 13 | 14 | impl_as_operand_for_instr!(AllocaInstruction); 15 | 16 | impl_send_sync!(AllocaInstruction); 17 | 18 | impl<'ctx> GetType<'ctx> for AllocaInstruction<'ctx> {} 19 | 20 | impl<'ctx> GetDebugMetadata<'ctx> for AllocaInstruction<'ctx> {} 21 | 22 | impl<'ctx> InstructionTrait<'ctx> for AllocaInstruction<'ctx> {} 23 | 24 | impl<'ctx> InstructionDebugLoc for AllocaInstruction<'ctx> {} 25 | 26 | impl<'ctx> AsInstruction<'ctx> for AllocaInstruction<'ctx> { 27 | fn as_instruction(&self) -> Instruction<'ctx> { 28 | Instruction::Alloca(*self) 29 | } 30 | } 31 | 32 | impl<'ctx> ValueOpcode for AllocaInstruction<'ctx> { 33 | fn opcode(&self) -> Opcode { 34 | Opcode::Alloca 35 | } 36 | } 37 | 38 | impl<'ctx> AllocaInstruction<'ctx> { 39 | /// Get the pointer type of alloca 40 | pub fn get_pointer_type(&self) -> PointerType<'ctx> { 41 | PointerType::from_llvm(self.get_type().type_ref()) 42 | } 43 | 44 | /// Get the element type which this allocated pointer points to 45 | pub fn get_element_type(&self) -> Type<'ctx> { 46 | self.get_pointer_type().element_type() 47 | } 48 | } 49 | 50 | impl_positional_value_ref!(AllocaInstruction, 0); 51 | 52 | impl_positional_from_llvm_value!(AllocaInstruction); 53 | -------------------------------------------------------------------------------- /src/values/instruction/binary.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetInstructionOpcode, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMOpcode; 4 | use std::marker::PhantomData; 5 | 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// Binary Opcode 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub enum BinaryOpcode { 12 | // Arithmatics 13 | Add, 14 | Sub, 15 | Mul, 16 | UDiv, 17 | SDiv, 18 | URem, 19 | SRem, 20 | // Floating point 21 | FAdd, 22 | FSub, 23 | FMul, 24 | FDiv, 25 | FRem, 26 | // Bitwise operation 27 | Shl, 28 | LShr, 29 | AShr, 30 | And, 31 | Or, 32 | Xor, 33 | } 34 | 35 | impl BinaryOpcode { 36 | pub fn from_llvm(llvm_opcode: LLVMOpcode) -> Option { 37 | match llvm_opcode { 38 | LLVMOpcode::LLVMAdd => Some(Self::Add), 39 | LLVMOpcode::LLVMSub => Some(Self::Sub), 40 | LLVMOpcode::LLVMMul => Some(Self::Mul), 41 | LLVMOpcode::LLVMUDiv => Some(Self::UDiv), 42 | LLVMOpcode::LLVMSDiv => Some(Self::SDiv), 43 | LLVMOpcode::LLVMURem => Some(Self::URem), 44 | LLVMOpcode::LLVMSRem => Some(Self::SRem), 45 | LLVMOpcode::LLVMFAdd => Some(Self::FAdd), 46 | LLVMOpcode::LLVMFSub => Some(Self::FSub), 47 | LLVMOpcode::LLVMFMul => Some(Self::FMul), 48 | LLVMOpcode::LLVMFDiv => Some(Self::FDiv), 49 | LLVMOpcode::LLVMFRem => Some(Self::FRem), 50 | LLVMOpcode::LLVMShl => Some(Self::Shl), 51 | LLVMOpcode::LLVMLShr => Some(Self::LShr), 52 | LLVMOpcode::LLVMAShr => Some(Self::AShr), 53 | LLVMOpcode::LLVMAnd => Some(Self::And), 54 | LLVMOpcode::LLVMOr => Some(Self::Or), 55 | LLVMOpcode::LLVMXor => Some(Self::Xor), 56 | _ => None, 57 | } 58 | } 59 | 60 | pub fn to_string(&self) -> &str { 61 | match self { 62 | Self::Add => "add", 63 | Self::Sub => "sub", 64 | Self::Mul => "mul", 65 | Self::UDiv => "udiv", 66 | Self::SDiv => "sdiv", 67 | Self::URem => "urem", 68 | Self::SRem => "srem", 69 | Self::FAdd => "fadd", 70 | Self::FSub => "fsub", 71 | Self::FMul => "fmul", 72 | Self::FDiv => "fdiv", 73 | Self::FRem => "frem", 74 | Self::Shl => "shl", 75 | Self::LShr => "lshr", 76 | Self::AShr => "ashr", 77 | Self::And => "and", 78 | Self::Or => "or", 79 | Self::Xor => "xor", 80 | } 81 | } 82 | } 83 | 84 | /// [Binary instruction](https://llvm.org/docs/LangRef.html#binary-operations) 85 | /// 86 | /// Covers the following instruction opcodes: 87 | /// - Integer Arithmetics 88 | /// - Add 89 | /// - Sub 90 | /// - Mul 91 | /// - UDiv 92 | /// - SDiv 93 | /// - URem 94 | /// - SRem 95 | /// - Floating Point Arithmetics 96 | /// - FAdd 97 | /// - FSub 98 | /// - FMul 99 | /// - FDiv 100 | /// - Bitwise 101 | /// - Shl 102 | /// - LShr 103 | /// - AShr 104 | /// - And 105 | /// - Or 106 | /// - Xor 107 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 108 | pub struct BinaryInstruction<'ctx>(BinaryOpcode, LLVMValueRef, PhantomData<&'ctx ()>); 109 | 110 | impl_instr_debug!(BinaryInstruction); 111 | 112 | impl_as_operand_for_instr!(BinaryInstruction); 113 | 114 | impl_send_sync!(BinaryInstruction); 115 | 116 | impl<'ctx> GetType<'ctx> for BinaryInstruction<'ctx> {} 117 | 118 | impl<'ctx> GetDebugMetadata<'ctx> for BinaryInstruction<'ctx> {} 119 | 120 | impl<'ctx> InstructionDebugLoc for BinaryInstruction<'ctx> {} 121 | 122 | impl<'ctx> InstructionTrait<'ctx> for BinaryInstruction<'ctx> {} 123 | 124 | impl<'ctx> AsInstruction<'ctx> for BinaryInstruction<'ctx> { 125 | fn as_instruction(&self) -> Instruction<'ctx> { 126 | Instruction::Binary(*self) 127 | } 128 | } 129 | 130 | impl<'ctx> ValueOpcode for BinaryInstruction<'ctx> { 131 | fn opcode(&self) -> Opcode { 132 | Opcode::Binary(self.binary_opcode()) 133 | } 134 | } 135 | 136 | impl<'ctx> BinaryInstruction<'ctx> { 137 | /// Get the opcode of this binary instruction 138 | pub fn binary_opcode(&self) -> BinaryOpcode { 139 | self.0 140 | } 141 | 142 | /// Get the lhs operand 143 | pub fn op0(&self) -> Operand<'ctx> { 144 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 145 | } 146 | 147 | /// Get the rhs operand 148 | pub fn op1(&self) -> Operand<'ctx> { 149 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 1) }) 150 | } 151 | } 152 | 153 | impl_op_from_llvm_value!(BinaryInstruction, BinaryOpcode, LLVMGetInstructionOpcode); 154 | 155 | impl_positional_value_ref!(BinaryInstruction, 1); 156 | -------------------------------------------------------------------------------- /src/values/instruction/br.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMValueAsBasicBlock}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::utils::*; 6 | use crate::values::*; 7 | use crate::{FromLLVMBlock, FromLLVMValue, ValueRef}; 8 | 9 | /// [Branch instruction](https://llvm.org/docs/LangRef.html#br-instruction) 10 | /// 11 | /// Branch could either be conditional or unconditional, and will have different behavior 12 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 13 | pub enum BranchInstruction<'ctx> { 14 | Conditional(ConditionalBranchInstruction<'ctx>), 15 | Unconditional(UnconditionalBranchInstruction<'ctx>), 16 | } 17 | 18 | impl_as_operand_for_instr!(BranchInstruction); 19 | 20 | impl<'ctx> GetDebugMetadata<'ctx> for BranchInstruction<'ctx> {} 21 | 22 | impl<'ctx> InstructionDebugLoc for BranchInstruction<'ctx> {} 23 | 24 | impl<'ctx> InstructionTrait<'ctx> for BranchInstruction<'ctx> {} 25 | 26 | impl<'ctx> AsInstruction<'ctx> for BranchInstruction<'ctx> { 27 | fn as_instruction(&self) -> Instruction<'ctx> { 28 | Instruction::Branch(*self) 29 | } 30 | } 31 | 32 | impl<'ctx> ValueOpcode for BranchInstruction<'ctx> { 33 | fn opcode(&self) -> Opcode { 34 | Opcode::Br 35 | } 36 | } 37 | 38 | impl<'ctx> BranchInstruction<'ctx> { 39 | /// Get the destination blocks from this branch instruction 40 | /// 41 | /// If this instruction is conditional, then there will be two target blocks; 42 | /// if unconditional, then there will be only one target block 43 | pub fn destinations(&self) -> Vec> { 44 | match self { 45 | Self::Conditional(c) => vec![c.then_block(), c.else_block()], 46 | Self::Unconditional(u) => vec![u.destination()], 47 | } 48 | } 49 | } 50 | 51 | impl<'ctx> FromLLVMValue for BranchInstruction<'ctx> { 52 | fn from_llvm(ptr: LLVMValueRef) -> Self { 53 | match unsafe { LLVMGetNumOperands(ptr) } { 54 | 1 => Self::Unconditional(UnconditionalBranchInstruction::from_llvm(ptr)), 55 | 3 => Self::Conditional(ConditionalBranchInstruction::from_llvm(ptr)), 56 | _ => panic!("Unknown branch variant"), 57 | } 58 | } 59 | } 60 | 61 | impl<'ctx> ValueRef for BranchInstruction<'ctx> { 62 | fn value_ref(&self) -> LLVMValueRef { 63 | match self { 64 | Self::Conditional(c) => c.value_ref(), 65 | Self::Unconditional(u) => u.value_ref(), 66 | } 67 | } 68 | } 69 | 70 | /// Conditional Branch Instruction 71 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 72 | pub struct ConditionalBranchInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 73 | 74 | impl_instr_debug!(ConditionalBranchInstruction); 75 | 76 | impl_as_operand_for_instr!(ConditionalBranchInstruction); 77 | 78 | impl_send_sync!(ConditionalBranchInstruction); 79 | 80 | impl<'ctx> GetDebugMetadata<'ctx> for ConditionalBranchInstruction<'ctx> {} 81 | 82 | impl<'ctx> InstructionDebugLoc for ConditionalBranchInstruction<'ctx> {} 83 | 84 | impl<'ctx> InstructionTrait<'ctx> for ConditionalBranchInstruction<'ctx> {} 85 | 86 | impl<'ctx> ConditionalBranchInstruction<'ctx> { 87 | /// Get the condition operand used to determine which branch to take 88 | pub fn condition(&self) -> Operand<'ctx> { 89 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 90 | } 91 | 92 | /// Get the block taken when condition is satisfied (then block) 93 | pub fn then_block(&self) -> Block<'ctx> { 94 | let operand = unsafe { LLVMGetOperand(self.0, 2) }; 95 | let block = unsafe { LLVMValueAsBasicBlock(operand) }; 96 | Block::from_llvm(block) 97 | } 98 | 99 | /// Get the block taken when condition is unsatisfied (else block) 100 | pub fn else_block(&self) -> Block<'ctx> { 101 | let operand = unsafe { LLVMGetOperand(self.0, 1) }; 102 | let block = unsafe { LLVMValueAsBasicBlock(operand) }; 103 | Block::from_llvm(block) 104 | } 105 | } 106 | 107 | impl<'ctx> ValueOpcode for ConditionalBranchInstruction<'ctx> { 108 | fn opcode(&self) -> Opcode { 109 | Opcode::Br 110 | } 111 | } 112 | 113 | impl<'ctx> AsInstruction<'ctx> for ConditionalBranchInstruction<'ctx> { 114 | fn as_instruction(&self) -> Instruction<'ctx> { 115 | Instruction::Branch(BranchInstruction::Conditional(*self)) 116 | } 117 | } 118 | 119 | impl_positional_value_ref!(ConditionalBranchInstruction, 0); 120 | 121 | impl_positional_from_llvm_value!(ConditionalBranchInstruction); 122 | 123 | /// Unconditional branch instruction 124 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 125 | pub struct UnconditionalBranchInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 126 | 127 | impl_instr_debug!(UnconditionalBranchInstruction); 128 | 129 | impl_as_operand_for_instr!(UnconditionalBranchInstruction); 130 | 131 | impl_send_sync!(UnconditionalBranchInstruction); 132 | 133 | impl<'ctx> GetDebugMetadata<'ctx> for UnconditionalBranchInstruction<'ctx> {} 134 | 135 | impl<'ctx> InstructionDebugLoc for UnconditionalBranchInstruction<'ctx> {} 136 | 137 | impl<'ctx> InstructionTrait<'ctx> for UnconditionalBranchInstruction<'ctx> {} 138 | 139 | impl<'ctx> UnconditionalBranchInstruction<'ctx> { 140 | /// Get the target block that this branch jumps to 141 | pub fn destination(&self) -> Block<'ctx> { 142 | let operand = unsafe { LLVMGetOperand(self.0, 0) }; 143 | let block = unsafe { LLVMValueAsBasicBlock(operand) }; 144 | Block::from_llvm(block) 145 | } 146 | 147 | /// Check if this unconditional branch is jumping as a end-of-loop-body jump 148 | /// 149 | /// Will return Some(is_loop_jump) when debug metadata is presented, None otherwise 150 | pub fn is_loop_jump(&self) -> Option { 151 | mdkind_ids::dbg_metadata(self.value_ref()).map(|_| mdkind_ids::loop_metadata(self.value_ref()).is_some()) 152 | } 153 | } 154 | 155 | impl<'ctx> ValueOpcode for UnconditionalBranchInstruction<'ctx> { 156 | fn opcode(&self) -> Opcode { 157 | Opcode::Br 158 | } 159 | } 160 | 161 | impl<'ctx> AsInstruction<'ctx> for UnconditionalBranchInstruction<'ctx> { 162 | fn as_instruction(&self) -> Instruction<'ctx> { 163 | Instruction::Branch(BranchInstruction::Unconditional(*self)) 164 | } 165 | } 166 | 167 | impl_positional_value_ref!(UnconditionalBranchInstruction, 0); 168 | 169 | impl_positional_from_llvm_value!(UnconditionalBranchInstruction); 170 | -------------------------------------------------------------------------------- /src/values/instruction/call.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Call instruction](https://llvm.org/docs/LangRef.html#call-instruction) 10 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct CallInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_instr_debug!(CallInstruction); 14 | 15 | impl_as_operand_for_instr!(CallInstruction); 16 | 17 | impl_send_sync!(CallInstruction); 18 | 19 | impl<'ctx> GetType<'ctx> for CallInstruction<'ctx> {} 20 | 21 | impl<'ctx> GetDebugMetadata<'ctx> for CallInstruction<'ctx> {} 22 | 23 | impl<'ctx> InstructionDebugLoc for CallInstruction<'ctx> {} 24 | 25 | impl<'ctx> InstructionTrait<'ctx> for CallInstruction<'ctx> {} 26 | 27 | impl<'ctx> CallInstruction<'ctx> { 28 | /// Get the callee function if the callee is an LLVM function 29 | pub fn callee_function(&self) -> Option> { 30 | match self.callee() { 31 | Operand::Constant(Constant::Function(f)) => Some(f), 32 | _ => None, 33 | } 34 | } 35 | 36 | /// Get the callee as inline assembly value if the callee is an InlineAsm 37 | pub fn callee_inline_asm(&self) -> Option> { 38 | match self.callee() { 39 | Operand::InlineAsm(ia) => Some(ia), 40 | _ => None, 41 | } 42 | } 43 | 44 | /// Get the callee function type 45 | pub fn callee_function_type(&self) -> FunctionType<'ctx> { 46 | FunctionType::from_llvm(unsafe { LLVMGetElementType(self.callee().get_type().type_ref()) }) 47 | } 48 | 49 | /// Get the callee value in operand 50 | pub fn callee(&self) -> Operand<'ctx> { 51 | let operand_id = self.num_arguments(); 52 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, operand_id as u32) }) 53 | } 54 | 55 | /// Get the number of arguments passed to the callee function 56 | pub fn num_arguments(&self) -> usize { 57 | let num_operands = unsafe { LLVMGetNumOperands(self.0) }; 58 | num_operands as usize - 1 59 | } 60 | 61 | /// Get the arguments being passed to the callee function 62 | pub fn arguments(&self) -> Vec> { 63 | (0..self.num_arguments()) 64 | .map(|i| Operand::from_llvm(unsafe { LLVMGetOperand(self.0, i as u32) })) 65 | .collect() 66 | } 67 | 68 | /// Get the argument at a given index 69 | pub fn argument(&self, index: usize) -> Option> { 70 | if index < self.num_arguments() { 71 | Some(Operand::from_llvm(unsafe { LLVMGetOperand(self.0, index as u32) })) 72 | } else { 73 | None 74 | } 75 | } 76 | 77 | /// Check if this function call is a tail call 78 | pub fn is_tail_call(&self) -> bool { 79 | unsafe { LLVMIsTailCall(self.0) == 1 } 80 | } 81 | 82 | /// Check if this call is to an inline assembly 83 | pub fn is_inline_asm_call(&self) -> bool { 84 | match self.callee() { 85 | Operand::InlineAsm(_) => true, 86 | _ => false, 87 | } 88 | } 89 | 90 | /// Check if this call is to llvm intrinsic function 91 | pub fn is_intrinsic_call(&self) -> bool { 92 | unsafe { !LLVMIsAIntrinsicInst(self.0).is_null() } 93 | } 94 | } 95 | 96 | impl<'ctx> ValueOpcode for CallInstruction<'ctx> { 97 | fn opcode(&self) -> Opcode { 98 | Opcode::Call 99 | } 100 | } 101 | 102 | impl<'ctx> AsInstruction<'ctx> for CallInstruction<'ctx> { 103 | fn as_instruction(&self) -> Instruction<'ctx> { 104 | Instruction::Call(*self) 105 | } 106 | } 107 | 108 | impl_positional_value_ref!(CallInstruction, 0); 109 | 110 | impl_positional_from_llvm_value!(CallInstruction); 111 | -------------------------------------------------------------------------------- /src/values/instruction/call_br.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// [CallBr instruction](https://llvm.org/docs/LangRef.html#callbr-instruction) 8 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct CallBrInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_instr_debug!(CallBrInstruction); 12 | 13 | impl_as_operand_for_instr!(CallBrInstruction); 14 | 15 | impl_send_sync!(CallBrInstruction); 16 | 17 | impl<'ctx> GetType<'ctx> for CallBrInstruction<'ctx> {} 18 | 19 | impl<'ctx> GetDebugMetadata<'ctx> for CallBrInstruction<'ctx> {} 20 | 21 | impl<'ctx> InstructionDebugLoc for CallBrInstruction<'ctx> {} 22 | 23 | impl<'ctx> InstructionTrait<'ctx> for CallBrInstruction<'ctx> {} 24 | 25 | impl<'ctx> CallBrInstruction<'ctx> {} 26 | 27 | impl<'ctx> ValueOpcode for CallBrInstruction<'ctx> { 28 | fn opcode(&self) -> Opcode { 29 | Opcode::CallBr 30 | } 31 | } 32 | 33 | impl<'ctx> AsInstruction<'ctx> for CallBrInstruction<'ctx> { 34 | fn as_instruction(&self) -> Instruction<'ctx> { 35 | Instruction::CallBr(*self) 36 | } 37 | } 38 | 39 | impl_positional_value_ref!(CallBrInstruction, 0); 40 | 41 | impl_positional_from_llvm_value!(CallBrInstruction); 42 | -------------------------------------------------------------------------------- /src/values/instruction/extract_value.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Extract value instruction](https://llvm.org/docs/LangRef.html#extractvalue-instruction) 10 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct ExtractValueInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_instr_debug!(ExtractValueInstruction); 14 | 15 | impl_as_operand_for_instr!(ExtractValueInstruction); 16 | 17 | impl_send_sync!(ExtractValueInstruction); 18 | 19 | impl<'ctx> GetType<'ctx> for ExtractValueInstruction<'ctx> {} 20 | 21 | impl<'ctx> GetDebugMetadata<'ctx> for ExtractValueInstruction<'ctx> {} 22 | 23 | impl<'ctx> InstructionDebugLoc for ExtractValueInstruction<'ctx> {} 24 | 25 | impl<'ctx> InstructionTrait<'ctx> for ExtractValueInstruction<'ctx> {} 26 | 27 | impl<'ctx> ExtractValueInstruction<'ctx> { 28 | /// Get the aggregate operand 29 | pub fn aggregate(&self) -> Operand<'ctx> { 30 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 31 | } 32 | 33 | /// Get the aggregate type 34 | pub fn aggregate_type(&self) -> Type<'ctx> { 35 | self.aggregate().get_type() 36 | } 37 | 38 | /// Get the number of indices 39 | pub fn num_indices(&self) -> usize { 40 | unsafe { LLVMGetNumIndices(self.0) as usize } 41 | } 42 | 43 | /// Get the indices 44 | pub fn indices(&self) -> Vec { 45 | let num_indices = self.num_indices(); 46 | let mut indices = vec![0; num_indices]; 47 | unsafe { 48 | let raw_indices = LLVMGetIndices(self.0); 49 | for i in 0..num_indices { 50 | indices[i] = *raw_indices.offset(i as isize) as u32; 51 | } 52 | } 53 | return indices; 54 | } 55 | } 56 | 57 | impl<'ctx> ValueOpcode for ExtractValueInstruction<'ctx> { 58 | fn opcode(&self) -> Opcode { 59 | Opcode::ExtractValue 60 | } 61 | } 62 | 63 | impl<'ctx> AsInstruction<'ctx> for ExtractValueInstruction<'ctx> { 64 | fn as_instruction(&self) -> Instruction<'ctx> { 65 | Instruction::ExtractValue(*self) 66 | } 67 | } 68 | 69 | impl_positional_value_ref!(ExtractValueInstruction, 0); 70 | 71 | impl_positional_from_llvm_value!(ExtractValueInstruction); 72 | -------------------------------------------------------------------------------- /src/values/instruction/fcmp.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetFCmpPredicate, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMRealPredicate; 4 | use std::marker::PhantomData; 5 | 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// Floating point comparison predicate 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub enum FCmpPredicate { 12 | OEQ, 13 | OGE, 14 | OGT, 15 | OLE, 16 | OLT, 17 | ONE, 18 | ORD, 19 | PredicateFalse, 20 | PredicateTrue, 21 | UEQ, 22 | UGE, 23 | UGT, 24 | ULE, 25 | ULT, 26 | UNE, 27 | UNO, 28 | } 29 | 30 | impl FCmpPredicate { 31 | pub fn from_llvm(pred: LLVMRealPredicate) -> Self { 32 | use LLVMRealPredicate::*; 33 | match pred { 34 | LLVMRealOEQ => Self::OEQ, 35 | LLVMRealOGE => Self::OGE, 36 | LLVMRealOGT => Self::OGT, 37 | LLVMRealOLE => Self::OLE, 38 | LLVMRealOLT => Self::OLT, 39 | LLVMRealONE => Self::ONE, 40 | LLVMRealORD => Self::ORD, 41 | LLVMRealPredicateFalse => Self::PredicateFalse, 42 | LLVMRealPredicateTrue => Self::PredicateTrue, 43 | LLVMRealUEQ => Self::UEQ, 44 | LLVMRealUGE => Self::UGE, 45 | LLVMRealUGT => Self::UGT, 46 | LLVMRealULE => Self::ULE, 47 | LLVMRealULT => Self::ULT, 48 | LLVMRealUNE => Self::UNE, 49 | LLVMRealUNO => Self::UNO, 50 | } 51 | } 52 | 53 | pub fn to_string(&self) -> &str { 54 | match self { 55 | Self::OEQ => "oeq", 56 | Self::OGE => "oge", 57 | Self::OGT => "ogt", 58 | Self::OLE => "ole", 59 | Self::OLT => "olt", 60 | Self::ONE => "one", 61 | Self::ORD => "ord", 62 | Self::PredicateFalse => "false", 63 | Self::PredicateTrue => "true", 64 | Self::UEQ => "ueq", 65 | Self::UGE => "uge", 66 | Self::UGT => "ugt", 67 | Self::ULE => "ule", 68 | Self::ULT => "ult", 69 | Self::UNE => "une", 70 | Self::UNO => "uno", 71 | } 72 | } 73 | } 74 | 75 | /// [Floating point comparison (FCmp) instruction](https://llvm.org/docs/LangRef.html#fcmp-instruction) 76 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 77 | pub struct FCmpInstruction<'ctx>(FCmpPredicate, LLVMValueRef, PhantomData<&'ctx ()>); 78 | 79 | impl_instr_debug!(FCmpInstruction); 80 | 81 | impl_as_operand_for_instr!(FCmpInstruction); 82 | 83 | impl_send_sync!(FCmpInstruction); 84 | 85 | impl<'ctx> GetType<'ctx> for FCmpInstruction<'ctx> {} 86 | 87 | impl<'ctx> GetDebugMetadata<'ctx> for FCmpInstruction<'ctx> {} 88 | 89 | impl<'ctx> InstructionDebugLoc for FCmpInstruction<'ctx> {} 90 | 91 | impl<'ctx> InstructionTrait<'ctx> for FCmpInstruction<'ctx> {} 92 | 93 | impl<'ctx> FCmpInstruction<'ctx> { 94 | /// Get the predicate 95 | pub fn predicate(&self) -> FCmpPredicate { 96 | self.0 97 | } 98 | 99 | /// Get the lhs operand 100 | pub fn op0(&self) -> Operand<'ctx> { 101 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 102 | } 103 | 104 | /// Get the rhs operand 105 | pub fn op1(&self) -> Operand<'ctx> { 106 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 1) }) 107 | } 108 | } 109 | 110 | impl<'ctx> ValueOpcode for FCmpInstruction<'ctx> { 111 | fn opcode(&self) -> Opcode { 112 | Opcode::FCmp 113 | } 114 | } 115 | 116 | impl<'ctx> AsInstruction<'ctx> for FCmpInstruction<'ctx> { 117 | fn as_instruction(&self) -> Instruction<'ctx> { 118 | Instruction::FCmp(*self) 119 | } 120 | } 121 | 122 | impl_positional_value_ref!(FCmpInstruction, 1); 123 | 124 | impl_cmp_from_llvm_value!(FCmpInstruction, FCmpPredicate, LLVMGetFCmpPredicate); 125 | -------------------------------------------------------------------------------- /src/values/instruction/gep.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Get Element Pointer (GEP) instruction](https://llvm.org/docs/LangRef.html#getelementptr-instruction) 10 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct GetElementPtrInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_instr_debug!(GetElementPtrInstruction); 14 | 15 | impl_as_operand_for_instr!(GetElementPtrInstruction); 16 | 17 | impl_send_sync!(GetElementPtrInstruction); 18 | 19 | impl<'ctx> GetType<'ctx> for GetElementPtrInstruction<'ctx> {} 20 | 21 | impl<'ctx> GetDebugMetadata<'ctx> for GetElementPtrInstruction<'ctx> {} 22 | 23 | impl<'ctx> InstructionDebugLoc for GetElementPtrInstruction<'ctx> {} 24 | 25 | impl<'ctx> InstructionTrait<'ctx> for GetElementPtrInstruction<'ctx> {} 26 | 27 | impl<'ctx> GetElementPtrInstruction<'ctx> { 28 | /// Get the base location 29 | pub fn location(&self) -> Operand<'ctx> { 30 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 31 | } 32 | 33 | /// Get the number of indices used to get the element pointer 34 | pub fn num_indices(&self) -> usize { 35 | (unsafe { LLVMGetNumOperands(self.0) as usize }) - 1 36 | } 37 | 38 | /// Get the indices used to get the pointer, in vector form 39 | pub fn indices(&self) -> Vec> { 40 | (0..self.num_indices() as u32) 41 | .map(|i| Operand::from_llvm(unsafe { LLVMGetOperand(self.0, i + 1) })) 42 | .collect() 43 | } 44 | 45 | /// Get the pointer type of the result of this GEP instruction 46 | pub fn get_pointer_type(&self) -> PointerType<'ctx> { 47 | PointerType::from_llvm(self.get_type().type_ref()) 48 | } 49 | } 50 | 51 | impl<'ctx> ValueOpcode for GetElementPtrInstruction<'ctx> { 52 | fn opcode(&self) -> Opcode { 53 | Opcode::GetElementPtr 54 | } 55 | } 56 | 57 | impl<'ctx> AsInstruction<'ctx> for GetElementPtrInstruction<'ctx> { 58 | fn as_instruction(&self) -> Instruction<'ctx> { 59 | Instruction::GetElementPtr(*self) 60 | } 61 | } 62 | 63 | impl_positional_value_ref!(GetElementPtrInstruction, 0); 64 | 65 | impl_positional_from_llvm_value!(GetElementPtrInstruction); 66 | -------------------------------------------------------------------------------- /src/values/instruction/icmp.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetICmpPredicate, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMIntPredicate; 4 | use std::marker::PhantomData; 5 | 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// Integer conparison predicate 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub enum ICmpPredicate { 12 | /// Equals 13 | EQ, 14 | /// Not-equals 15 | NE, 16 | /// Signed greater-than or equal-to 17 | SGE, 18 | /// Unsigned greater-than or equal-to 19 | UGE, 20 | /// Signed greater-than 21 | SGT, 22 | /// Unsigned greater-than 23 | UGT, 24 | /// Signed less-than or equal-to 25 | SLE, 26 | /// Unsigned less-than or equal-to 27 | ULE, 28 | /// Signed less-than 29 | SLT, 30 | /// Unsigned less-than 31 | ULT, 32 | } 33 | 34 | impl ICmpPredicate { 35 | pub(crate) fn from_llvm(pred: LLVMIntPredicate) -> Self { 36 | use LLVMIntPredicate::*; 37 | match pred { 38 | LLVMIntEQ => Self::EQ, 39 | LLVMIntNE => Self::NE, 40 | LLVMIntSGE => Self::SGE, 41 | LLVMIntUGE => Self::UGE, 42 | LLVMIntSGT => Self::SGT, 43 | LLVMIntUGT => Self::UGT, 44 | LLVMIntSLE => Self::SLE, 45 | LLVMIntULE => Self::ULE, 46 | LLVMIntSLT => Self::SLT, 47 | LLVMIntULT => Self::ULT, 48 | } 49 | } 50 | 51 | pub fn to_string(&self) -> &str { 52 | match self { 53 | Self::EQ => "eq", 54 | Self::NE => "ne", 55 | Self::SGE => "sge", 56 | Self::SGT => "sgt", 57 | Self::SLE => "sle", 58 | Self::SLT => "slt", 59 | Self::UGE => "uge", 60 | Self::UGT => "ugt", 61 | Self::ULE => "ule", 62 | Self::ULT => "ult", 63 | } 64 | } 65 | } 66 | 67 | /// [Integer comparison (ICmp) instruction](https://llvm.org/docs/LangRef.html#icmp-instruction) 68 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 69 | pub struct ICmpInstruction<'ctx>(ICmpPredicate, LLVMValueRef, PhantomData<&'ctx ()>); 70 | 71 | impl_instr_debug!(ICmpInstruction); 72 | 73 | impl_as_operand_for_instr!(ICmpInstruction); 74 | 75 | impl_send_sync!(ICmpInstruction); 76 | 77 | impl<'ctx> GetType<'ctx> for ICmpInstruction<'ctx> {} 78 | 79 | impl<'ctx> GetDebugMetadata<'ctx> for ICmpInstruction<'ctx> {} 80 | 81 | impl<'ctx> InstructionDebugLoc for ICmpInstruction<'ctx> {} 82 | 83 | impl<'ctx> InstructionTrait<'ctx> for ICmpInstruction<'ctx> {} 84 | 85 | impl<'ctx> ICmpInstruction<'ctx> { 86 | /// Get the integer comparison predicate 87 | pub fn predicate(&self) -> ICmpPredicate { 88 | self.0 89 | } 90 | 91 | /// Get the lhs operand 92 | pub fn op0(&self) -> Operand<'ctx> { 93 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 94 | } 95 | 96 | /// Get the rhs operand 97 | pub fn op1(&self) -> Operand<'ctx> { 98 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 1) }) 99 | } 100 | } 101 | 102 | impl<'ctx> ValueOpcode for ICmpInstruction<'ctx> { 103 | fn opcode(&self) -> Opcode { 104 | Opcode::ICmp 105 | } 106 | } 107 | 108 | impl<'ctx> AsInstruction<'ctx> for ICmpInstruction<'ctx> { 109 | fn as_instruction(&self) -> Instruction<'ctx> { 110 | Instruction::ICmp(*self) 111 | } 112 | } 113 | 114 | impl_positional_value_ref!(ICmpInstruction, 1); 115 | 116 | impl_cmp_from_llvm_value!(ICmpInstruction, ICmpPredicate, LLVMGetICmpPredicate); 117 | -------------------------------------------------------------------------------- /src/values/instruction/indir_br.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Indirect Branch instruction](https://llvm.org/docs/LangRef.html#indirectbr-instruction) 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct IndirectBranchInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_instr_debug!(IndirectBranchInstruction); 13 | 14 | impl_as_operand_for_instr!(IndirectBranchInstruction); 15 | 16 | impl_send_sync!(IndirectBranchInstruction); 17 | 18 | impl<'ctx> GetType<'ctx> for IndirectBranchInstruction<'ctx> {} 19 | 20 | impl<'ctx> GetDebugMetadata<'ctx> for IndirectBranchInstruction<'ctx> {} 21 | 22 | impl<'ctx> InstructionDebugLoc for IndirectBranchInstruction<'ctx> {} 23 | 24 | impl<'ctx> InstructionTrait<'ctx> for IndirectBranchInstruction<'ctx> {} 25 | 26 | impl<'ctx> IndirectBranchInstruction<'ctx> { 27 | /// Get the block address 28 | pub fn address(&self) -> BlockAddress<'ctx> { 29 | BlockAddress::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 30 | } 31 | 32 | /// Get the possible block destinations 33 | pub fn destinations(&self) -> Vec> { 34 | let num_operands = unsafe { LLVMGetNumOperands(self.0) as u32 }; 35 | let num_dests = num_operands - 1; 36 | (1..=num_dests) 37 | .map(|i| Block::from_llvm(unsafe { LLVMValueAsBasicBlock(LLVMGetOperand(self.0, i)) })) 38 | .collect() 39 | } 40 | } 41 | 42 | impl<'ctx> ValueOpcode for IndirectBranchInstruction<'ctx> { 43 | fn opcode(&self) -> Opcode { 44 | Opcode::IndirectBr 45 | } 46 | } 47 | 48 | impl<'ctx> AsInstruction<'ctx> for IndirectBranchInstruction<'ctx> { 49 | fn as_instruction(&self) -> Instruction<'ctx> { 50 | Instruction::IndirectBranch(*self) 51 | } 52 | } 53 | 54 | impl_positional_value_ref!(IndirectBranchInstruction, 0); 55 | 56 | impl_positional_from_llvm_value!(IndirectBranchInstruction); 57 | -------------------------------------------------------------------------------- /src/values/instruction/insert_value.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::types::*; 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// [Insert value instruction](https://llvm.org/docs/LangRef.html#insertvalue-instruction) 10 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct InsertValueInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_instr_debug!(InsertValueInstruction); 14 | 15 | impl_as_operand_for_instr!(InsertValueInstruction); 16 | 17 | impl_send_sync!(InsertValueInstruction); 18 | 19 | impl<'ctx> GetType<'ctx> for InsertValueInstruction<'ctx> {} 20 | 21 | impl<'ctx> GetDebugMetadata<'ctx> for InsertValueInstruction<'ctx> {} 22 | 23 | impl<'ctx> InstructionDebugLoc for InsertValueInstruction<'ctx> {} 24 | 25 | impl<'ctx> InstructionTrait<'ctx> for InsertValueInstruction<'ctx> {} 26 | 27 | impl<'ctx> InsertValueInstruction<'ctx> { 28 | /// Get the aggregate operand 29 | pub fn aggregate(&self) -> Operand<'ctx> { 30 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 31 | } 32 | 33 | /// Get the aggregate type 34 | pub fn aggregate_type(&self) -> Type<'ctx> { 35 | self.aggregate().get_type() 36 | } 37 | 38 | /// Get the inserted value 39 | pub fn value(&self) -> Operand<'ctx> { 40 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 1) }) 41 | } 42 | 43 | /// Get the inserted value type 44 | pub fn value_type(&self) -> Type<'ctx> { 45 | self.value().get_type() 46 | } 47 | 48 | /// Get the number of indices 49 | pub fn num_indices(&self) -> usize { 50 | unsafe { LLVMGetNumIndices(self.0) as usize } 51 | } 52 | 53 | /// Get the indices 54 | pub fn indices(&self) -> Vec { 55 | let num_indices = self.num_indices(); 56 | let mut indices = vec![0; num_indices]; 57 | unsafe { 58 | let raw_indices = LLVMGetIndices(self.0); 59 | for i in 0..num_indices { 60 | indices[i] = *raw_indices.offset(i as isize) as u32; 61 | } 62 | } 63 | return indices; 64 | } 65 | } 66 | 67 | impl<'ctx> ValueOpcode for InsertValueInstruction<'ctx> { 68 | fn opcode(&self) -> Opcode { 69 | Opcode::InsertValue 70 | } 71 | } 72 | 73 | impl<'ctx> AsInstruction<'ctx> for InsertValueInstruction<'ctx> { 74 | fn as_instruction(&self) -> Instruction<'ctx> { 75 | Instruction::InsertValue(*self) 76 | } 77 | } 78 | 79 | impl_positional_value_ref!(InsertValueInstruction, 0); 80 | 81 | impl_positional_from_llvm_value!(InsertValueInstruction); 82 | -------------------------------------------------------------------------------- /src/values/instruction/instr.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetInstructionOpcode; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMOpcode; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Instruction](https://llvm.org/docs/LangRef.html#instruction-reference) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub enum Instruction<'ctx> { 11 | Alloca(AllocaInstruction<'ctx>), 12 | Binary(BinaryInstruction<'ctx>), 13 | Branch(BranchInstruction<'ctx>), 14 | Call(CallInstruction<'ctx>), 15 | CallBr(CallBrInstruction<'ctx>), 16 | ExtractValue(ExtractValueInstruction<'ctx>), 17 | FCmp(FCmpInstruction<'ctx>), 18 | GetElementPtr(GetElementPtrInstruction<'ctx>), 19 | ICmp(ICmpInstruction<'ctx>), 20 | IndirectBranch(IndirectBranchInstruction<'ctx>), 21 | InsertValue(InsertValueInstruction<'ctx>), 22 | Load(LoadInstruction<'ctx>), 23 | Phi(PhiInstruction<'ctx>), 24 | Return(ReturnInstruction<'ctx>), 25 | Select(SelectInstruction<'ctx>), 26 | Store(StoreInstruction<'ctx>), 27 | Switch(SwitchInstruction<'ctx>), 28 | Unary(UnaryInstruction<'ctx>), 29 | Unreachable(UnreachableInstruction<'ctx>), 30 | Other(GenericValue<'ctx>), 31 | } 32 | 33 | impl<'ctx> GetDebugMetadata<'ctx> for Instruction<'ctx> {} 34 | 35 | impl<'ctx> InstructionDebugLoc for Instruction<'ctx> {} 36 | 37 | impl<'ctx> InstructionTrait<'ctx> for Instruction<'ctx> {} 38 | 39 | impl<'ctx> ValueOpcode for Instruction<'ctx> { 40 | fn opcode(&self) -> Opcode { 41 | match self { 42 | Self::Alloca(alc_instr) => alc_instr.opcode(), 43 | Self::Binary(bin_instr) => bin_instr.opcode(), 44 | Self::Branch(br_instr) => br_instr.opcode(), 45 | Self::Call(call_instr) => call_instr.opcode(), 46 | Self::CallBr(call_br_instr) => call_br_instr.opcode(), 47 | Self::ExtractValue(extval_instr) => extval_instr.opcode(), 48 | Self::FCmp(fcmp_instr) => fcmp_instr.opcode(), 49 | Self::GetElementPtr(gep_instr) => gep_instr.opcode(), 50 | Self::ICmp(icmp_instr) => icmp_instr.opcode(), 51 | Self::IndirectBranch(indbr_instr) => indbr_instr.opcode(), 52 | Self::InsertValue(insval_instr) => insval_instr.opcode(), 53 | Self::Load(ld_instr) => ld_instr.opcode(), 54 | Self::Phi(phi_instr) => phi_instr.opcode(), 55 | Self::Return(ret_instr) => ret_instr.opcode(), 56 | Self::Select(sel_instr) => sel_instr.opcode(), 57 | Self::Store(st_instr) => st_instr.opcode(), 58 | Self::Switch(switch_instr) => switch_instr.opcode(), 59 | Self::Unary(una_instr) => una_instr.opcode(), 60 | Self::Unreachable(unr_instr) => unr_instr.opcode(), 61 | Self::Other(_) => Opcode::Unknown, 62 | } 63 | } 64 | } 65 | 66 | impl<'ctx> AsInstruction<'ctx> for Instruction<'ctx> { 67 | fn as_instruction(&self) -> Self { 68 | self.clone() 69 | } 70 | } 71 | 72 | impl_as_operand_for_instr!(Instruction); 73 | 74 | impl<'ctx> FromLLVMValue for Instruction<'ctx> { 75 | fn from_llvm(ptr: LLVMValueRef) -> Self { 76 | use LLVMOpcode::*; 77 | match unsafe { LLVMGetInstructionOpcode(ptr) } { 78 | LLVMAlloca => Self::Alloca(AllocaInstruction::from_llvm(ptr)), 79 | LLVMBr => Self::Branch(BranchInstruction::from_llvm(ptr)), 80 | LLVMCall => Self::Call(CallInstruction::from_llvm(ptr)), 81 | LLVMCallBr => Self::CallBr(CallBrInstruction::from_llvm(ptr)), 82 | LLVMExtractValue => Self::ExtractValue(ExtractValueInstruction::from_llvm(ptr)), 83 | LLVMFCmp => Self::FCmp(FCmpInstruction::from_llvm(ptr)), 84 | LLVMGetElementPtr => Self::GetElementPtr(GetElementPtrInstruction::from_llvm(ptr)), 85 | LLVMICmp => Self::ICmp(ICmpInstruction::from_llvm(ptr)), 86 | LLVMIndirectBr => Self::IndirectBranch(IndirectBranchInstruction::from_llvm(ptr)), 87 | LLVMLoad => Self::Load(LoadInstruction::from_llvm(ptr)), 88 | LLVMPHI => Self::Phi(PhiInstruction::from_llvm(ptr)), 89 | LLVMRet => Self::Return(ReturnInstruction::from_llvm(ptr)), 90 | LLVMSelect => Self::Select(SelectInstruction::from_llvm(ptr)), 91 | LLVMStore => Self::Store(StoreInstruction::from_llvm(ptr)), 92 | LLVMSwitch => Self::Switch(SwitchInstruction::from_llvm(ptr)), 93 | LLVMUnreachable => Self::Unreachable(UnreachableInstruction::from_llvm(ptr)), 94 | op if BinaryOpcode::from_llvm(op).is_some() => Self::Binary(BinaryInstruction::from_llvm(ptr)), 95 | op if UnaryOpcode::from_llvm(op).is_some() => Self::Unary(UnaryInstruction::from_llvm(ptr)), 96 | _ => Self::Other(GenericValue::from_llvm(ptr)), 97 | } 98 | } 99 | } 100 | 101 | impl<'ctx> ValueRef for Instruction<'ctx> { 102 | fn value_ref(&self) -> LLVMValueRef { 103 | match self { 104 | Self::Alloca(alc_instr) => alc_instr.value_ref(), 105 | Self::Binary(bin_instr) => bin_instr.value_ref(), 106 | Self::Branch(br_instr) => br_instr.value_ref(), 107 | Self::Call(call_instr) => call_instr.value_ref(), 108 | Self::CallBr(call_br_instr) => call_br_instr.value_ref(), 109 | Self::ExtractValue(extval_instr) => extval_instr.value_ref(), 110 | Self::FCmp(fcmp_instr) => fcmp_instr.value_ref(), 111 | Self::GetElementPtr(gep_instr) => gep_instr.value_ref(), 112 | Self::ICmp(icmp_instr) => icmp_instr.value_ref(), 113 | Self::IndirectBranch(indbr_instr) => indbr_instr.value_ref(), 114 | Self::InsertValue(insval_instr) => insval_instr.value_ref(), 115 | Self::Load(ld_instr) => ld_instr.value_ref(), 116 | Self::Phi(phi_instr) => phi_instr.value_ref(), 117 | Self::Return(ret_instr) => ret_instr.value_ref(), 118 | Self::Select(sel_instr) => sel_instr.value_ref(), 119 | Self::Store(st_instr) => st_instr.value_ref(), 120 | Self::Switch(switch_instr) => switch_instr.value_ref(), 121 | Self::Unary(una_instr) => una_instr.value_ref(), 122 | Self::Unreachable(unr_instr) => unr_instr.value_ref(), 123 | Self::Other(otr_instr) => otr_instr.value_ref(), 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/values/instruction/load.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Load instruction](https://llvm.org/docs/LangRef.html#load-instruction) 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct LoadInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_instr_debug!(LoadInstruction); 13 | 14 | impl_as_operand_for_instr!(LoadInstruction); 15 | 16 | impl_send_sync!(LoadInstruction); 17 | 18 | impl<'ctx> GetType<'ctx> for LoadInstruction<'ctx> {} 19 | 20 | impl<'ctx> GetDebugMetadata<'ctx> for LoadInstruction<'ctx> {} 21 | 22 | impl<'ctx> InstructionDebugLoc for LoadInstruction<'ctx> {} 23 | 24 | impl<'ctx> InstructionTrait<'ctx> for LoadInstruction<'ctx> {} 25 | 26 | impl<'ctx> LoadInstruction<'ctx> { 27 | /// Get the location operand which the value is load from 28 | pub fn location(&self) -> Operand<'ctx> { 29 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 30 | } 31 | } 32 | 33 | impl<'ctx> ValueOpcode for LoadInstruction<'ctx> { 34 | fn opcode(&self) -> Opcode { 35 | Opcode::Load 36 | } 37 | } 38 | 39 | impl<'ctx> AsInstruction<'ctx> for LoadInstruction<'ctx> { 40 | fn as_instruction(&self) -> Instruction<'ctx> { 41 | Instruction::Load(*self) 42 | } 43 | } 44 | 45 | impl_positional_value_ref!(LoadInstruction, 0); 46 | 47 | impl_positional_from_llvm_value!(LoadInstruction); 48 | -------------------------------------------------------------------------------- /src/values/instruction/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_instr_debug { 2 | ($id:ident) => { 3 | impl<'ctx> std::fmt::Debug for $id<'ctx> { 4 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 5 | f.debug_tuple(stringify!($id)).field(&self.to_string()).finish() 6 | } 7 | } 8 | }; 9 | } 10 | 11 | macro_rules! impl_as_operand_for_instr { 12 | ($id:ident) => { 13 | impl<'ctx> AsOperand<'ctx> for $id<'ctx> { 14 | fn as_operand(&self) -> Operand<'ctx> { 15 | Operand::Instruction(self.as_instruction()) 16 | } 17 | } 18 | } 19 | } 20 | 21 | macro_rules! impl_op_from_llvm_value { 22 | ($id:ident, $op:ident, $op_getter:ident) => { 23 | impl<'ctx> FromLLVMValue for $id<'ctx> { 24 | fn from_llvm(ptr: LLVMValueRef) -> Self { 25 | let op = $op::from_llvm(unsafe { $op_getter(ptr) }).unwrap(); 26 | Self(op, ptr, PhantomData) 27 | } 28 | } 29 | } 30 | } 31 | 32 | macro_rules! impl_cmp_from_llvm_value { 33 | ($id:ident, $op:ident, $op_getter:ident) => { 34 | impl<'ctx> FromLLVMValue for $id<'ctx> { 35 | fn from_llvm(ptr: LLVMValueRef) -> Self { 36 | let op = $op::from_llvm(unsafe { $op_getter(ptr) }); 37 | Self(op, ptr, PhantomData) 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/values/instruction/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | pub use macros::*; 4 | 5 | mod opcode; 6 | 7 | mod traits; 8 | mod alloca; 9 | mod binary; 10 | mod br; 11 | mod call; 12 | mod call_br; 13 | mod extract_value; 14 | mod insert_value; 15 | mod icmp; 16 | mod indir_br; 17 | mod fcmp; 18 | mod gep; 19 | mod instr; 20 | mod load; 21 | mod phi; 22 | mod ret; 23 | mod select; 24 | mod store; 25 | mod switch; 26 | mod unary; 27 | mod unreachable; 28 | 29 | pub use opcode::*; 30 | pub use traits::*; 31 | pub use alloca::*; 32 | pub use binary::*; 33 | pub use br::*; 34 | pub use call::*; 35 | pub use call_br::*; 36 | pub use extract_value::*; 37 | pub use insert_value::*; 38 | pub use icmp::*; 39 | pub use indir_br::*; 40 | pub use fcmp::*; 41 | pub use gep::*; 42 | pub use instr::*; 43 | pub use load::*; 44 | pub use phi::*; 45 | pub use ret::*; 46 | pub use select::*; 47 | pub use store::*; 48 | pub use switch::*; 49 | pub use unary::*; 50 | pub use unreachable::*; -------------------------------------------------------------------------------- /src/values/instruction/opcode.rs: -------------------------------------------------------------------------------- 1 | use super::binary::BinaryOpcode; 2 | use super::unary::UnaryOpcode; 3 | 4 | #[derive(Debug, Copy, Clone)] 5 | pub enum Opcode { 6 | Alloca, 7 | Binary(BinaryOpcode), 8 | Br, 9 | CallBr, 10 | Call, 11 | ExtractValue, 12 | FCmp, 13 | GetElementPtr, 14 | ICmp, 15 | IndirectBr, 16 | InsertValue, 17 | Load, 18 | Phi, 19 | Ret, 20 | Select, 21 | Store, 22 | Switch, 23 | Unary(UnaryOpcode), 24 | Unreachable, 25 | Unknown, 26 | } 27 | 28 | impl Opcode { 29 | pub fn to_string(&self) -> &str { 30 | match self { 31 | Self::Alloca => "alloca", 32 | Self::Binary(bin_op) => bin_op.to_string(), 33 | Self::Br => "br", 34 | Self::CallBr => "callbr", 35 | Self::Call => "call", 36 | Self::ExtractValue => "extractvalue", 37 | Self::FCmp => "fcmp", 38 | Self::GetElementPtr => "getelementptr", 39 | Self::ICmp => "icmp", 40 | Self::IndirectBr => "indirectbr", 41 | Self::InsertValue => "insertvalue", 42 | Self::Load => "load", 43 | Self::Phi => "phi", 44 | Self::Ret => "ret", 45 | Self::Select => "select", 46 | Self::Store => "store", 47 | Self::Switch => "switch", 48 | Self::Unary(una_op) => una_op.to_string(), 49 | Self::Unreachable => "unreachable", 50 | Self::Unknown => "unknown", 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/values/instruction/phi.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMCountIncoming, LLVMGetIncomingBlock, LLVMGetIncomingValue}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// Incoming block & value for PHI instruction 9 | pub struct PhiIncoming<'ctx> { 10 | pub block: Block<'ctx>, 11 | pub value: Operand<'ctx>, 12 | } 13 | 14 | /// [PHI instruction](https://llvm.org/docs/LangRef.html#phi-instruction) 15 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 16 | pub struct PhiInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 17 | 18 | impl_instr_debug!(PhiInstruction); 19 | 20 | impl_as_operand_for_instr!(PhiInstruction); 21 | 22 | impl_send_sync!(PhiInstruction); 23 | 24 | impl<'ctx> GetType<'ctx> for PhiInstruction<'ctx> {} 25 | 26 | impl<'ctx> GetDebugMetadata<'ctx> for PhiInstruction<'ctx> {} 27 | 28 | impl<'ctx> InstructionDebugLoc for PhiInstruction<'ctx> {} 29 | 30 | impl<'ctx> InstructionTrait<'ctx> for PhiInstruction<'ctx> {} 31 | 32 | impl<'ctx> PhiInstruction<'ctx> { 33 | /// Get the number of incoming nodes 34 | pub fn num_incomings(&self) -> usize { 35 | unsafe { LLVMCountIncoming(self.0) as usize } 36 | } 37 | 38 | /// Get the incomings 39 | pub fn incomings(&self) -> Vec> { 40 | (0..self.num_incomings()) 41 | .map(|i| PhiIncoming { 42 | block: Block::from_llvm(unsafe { LLVMGetIncomingBlock(self.0, i as u32) }), 43 | value: Operand::from_llvm(unsafe { LLVMGetIncomingValue(self.0, i as u32) }), 44 | }) 45 | .collect() 46 | } 47 | } 48 | 49 | impl<'ctx> ValueOpcode for PhiInstruction<'ctx> { 50 | fn opcode(&self) -> Opcode { 51 | Opcode::Phi 52 | } 53 | } 54 | 55 | impl<'ctx> AsInstruction<'ctx> for PhiInstruction<'ctx> { 56 | fn as_instruction(&self) -> Instruction<'ctx> { 57 | Instruction::Phi(*self) 58 | } 59 | } 60 | 61 | impl_positional_value_ref!(PhiInstruction, 0); 62 | 63 | impl_positional_from_llvm_value!(PhiInstruction); 64 | -------------------------------------------------------------------------------- /src/values/instruction/ret.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Return (Ret) instruction](https://llvm.org/docs/LangRef.html#ret-instruction) 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct ReturnInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_instr_debug!(ReturnInstruction); 13 | 14 | impl_as_operand_for_instr!(ReturnInstruction); 15 | 16 | impl_send_sync!(ReturnInstruction); 17 | 18 | impl<'ctx> GetDebugMetadata<'ctx> for ReturnInstruction<'ctx> {} 19 | 20 | impl<'ctx> InstructionDebugLoc for ReturnInstruction<'ctx> {} 21 | 22 | impl<'ctx> InstructionTrait<'ctx> for ReturnInstruction<'ctx> {} 23 | 24 | impl<'ctx> ReturnInstruction<'ctx> { 25 | /// Check if this return instruction has returned value 26 | pub fn has_op(&self) -> bool { 27 | unsafe { LLVMGetNumOperands(self.0) != 0 } 28 | } 29 | 30 | /// Get the returned value. The instruction might not contain one 31 | pub fn op(&self) -> Option> { 32 | if self.has_op() { 33 | Some(Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) })) 34 | } else { 35 | None 36 | } 37 | } 38 | } 39 | 40 | impl<'ctx> ValueOpcode for ReturnInstruction<'ctx> { 41 | fn opcode(&self) -> Opcode { 42 | Opcode::Ret 43 | } 44 | } 45 | 46 | impl<'ctx> AsInstruction<'ctx> for ReturnInstruction<'ctx> { 47 | fn as_instruction(&self) -> Instruction<'ctx> { 48 | Instruction::Return(*self) 49 | } 50 | } 51 | 52 | impl_positional_value_ref!(ReturnInstruction, 0); 53 | 54 | impl_positional_from_llvm_value!(ReturnInstruction); 55 | -------------------------------------------------------------------------------- /src/values/instruction/select.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetOperand; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Select instruction](https://llvm.org/docs/LangRef.html#select-instruction) 9 | /// 10 | /// The code `res = a < b ? a : b` will be turned into 11 | /// 12 | /// ``` llvm 13 | /// %cmp = icmp slt %a %b 14 | /// %res = select %cmp %a %b 15 | /// ``` 16 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 17 | pub struct SelectInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 18 | 19 | impl_instr_debug!(SelectInstruction); 20 | 21 | impl_as_operand_for_instr!(SelectInstruction); 22 | 23 | impl_send_sync!(SelectInstruction); 24 | 25 | impl<'ctx> GetType<'ctx> for SelectInstruction<'ctx> {} 26 | 27 | impl<'ctx> GetDebugMetadata<'ctx> for SelectInstruction<'ctx> {} 28 | 29 | impl<'ctx> InstructionTrait<'ctx> for SelectInstruction<'ctx> {} 30 | 31 | impl<'ctx> InstructionDebugLoc for SelectInstruction<'ctx> {} 32 | 33 | impl<'ctx> AsInstruction<'ctx> for SelectInstruction<'ctx> { 34 | fn as_instruction(&self) -> Instruction<'ctx> { 35 | Instruction::Select(*self) 36 | } 37 | } 38 | 39 | impl<'ctx> ValueOpcode for SelectInstruction<'ctx> { 40 | fn opcode(&self) -> Opcode { 41 | Opcode::Select 42 | } 43 | } 44 | 45 | impl<'ctx> SelectInstruction<'ctx> { 46 | /// The condition to check 47 | pub fn condition(&self) -> Operand<'ctx> { 48 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 49 | } 50 | 51 | /// The value to select when the condition is true 52 | pub fn true_value(&self) -> Operand<'ctx> { 53 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 1) }) 54 | } 55 | 56 | /// The value to select when the condition is false 57 | pub fn false_value(&self) -> Operand<'ctx> { 58 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 2) }) 59 | } 60 | } 61 | 62 | impl_positional_value_ref!(SelectInstruction, 0); 63 | 64 | impl_positional_from_llvm_value!(SelectInstruction); 65 | -------------------------------------------------------------------------------- /src/values/instruction/store.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetOperand; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// [Store instruction](https://llvm.org/docs/LangRef.html#store-instruction) 9 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct StoreInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 11 | 12 | impl_instr_debug!(StoreInstruction); 13 | 14 | impl_as_operand_for_instr!(StoreInstruction); 15 | 16 | impl_send_sync!(StoreInstruction); 17 | 18 | impl<'ctx> GetDebugMetadata<'ctx> for StoreInstruction<'ctx> {} 19 | 20 | impl<'ctx> InstructionDebugLoc for StoreInstruction<'ctx> {} 21 | 22 | impl<'ctx> InstructionTrait<'ctx> for StoreInstruction<'ctx> {} 23 | 24 | impl<'ctx> StoreInstruction<'ctx> { 25 | /// Get the location operand where the value is stored to 26 | pub fn location(&self) -> Operand<'ctx> { 27 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 1) }) 28 | } 29 | 30 | /// Get the value operand 31 | pub fn value(&self) -> Operand<'ctx> { 32 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 33 | } 34 | } 35 | 36 | impl<'ctx> ValueOpcode for StoreInstruction<'ctx> { 37 | fn opcode(&self) -> Opcode { 38 | Opcode::Store 39 | } 40 | } 41 | 42 | impl<'ctx> AsInstruction<'ctx> for StoreInstruction<'ctx> { 43 | fn as_instruction(&self) -> Instruction<'ctx> { 44 | Instruction::Store(*self) 45 | } 46 | } 47 | 48 | impl_positional_value_ref!(StoreInstruction, 0); 49 | 50 | impl_positional_from_llvm_value!(StoreInstruction); 51 | -------------------------------------------------------------------------------- /src/values/instruction/switch.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetNumOperands, LLVMGetOperand, LLVMValueAsBasicBlock}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use std::marker::PhantomData; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// One Case of switch 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub struct SwitchCase<'ctx> { 11 | /// The value that the switch operand will be checked against. 12 | /// This value is always integer constant. 13 | pub case: IntConstant<'ctx>, 14 | /// The block it will take when the value matches 15 | pub destination: Block<'ctx>, 16 | } 17 | 18 | /// [Switch instruction](https://llvm.org/docs/LangRef.html#switch-instruction) 19 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 20 | pub struct SwitchInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 21 | 22 | impl_instr_debug!(SwitchInstruction); 23 | 24 | impl_as_operand_for_instr!(SwitchInstruction); 25 | 26 | impl_send_sync!(SwitchInstruction); 27 | 28 | impl<'ctx> GetDebugMetadata<'ctx> for SwitchInstruction<'ctx> {} 29 | 30 | impl<'ctx> InstructionDebugLoc for SwitchInstruction<'ctx> {} 31 | 32 | impl<'ctx> InstructionTrait<'ctx> for SwitchInstruction<'ctx> {} 33 | 34 | impl<'ctx> SwitchInstruction<'ctx> { 35 | /// Get the value that is checked against 36 | pub fn condition(&self) -> Operand<'ctx> { 37 | Operand::from_llvm(unsafe { LLVMGetOperand(self.0, 0) }) 38 | } 39 | 40 | /// Get the default block, which is the block this instruction will jump to when 41 | /// no branch target is matching the value 42 | pub fn default_destination(&self) -> Block<'ctx> { 43 | let operand = unsafe { LLVMGetOperand(self.0, 1) }; 44 | let block = unsafe { LLVMValueAsBasicBlock(operand) }; 45 | Block::from_llvm(block) 46 | } 47 | 48 | /// Get the number of cases 49 | pub fn num_cases(&self) -> usize { 50 | let num_operands = unsafe { LLVMGetNumOperands(self.0) as usize }; 51 | (num_operands - 2) / 2 52 | } 53 | 54 | /// Get the cases 55 | pub fn cases(&self) -> Vec> { 56 | (0..self.num_cases() as u32) 57 | .map(|i| SwitchCase { 58 | case: IntConstant::from_llvm(unsafe { LLVMGetOperand(self.0, i * 2 + 2) }), 59 | destination: Block::from_llvm(unsafe { LLVMValueAsBasicBlock(LLVMGetOperand(self.0, i * 2 + 3)) }), 60 | }) 61 | .collect() 62 | } 63 | 64 | /// Get destination blocks 65 | pub fn destinations(&self) -> Vec> { 66 | vec![ 67 | vec![self.default_destination()], 68 | self.cases().into_iter().map(|case| case.destination).collect(), 69 | ] 70 | .concat() 71 | } 72 | } 73 | 74 | impl<'ctx> ValueOpcode for SwitchInstruction<'ctx> { 75 | fn opcode(&self) -> Opcode { 76 | Opcode::Switch 77 | } 78 | } 79 | 80 | impl<'ctx> AsInstruction<'ctx> for SwitchInstruction<'ctx> { 81 | fn as_instruction(&self) -> Instruction<'ctx> { 82 | Instruction::Switch(*self) 83 | } 84 | } 85 | 86 | impl_positional_value_ref!(SwitchInstruction, 0); 87 | 88 | impl_positional_from_llvm_value!(SwitchInstruction); 89 | -------------------------------------------------------------------------------- /src/values/instruction/traits.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | 3 | use crate::values::*; 4 | use crate::*; 5 | 6 | /// Turn instructions into Instruction Container Enum 7 | pub trait AsInstruction<'ctx> { 8 | fn as_instruction(&self) -> Instruction<'ctx>; 9 | } 10 | 11 | pub trait ValueOpcode { 12 | fn opcode(&self) -> Opcode; 13 | } 14 | 15 | pub trait InstructionTrait<'ctx>: AsInstruction<'ctx> + ValueRef { 16 | /// Get the parent block 17 | fn parent_block(&self) -> Block<'ctx> { 18 | let value = unsafe { LLVMGetInstructionParent(self.value_ref()) }; 19 | Block::from_llvm(value) 20 | } 21 | 22 | /// Get the parent function 23 | fn parent_function(&self) -> Function<'ctx> { 24 | self.parent_block().parent_function() 25 | } 26 | 27 | /// Get the previous instruction of this one 28 | fn prev_instruction(&self) -> Option> { 29 | let this_ptr = self.value_ref(); 30 | let prev_ptr = unsafe { LLVMGetPreviousInstruction(this_ptr) }; 31 | if prev_ptr.is_null() { 32 | None 33 | } else { 34 | Some(Instruction::from_llvm(prev_ptr)) 35 | } 36 | } 37 | 38 | /// Get the next instruction of this one 39 | fn next_instruction(&self) -> Option> { 40 | let this_ptr = self.value_ref(); 41 | let next_ptr = unsafe { LLVMGetNextInstruction(this_ptr) }; 42 | if next_ptr.is_null() { 43 | None 44 | } else { 45 | Some(Instruction::from_llvm(next_ptr)) 46 | } 47 | } 48 | 49 | /// Get the number of operands used in this instruction 50 | fn num_operands(&self) -> usize { 51 | unsafe { LLVMGetNumOperands(self.value_ref()) as usize } 52 | } 53 | 54 | /// Get the operand at a given index 55 | fn operand(&self, index: usize) -> Option> { 56 | if index < self.num_operands() { 57 | Some(Operand::from_llvm(unsafe { 58 | LLVMGetOperand(self.value_ref(), index as u32) 59 | })) 60 | } else { 61 | None 62 | } 63 | } 64 | 65 | /// Iterate all the operands of the instruction 66 | fn iter_operands(&self) -> InstructionOperandIterator<'ctx> { 67 | InstructionOperandIterator { instr: self.as_instruction(), curr_index: 0 } 68 | } 69 | 70 | /// Get the string representation of the instruction 71 | fn to_string(&self) -> String { 72 | unsafe { utils::raw_to_string(LLVMPrintValueToString(self.value_ref())) } 73 | } 74 | } 75 | 76 | #[doc(hidden)] 77 | pub struct InstructionOperandIterator<'ctx> { 78 | instr: Instruction<'ctx>, 79 | curr_index: usize, 80 | } 81 | 82 | impl<'ctx> Iterator for InstructionOperandIterator<'ctx> { 83 | type Item = Operand<'ctx>; 84 | 85 | fn next(&mut self) -> Option { 86 | if self.curr_index < self.instr.num_operands() { 87 | let item = self.instr.operand(self.curr_index); 88 | self.curr_index += 1; 89 | Some(item.unwrap()) 90 | } else { 91 | None 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/values/instruction/unary.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetInstructionOpcode, LLVMGetOperand}; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMOpcode; 4 | use std::marker::PhantomData; 5 | 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// Unary opcode 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub enum UnaryOpcode { 12 | FNeg, 13 | Trunc, 14 | ZExt, 15 | SExt, 16 | FPToUI, 17 | FPToSI, 18 | UIToFP, 19 | SIToFP, 20 | FPTrunc, 21 | FPExt, 22 | PtrToInt, 23 | IntToPtr, 24 | BitCast, 25 | } 26 | 27 | impl UnaryOpcode { 28 | pub fn from_llvm(llvm_opcode: LLVMOpcode) -> Option { 29 | match llvm_opcode { 30 | LLVMOpcode::LLVMFNeg => Some(Self::FNeg), 31 | LLVMOpcode::LLVMTrunc => Some(Self::Trunc), 32 | LLVMOpcode::LLVMZExt => Some(Self::ZExt), 33 | LLVMOpcode::LLVMSExt => Some(Self::SExt), 34 | LLVMOpcode::LLVMFPToUI => Some(Self::FPToUI), 35 | LLVMOpcode::LLVMFPToSI => Some(Self::FPToSI), 36 | LLVMOpcode::LLVMUIToFP => Some(Self::UIToFP), 37 | LLVMOpcode::LLVMSIToFP => Some(Self::SIToFP), 38 | LLVMOpcode::LLVMFPTrunc => Some(Self::FPTrunc), 39 | LLVMOpcode::LLVMFPExt => Some(Self::FPExt), 40 | LLVMOpcode::LLVMPtrToInt => Some(Self::PtrToInt), 41 | LLVMOpcode::LLVMIntToPtr => Some(Self::IntToPtr), 42 | LLVMOpcode::LLVMBitCast => Some(Self::BitCast), 43 | _ => None, 44 | } 45 | } 46 | 47 | pub fn to_string(&self) -> &str { 48 | match self { 49 | Self::FNeg => "fneg", 50 | Self::Trunc => "trunc", 51 | Self::ZExt => "zext", 52 | Self::SExt => "sext", 53 | Self::FPToUI => "fptoui", 54 | Self::FPToSI => "fptosi", 55 | Self::UIToFP => "uitofp", 56 | Self::SIToFP => "sitofp", 57 | Self::FPTrunc => "fptrunc", 58 | Self::FPExt => "fpext", 59 | Self::PtrToInt => "ptrtoint", 60 | Self::IntToPtr => "inttoptr", 61 | Self::BitCast => "bitcast", 62 | } 63 | } 64 | } 65 | 66 | /// [Unary instruction](https://llvm.org/docs/LangRef.html#unary-operations) 67 | /// 68 | /// Covers the following instruction opcodes: 69 | /// - [Unary](https://llvm.org/docs/LangRef.html#unary-operations) 70 | /// - [FNeg](https://llvm.org/docs/LangRef.html#fneg-instruction) 71 | /// - [Conversion](https://llvm.org/docs/LangRef.html#conversion-operations) 72 | /// - [Trunc](https://llvm.org/docs/LangRef.html#trunc-to-instruction) 73 | /// - [ZExt](https://llvm.org/docs/LangRef.html#zext-to-instruction) 74 | /// - [SExt](https://llvm.org/docs/LangRef.html#sext-to-instruction) 75 | /// - [FPToUI](https://llvm.org/docs/LangRef.html#fptoui-to-instruction) 76 | /// - [FPToSI](https://llvm.org/docs/LangRef.html#fptosi-to-instruction) 77 | /// - [UIToFP](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) 78 | /// - [SIToFP](https://llvm.org/docs/LangRef.html#sitofp-to-instruction) 79 | /// - [FPTrunc](https://llvm.org/docs/LangRef.html#fptrunc-to-instruction) 80 | /// - [FPExt](https://llvm.org/docs/LangRef.html#fpext-to-instruction) 81 | /// - [PtrToInt](https://llvm.org/docs/LangRef.html#ptrtoint-to-instruction) 82 | /// - [IntToPtr](https://llvm.org/docs/LangRef.html#inttoptr-to-instruction) 83 | /// - [BitCast](https://llvm.org/docs/LangRef.html#bitcast-to-instruction) 84 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 85 | pub struct UnaryInstruction<'ctx>(UnaryOpcode, LLVMValueRef, PhantomData<&'ctx ()>); 86 | 87 | impl_instr_debug!(UnaryInstruction); 88 | 89 | impl_as_operand_for_instr!(UnaryInstruction); 90 | 91 | impl_send_sync!(UnaryInstruction); 92 | 93 | impl<'ctx> GetType<'ctx> for UnaryInstruction<'ctx> {} 94 | 95 | impl<'ctx> GetDebugMetadata<'ctx> for UnaryInstruction<'ctx> {} 96 | 97 | impl<'ctx> InstructionDebugLoc for UnaryInstruction<'ctx> {} 98 | 99 | impl<'ctx> InstructionTrait<'ctx> for UnaryInstruction<'ctx> {} 100 | 101 | impl<'ctx> UnaryInstruction<'ctx> { 102 | /// Get the opcode of this unary instruction 103 | pub fn unary_opcode(&self) -> UnaryOpcode { 104 | self.0 105 | } 106 | 107 | /// Get the operand 108 | pub fn op0(&self) -> Operand<'ctx> { 109 | Operand::from_llvm(unsafe { LLVMGetOperand(self.1, 0) }) 110 | } 111 | } 112 | 113 | impl<'ctx> ValueOpcode for UnaryInstruction<'ctx> { 114 | fn opcode(&self) -> Opcode { 115 | Opcode::Unary(self.unary_opcode()) 116 | } 117 | } 118 | 119 | impl<'ctx> AsInstruction<'ctx> for UnaryInstruction<'ctx> { 120 | fn as_instruction(&self) -> Instruction<'ctx> { 121 | Instruction::Unary(*self) 122 | } 123 | } 124 | 125 | impl_op_from_llvm_value!(UnaryInstruction, UnaryOpcode, LLVMGetInstructionOpcode); 126 | 127 | impl_positional_value_ref!(UnaryInstruction, 1); 128 | -------------------------------------------------------------------------------- /src/values/instruction/unreachable.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// [Unreachable instruction](https://llvm.org/docs/LangRef.html#unreachable-instruction) 8 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct UnreachableInstruction<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_instr_debug!(UnreachableInstruction); 12 | 13 | impl_as_operand_for_instr!(UnreachableInstruction); 14 | 15 | impl_send_sync!(UnreachableInstruction); 16 | 17 | impl<'ctx> InstructionDebugLoc for UnreachableInstruction<'ctx> {} 18 | 19 | impl<'ctx> InstructionTrait<'ctx> for UnreachableInstruction<'ctx> {} 20 | 21 | impl<'ctx> GetDebugMetadata<'ctx> for UnreachableInstruction<'ctx> {} 22 | 23 | impl<'ctx> ValueOpcode for UnreachableInstruction<'ctx> { 24 | fn opcode(&self) -> Opcode { 25 | Opcode::Unreachable 26 | } 27 | } 28 | 29 | impl<'ctx> AsInstruction<'ctx> for UnreachableInstruction<'ctx> { 30 | fn as_instruction(&self) -> Instruction<'ctx> { 31 | Instruction::Unreachable(*self) 32 | } 33 | } 34 | 35 | impl_positional_value_ref!(UnreachableInstruction, 0); 36 | 37 | impl_positional_from_llvm_value!(UnreachableInstruction); 38 | -------------------------------------------------------------------------------- /src/values/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_positional_value_ref { 2 | ($id:ident, $pos:tt) => { 3 | impl<'ctx> ValueRef for $id<'ctx> { 4 | fn value_ref(&self) -> LLVMValueRef { 5 | self.$pos 6 | } 7 | } 8 | } 9 | } 10 | 11 | macro_rules! impl_positional_from_llvm_value { 12 | ($id:ident) => { 13 | impl<'ctx> FromLLVMValue for $id<'ctx> { 14 | fn from_llvm(ptr: LLVMValueRef) -> Self { 15 | Self(ptr, PhantomData) 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /src/values/metadata/const_as_md.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// Constant as Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct ConstantAsMetadata<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(ConstantAsMetadata); 12 | 13 | impl_send_sync!(ConstantAsMetadata); 14 | 15 | impl_positional_value_ref!(ConstantAsMetadata, 0); 16 | 17 | impl_positional_from_llvm_value!(ConstantAsMetadata); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for ConstantAsMetadata<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::ConstantAsMetadata(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/di_expression.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// DI Expression Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct DIExpression<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(DIExpression); 12 | 13 | impl_send_sync!(DIExpression); 14 | 15 | impl_positional_value_ref!(DIExpression, 0); 16 | 17 | impl_positional_from_llvm_value!(DIExpression); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for DIExpression<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::DIExpression(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/di_label.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// DI Label Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct DILabel<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(DILabel); 12 | 13 | impl_send_sync!(DILabel); 14 | 15 | impl_positional_value_ref!(DILabel, 0); 16 | 17 | impl_positional_from_llvm_value!(DILabel); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for DILabel<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::DILabel(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/di_local_var.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// DI Local Variable Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct DILocalVariable<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(DILocalVariable); 12 | 13 | impl_send_sync!(DILocalVariable); 14 | 15 | impl_positional_value_ref!(DILocalVariable, 0); 16 | 17 | impl_positional_from_llvm_value!(DILocalVariable); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for DILocalVariable<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::DILocalVariable(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/di_location.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::debuginfo::*; 3 | use llvm_sys::prelude::LLVMValueRef; 4 | use std::marker::PhantomData; 5 | 6 | use crate::values::*; 7 | use crate::*; 8 | 9 | /// DI Location Metadata 10 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 | pub struct DILocation<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 12 | 13 | impl_as_operand_for_metadata!(DILocation); 14 | 15 | impl_send_sync!(DILocation); 16 | 17 | impl<'ctx> DILocation<'ctx> { 18 | /// Get the column number 19 | pub fn col(&self) -> usize { 20 | unsafe { LLVMDILocationGetColumn(LLVMValueAsMetadata(self.0)) as usize } 21 | } 22 | 23 | /// Get the line number 24 | pub fn line(&self) -> usize { 25 | unsafe { LLVMDILocationGetLine(LLVMValueAsMetadata(self.0)) as usize } 26 | } 27 | } 28 | 29 | impl_positional_value_ref!(DILocation, 0); 30 | 31 | impl_positional_from_llvm_value!(DILocation); 32 | 33 | impl<'ctx> AsMetadata<'ctx> for DILocation<'ctx> { 34 | fn as_metadata(&self) -> Metadata<'ctx> { 35 | Metadata::DILocation(self.clone()) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/values/metadata/dist_md_op_ph.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// Distinct Metadata Operand Placeholder 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct DistinctMDOperandPlaceholder<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(DistinctMDOperandPlaceholder); 12 | 13 | impl_send_sync!(DistinctMDOperandPlaceholder); 14 | 15 | impl_positional_value_ref!(DistinctMDOperandPlaceholder, 0); 16 | 17 | impl_positional_from_llvm_value!(DistinctMDOperandPlaceholder); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for DistinctMDOperandPlaceholder<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::DistinctMDOperandPlaceholder(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/generic_di_node.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// Generic DI Node Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct GenericDINode<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(GenericDINode); 12 | 13 | impl_send_sync!(GenericDINode); 14 | 15 | impl_positional_value_ref!(GenericDINode, 0); 16 | 17 | impl_positional_from_llvm_value!(GenericDINode); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for GenericDINode<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::GenericDINode(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/local_as_md.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// Local as Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct LocalAsMetadata<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(LocalAsMetadata); 12 | 13 | impl_send_sync!(LocalAsMetadata); 14 | 15 | impl_positional_value_ref!(LocalAsMetadata, 0); 16 | 17 | impl_positional_from_llvm_value!(LocalAsMetadata); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for LocalAsMetadata<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::LocalAsMetadata(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! impl_as_operand_for_metadata { 2 | ($id:ident) => { 3 | impl<'ctx> AsOperand<'ctx> for $id<'ctx> { 4 | fn as_operand(&self) -> Operand<'ctx> { 5 | Operand::Metadata(self.as_metadata()) 6 | } 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/values/metadata/md_tuple.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::prelude::LLVMValueRef; 2 | use std::marker::PhantomData; 3 | 4 | use crate::values::*; 5 | use crate::*; 6 | 7 | /// MD Tuple Metadata 8 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 9 | pub struct MDTuple<'ctx>(LLVMValueRef, PhantomData<&'ctx ()>); 10 | 11 | impl_as_operand_for_metadata!(MDTuple); 12 | 13 | impl_send_sync!(MDTuple); 14 | 15 | impl_positional_value_ref!(MDTuple, 0); 16 | 17 | impl_positional_from_llvm_value!(MDTuple); 18 | 19 | impl<'ctx> AsMetadata<'ctx> for MDTuple<'ctx> { 20 | fn as_metadata(&self) -> Metadata<'ctx> { 21 | Metadata::MDTuple(self.clone()) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/values/metadata/metadata.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::*; 2 | use llvm_sys::debuginfo::*; 3 | use llvm_sys::prelude::LLVMValueRef; 4 | 5 | use crate::values::*; 6 | use crate::{FromLLVMValue, ValueRef}; 7 | 8 | /// [Metadata](https://llvm.org/docs/LangRef.html#metadata) 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub enum Metadata<'ctx> { 11 | ConstantAsMetadata(ConstantAsMetadata<'ctx>), 12 | DIExpression(DIExpression<'ctx>), 13 | DILabel(DILabel<'ctx>), 14 | DILocalVariable(DILocalVariable<'ctx>), 15 | DILocation(DILocation<'ctx>), 16 | DistinctMDOperandPlaceholder(DistinctMDOperandPlaceholder<'ctx>), 17 | GenericDINode(GenericDINode<'ctx>), 18 | LocalAsMetadata(LocalAsMetadata<'ctx>), 19 | MDTuple(MDTuple<'ctx>), 20 | Other(GenericValue<'ctx>), 21 | } 22 | 23 | impl<'ctx> FromLLVMValue for Metadata<'ctx> { 24 | fn from_llvm(ptr: LLVMValueRef) -> Self { 25 | use LLVMMetadataKind::*; 26 | match unsafe { LLVMGetMetadataKind(LLVMValueAsMetadata(ptr)) } { 27 | LLVMConstantAsMetadataMetadataKind => Self::ConstantAsMetadata(ConstantAsMetadata::from_llvm(ptr)), 28 | LLVMDIExpressionMetadataKind => Self::DIExpression(DIExpression::from_llvm(ptr)), 29 | LLVMDILabelMetadataKind => Self::DILabel(DILabel::from_llvm(ptr)), 30 | LLVMDILocalVariableMetadataKind => Self::DILocalVariable(DILocalVariable::from_llvm(ptr)), 31 | LLVMDILocationMetadataKind => Self::DILocation(DILocation::from_llvm(ptr)), 32 | LLVMDistinctMDOperandPlaceholderMetadataKind => { 33 | Self::DistinctMDOperandPlaceholder(DistinctMDOperandPlaceholder::from_llvm(ptr)) 34 | } 35 | LLVMGenericDINodeMetadataKind => Self::GenericDINode(GenericDINode::from_llvm(ptr)), 36 | LLVMLocalAsMetadataMetadataKind => Self::LocalAsMetadata(LocalAsMetadata::from_llvm(ptr)), 37 | LLVMMDTupleMetadataKind => Self::MDTuple(MDTuple::from_llvm(ptr)), 38 | _ => Self::Other(GenericValue::from_llvm(ptr)), 39 | } 40 | } 41 | } 42 | 43 | impl<'ctx> ValueRef for Metadata<'ctx> { 44 | fn value_ref(&self) -> LLVMValueRef { 45 | match self { 46 | Self::ConstantAsMetadata(c) => c.value_ref(), 47 | Self::DIExpression(e) => e.value_ref(), 48 | Self::DILabel(l) => l.value_ref(), 49 | Self::DILocalVariable(lv) => lv.value_ref(), 50 | Self::DILocation(l) => l.value_ref(), 51 | Self::DistinctMDOperandPlaceholder(d) => d.value_ref(), 52 | Self::GenericDINode(g) => g.value_ref(), 53 | Self::LocalAsMetadata(lam) => lam.value_ref(), 54 | Self::MDTuple(t) => t.value_ref(), 55 | Self::Other(g) => g.value_ref(), 56 | } 57 | } 58 | } 59 | 60 | impl<'ctx> AsMetadata<'ctx> for Metadata<'ctx> { 61 | fn as_metadata(&self) -> Self { 62 | self.clone() 63 | } 64 | } 65 | 66 | impl_as_operand_for_metadata!(Metadata); 67 | -------------------------------------------------------------------------------- /src/values/metadata/mod.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | mod macros; 3 | pub use macros::*; 4 | 5 | mod const_as_md; 6 | mod traits; 7 | mod metadata; 8 | mod dist_md_op_ph; 9 | mod generic_di_node; 10 | mod di_label; 11 | mod local_as_md; 12 | mod di_expression; 13 | mod di_local_var; 14 | mod di_location; 15 | mod md_tuple; 16 | pub use const_as_md::*; 17 | pub use metadata::*; 18 | pub use dist_md_op_ph::*; 19 | pub use generic_di_node::*; 20 | pub use di_label::*; 21 | pub use traits::*; 22 | pub use local_as_md::*; 23 | pub use di_local_var::*; 24 | pub use di_expression::*; 25 | pub use di_location::*; 26 | pub use md_tuple::*; 27 | -------------------------------------------------------------------------------- /src/values/metadata/traits.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | /// Turn metadata subclass into a Metadata enum 4 | pub trait AsMetadata<'ctx> { 5 | fn as_metadata(&self) -> Metadata<'ctx>; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /src/values/operand.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::LLVMGetValueKind; 2 | use llvm_sys::prelude::LLVMValueRef; 3 | use llvm_sys::LLVMValueKind; 4 | 5 | use crate::values::*; 6 | use crate::*; 7 | 8 | /// Container class for operand 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 10 | pub enum Operand<'ctx> { 11 | /// Result from a previous local instruction as operand 12 | Instruction(Instruction<'ctx>), 13 | /// Function argument as operand 14 | Argument(Argument<'ctx>), 15 | /// Constant as operand 16 | Constant(Constant<'ctx>), 17 | /// Inline Assembly as operand 18 | InlineAsm(InlineAsm<'ctx>), 19 | /// Metadata as operand 20 | Metadata(Metadata<'ctx>), 21 | } 22 | 23 | impl<'ctx> GetType<'ctx> for Operand<'ctx> {} 24 | 25 | impl<'ctx> FromLLVMValue for Operand<'ctx> { 26 | fn from_llvm(ptr: LLVMValueRef) -> Self { 27 | use LLVMValueKind::*; 28 | match unsafe { LLVMGetValueKind(ptr) } { 29 | LLVMArgumentValueKind => Self::Argument(Argument::from_llvm(ptr)), 30 | LLVMInstructionValueKind => Self::Instruction(Instruction::from_llvm(ptr)), 31 | LLVMMetadataAsValueValueKind => Self::Metadata(Metadata::from_llvm(ptr)), 32 | LLVMInlineAsmValueKind => Self::InlineAsm(InlineAsm::from_llvm(ptr)), 33 | _ => Self::Constant(Constant::from_llvm(ptr)), 34 | } 35 | } 36 | } 37 | 38 | impl<'ctx> ValueRef for Operand<'ctx> { 39 | fn value_ref(&self) -> LLVMValueRef { 40 | match self { 41 | Operand::Instruction(instr) => instr.value_ref(), 42 | Operand::Argument(arg) => arg.value_ref(), 43 | Operand::Constant(constant) => constant.value_ref(), 44 | Operand::InlineAsm(asm) => asm.value_ref(), 45 | Operand::Metadata(metadata) => metadata.value_ref(), 46 | } 47 | } 48 | } 49 | 50 | impl<'ctx> AsOperand<'ctx> for Operand<'ctx> { 51 | fn as_operand(&self) -> Operand<'ctx> { 52 | self.clone() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/values/traits.rs: -------------------------------------------------------------------------------- 1 | use llvm_sys::core::{LLVMGetDebugLocColumn, LLVMGetDebugLocLine, LLVMTypeOf}; 2 | 3 | use super::*; 4 | use crate::types::*; 5 | use crate::utils::*; 6 | use crate::*; 7 | 8 | /// GetType trait provides `get_type` functions 9 | pub trait GetType<'ctx>: ValueRef { 10 | fn get_type(&self) -> Type<'ctx> { 11 | Type::from_llvm(unsafe { LLVMTypeOf(self.value_ref()) }) 12 | } 13 | } 14 | 15 | /// Get debug metadata for any value 16 | pub trait GetDebugMetadata<'ctx>: ValueRef { 17 | fn dbg_metadata(&self) -> Option> { 18 | mdkind_ids::dbg_metadata(self.value_ref()).map(Metadata::from_llvm) 19 | } 20 | } 21 | 22 | /// Trait that turns a value into an operand 23 | pub trait AsOperand<'ctx> { 24 | fn as_operand(&self) -> Operand<'ctx>; 25 | } 26 | 27 | /// InstructionDebugLoc is implemented whenever it is an instruction 28 | pub trait InstructionDebugLoc {} 29 | 30 | /// GetDebugLoc trait is implemented when there's debug location with respect 31 | /// to a value 32 | pub trait GetDebugLoc { 33 | fn filename(&self) -> Option; 34 | 35 | fn line(&self) -> Option; 36 | 37 | fn col(&self) -> Option; 38 | 39 | fn debug_loc_string(&self) -> String { 40 | match self.filename() { 41 | Some(file) => match (self.line(), self.col()) { 42 | (Some(line), Some(col)) => return format!("{}:{}:{}", file, line, col), 43 | _ => return file, 44 | }, 45 | _ => {} 46 | }; 47 | String::new() 48 | } 49 | } 50 | 51 | impl<'ctx, V> GetDebugLoc for V 52 | where 53 | V: InstructionDebugLoc + ValueRef, 54 | { 55 | fn filename(&self) -> Option { 56 | match ( 57 | string_of_debugloc_directory(self.value_ref()), 58 | string_of_debugloc_filename(self.value_ref()), 59 | ) { 60 | (Some(dir), Some(file)) => Some(format!("{}/{}", dir, file)), 61 | _ => None, 62 | } 63 | } 64 | 65 | fn line(&self) -> Option { 66 | Some(unsafe { LLVMGetDebugLocLine(self.value_ref()) }) 67 | } 68 | 69 | fn col(&self) -> Option { 70 | Some(unsafe { LLVMGetDebugLocColumn(self.value_ref()) }) 71 | } 72 | } 73 | 74 | /// Turn the value into a GenericValue, implemented for every value class 75 | pub trait AsGenericValue<'ctx>: ValueRef { 76 | fn as_generic_value(&self) -> GenericValue<'ctx> { 77 | GenericValue::new(self.value_ref()) 78 | } 79 | } 80 | 81 | impl<'ctx, V> AsGenericValue<'ctx> for V where V: ValueRef {} 82 | -------------------------------------------------------------------------------- /tests/block_name.rs: -------------------------------------------------------------------------------- 1 | use llir; 2 | use std::path::Path; 3 | 4 | #[test] 5 | fn fn_ptr_1_block_name() -> Result<(), String> { 6 | let path = Path::new("tests/c_files/fn_ptr/fn_ptr_1.bc"); 7 | let context = llir::Context::create(); 8 | let module = context.load_module(path)?; 9 | for func in module.iter_functions() { 10 | for block in func.iter_blocks() { 11 | println!("{}", block.name()); 12 | } 13 | } 14 | Ok(()) 15 | } 16 | -------------------------------------------------------------------------------- /tests/c_files/argrel/argrel_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int f() { 5 | return 8; 6 | } 7 | 8 | int main() { 9 | int size = f(); 10 | char *p1 = (char *)malloc(size + 1); 11 | char *p2 = (char *)malloc(2); 12 | strncpy(p1, p2, size); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/c_files/argrel/argrel_2.c: -------------------------------------------------------------------------------- 1 | extern int g(); 2 | 3 | int f(int size) { 4 | char *p1 = malloc(size + 1); 5 | char *p2 = malloc(size); 6 | strcpy(p1, p2); 7 | } 8 | 9 | int main(int argc, char **argv) { 10 | int s = g(); 11 | f(s); 12 | } -------------------------------------------------------------------------------- /tests/c_files/argval/argval_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void my_free(void *ptr) { 4 | ptr = 0; 5 | } 6 | 7 | void free_wrapper(void *ptr) { 8 | my_free(ptr); 9 | } 10 | 11 | void f() { 12 | int *ptr = (int *) malloc(10); 13 | ptr[3] = 30; 14 | ptr[9] = 90; 15 | free_wrapper(ptr); 16 | } 17 | 18 | void g() { 19 | int *ptr = (int *) malloc(10); 20 | ptr[3] = 30; 21 | ptr[9] = 90; 22 | if (ptr != NULL) { 23 | free_wrapper(ptr); 24 | } 25 | } -------------------------------------------------------------------------------- /tests/c_files/argval/argval_2.c: -------------------------------------------------------------------------------- 1 | void *malloc(int size); 2 | 3 | void free(void *ptr) { 4 | ptr = 0; 5 | } 6 | 7 | int f(int i, int j) { 8 | int sum = i + j; 9 | int *ptr = (int *) malloc(sum); 10 | ptr[0] = 10; 11 | free(ptr); 12 | return sum; 13 | } -------------------------------------------------------------------------------- /tests/c_files/argval/argval_3.c: -------------------------------------------------------------------------------- 1 | int free(int s) { 2 | return s; 3 | } 4 | 5 | int g(int i, int j) { 6 | return free(i + j); 7 | } 8 | 9 | int f(int i) { 10 | int j = g(i, 3); 11 | return j; 12 | } -------------------------------------------------------------------------------- /tests/c_files/argval/argval_uses.c: -------------------------------------------------------------------------------- 1 | void kfree(void *ptr); 2 | 3 | struct Object { 4 | int i; 5 | }; 6 | 7 | // This tests argument used after function call 8 | void run1(int i, struct Object* obj) { 9 | kfree(obj); 10 | if (i == 0) { 11 | obj->i = 10; 12 | } 13 | } 14 | 15 | // This tests argument used after call in a function call 16 | void run2(int i, struct Object* obj) { 17 | kfree(obj); 18 | if (i == 0) { 19 | kfree(obj); 20 | } 21 | } -------------------------------------------------------------------------------- /tests/c_files/basic/example_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void g(int *p) { 4 | if (p != 0) { 5 | p[0] = 10; 6 | } 7 | } 8 | 9 | void h(int *p) { p[1] = 20; } 10 | 11 | void f(int size) { 12 | int *p = (int *)malloc(size * sizeof(int)); 13 | g(p); 14 | h(p); 15 | } 16 | 17 | int main() { 18 | int i = 0; 19 | int j = 10; 20 | f(i + j); 21 | } 22 | -------------------------------------------------------------------------------- /tests/c_files/basic/example_2.c: -------------------------------------------------------------------------------- 1 | int sum(int a, int b) { 2 | return a + b; 3 | } 4 | 5 | void mutate(int *ptr, int idx, int val) { 6 | ptr[idx] = val; 7 | } 8 | 9 | int main() { 10 | int i = sum(3, 4); 11 | int j = sum(i, 5); 12 | int *p = (int *) malloc(i * j * sizeof(int)); 13 | p[0] = 10; 14 | mutate(p, 2, 30); 15 | } -------------------------------------------------------------------------------- /tests/c_files/basic/example_3.c: -------------------------------------------------------------------------------- 1 | int g(int x) { 2 | return x; 3 | } 4 | 5 | void *f(int z) { 6 | int y = g(z); 7 | return malloc(y * sizeof(int)); 8 | } 9 | 10 | int h(int x) { 11 | return g(x); 12 | } 13 | 14 | int main() { 15 | f(0); 16 | h(1); 17 | } -------------------------------------------------------------------------------- /tests/c_files/basic/example_4.c: -------------------------------------------------------------------------------- 1 | int z1() { 2 | printf("Hello world\n"); 3 | } 4 | 5 | int y1() { 6 | z1(); 7 | } 8 | 9 | int x1() { 10 | y1(); 11 | } 12 | 13 | int x2() { 14 | y1(); 15 | } 16 | 17 | int main() { 18 | x1(); 19 | x2(); 20 | } -------------------------------------------------------------------------------- /tests/c_files/basic/example_5.c: -------------------------------------------------------------------------------- 1 | int *f(int x) { 2 | return malloc(x * sizeof(int)); 3 | } 4 | 5 | int main() { 6 | int x = 1; // x has to be greater than 0 7 | int *z; 8 | z = f(x); 9 | if (z != 0) { 10 | z[0] = 10; 11 | } 12 | } -------------------------------------------------------------------------------- /tests/c_files/basic/example_6.c: -------------------------------------------------------------------------------- 1 | // The goal of this example is to test if the target function itself will be included in the slice/trace 2 | // The main function will call f, g, and h. 3 | // When the target is (main -> g), then the slide should be [main, f, h], and the trace should be 4 | // [call f, printf("call from f"), call g, call h, printf("call from h")] 5 | 6 | int h() { 7 | printf("call from h"); 8 | } 9 | 10 | int g() { 11 | printf("call from g"); 12 | } 13 | 14 | int f() { 15 | printf("call from f"); 16 | } 17 | 18 | int main() { 19 | f(); 20 | g(); 21 | h(); 22 | } -------------------------------------------------------------------------------- /tests/c_files/basic/example_7.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char *f(int x) { 4 | char *p = (char *)malloc(4 * x); 5 | return p; 6 | } 7 | 8 | int main() { 9 | int x = 0; 10 | char *p = f(x); 11 | if (!p) 12 | *p = 1; 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/c_files/basic/exit_point.c: -------------------------------------------------------------------------------- 1 | void err_new() { 2 | int *a = 0; 3 | if (a == 0) 4 | return; 5 | a[0] = 10; 6 | } 7 | 8 | int *some_function() { 9 | int i = 0; 10 | if (i == 0) { 11 | err_new(); 12 | } 13 | } 14 | 15 | int main() { 16 | int *ptr = (int *) malloc(sizeof(int) * 4); 17 | int *dont_care = some_function(); 18 | if (ptr != 0) { 19 | ptr[3] = 5; 20 | } 21 | } -------------------------------------------------------------------------------- /tests/c_files/basic/exit_point_2.c: -------------------------------------------------------------------------------- 1 | void some_function() { 2 | int *a = 0; 3 | if (a == 0) 4 | return; 5 | a[0] = 10; 6 | } 7 | 8 | int main() { 9 | int *ptr = (int *) malloc(sizeof(int) * 4); 10 | some_function(); 11 | if (ptr != 0) { 12 | ptr[3] = 5; 13 | } 14 | } -------------------------------------------------------------------------------- /tests/c_files/basic/loop.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i; 3 | for (i = 0; i < 10; i++) { 4 | printf("%d\n", i); 5 | } 6 | } -------------------------------------------------------------------------------- /tests/c_files/basic/loop_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | for (i = 0; i < 10; i++) { 4 | if (i < 5) { 5 | printf("Less than 5\n"); 6 | } else { 7 | printf("Greater than or equal to 5\n"); 8 | } 9 | } 10 | return i; 11 | } -------------------------------------------------------------------------------- /tests/c_files/basic/recursive.c: -------------------------------------------------------------------------------- 1 | int fib(int n) { 2 | if (n == 0) { 3 | return 1; 4 | } else if (n == 1) { 5 | return 1; 6 | } else { 7 | return fib(n - 1) + fib(n - 2); 8 | } 9 | } 10 | 11 | int main() { 12 | int f = fib(5); 13 | printf("%d\n", f); 14 | } -------------------------------------------------------------------------------- /tests/c_files/basic/struct_store.c: -------------------------------------------------------------------------------- 1 | struct A { 2 | void *a; 3 | }; 4 | 5 | int f(struct A* obj) { 6 | obj->a = malloc(8); 7 | if (obj->a == 0) { 8 | return 0; 9 | } 10 | return 1; 11 | } 12 | 13 | int main() { 14 | struct A obj = { a: 0 }; 15 | f(&obj); 16 | } -------------------------------------------------------------------------------- /tests/c_files/basic/struct_store_2.c: -------------------------------------------------------------------------------- 1 | struct A { 2 | int i; 3 | }; 4 | 5 | struct A *f(int i) { 6 | struct A *a = (struct A *) malloc(sizeof(struct A)); 7 | a->i = i; 8 | return a; 9 | } 10 | 11 | int main() { 12 | struct A *a = f(10); 13 | return a->i; 14 | } -------------------------------------------------------------------------------- /tests/c_files/br/br_1.c: -------------------------------------------------------------------------------- 1 | void target(int *p) { 2 | *p = 1; 3 | } 4 | 5 | int main() { 6 | int i = 0; 7 | target(&i); 8 | if (!i) { 9 | goto err; 10 | } 11 | 12 | i += 100; 13 | return 0; 14 | 15 | err: 16 | return -1; 17 | } -------------------------------------------------------------------------------- /tests/c_files/causality/causality_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | FILE *f; 5 | f = fopen("a.c", "w"); 6 | if (f == NULL) { 7 | return 1; 8 | } 9 | fclose(f); 10 | } -------------------------------------------------------------------------------- /tests/c_files/causality/causality_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | FILE *f; 5 | f = fopen("a.c", "w"); 6 | if (f == NULL) { 7 | return 1; 8 | } 9 | fputs("This is so good", f); 10 | fputs("\n", f); 11 | fputs("\n", f); 12 | fputs("\n", f); 13 | fclose(f); 14 | } -------------------------------------------------------------------------------- /tests/c_files/causality/causality_3.c: -------------------------------------------------------------------------------- 1 | #define bool char 2 | 3 | struct Object1 { bool b; }; 4 | struct Object2 { int i; char *str; }; 5 | 6 | void kfree(void *); 7 | 8 | int main() { 9 | struct Object1 obj1_1; 10 | struct Object1 obj1_2; 11 | struct Object2 obj2_1; 12 | 13 | kfree(&obj1_1); 14 | kfree(&obj1_2); 15 | kfree(&obj2_1); 16 | } -------------------------------------------------------------------------------- /tests/c_files/causality/causality_bad_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | FILE *f; 5 | f = fopen("a.c", "w"); 6 | if (f == NULL) { 7 | fclose(f); 8 | } 9 | fclose(f); 10 | } -------------------------------------------------------------------------------- /tests/c_files/fn_ptr/fn_ptr_1.c: -------------------------------------------------------------------------------- 1 | long sum(long a, long b) { 2 | return a + b; 3 | } 4 | 5 | int sub(int a, int b) { 6 | return a - b; 7 | } 8 | 9 | int main() { 10 | int sub_res = sub(10, 20); 11 | int (*fn_ptr)(int, int) = ∑ 12 | int res = fn_ptr(sub_res, 5); 13 | } -------------------------------------------------------------------------------- /tests/c_files/free/free_struct.c: -------------------------------------------------------------------------------- 1 | struct Object { 2 | int index; 3 | char *str; 4 | }; 5 | 6 | void *kzalloc(int size); 7 | 8 | void kfree(void *ptr); 9 | 10 | int main() { 11 | struct Object *obj = (struct Object *) kzalloc(sizeof(struct Object)); 12 | obj->index = 10; 13 | obj->str = (char *) kzalloc(100); 14 | obj->index += 100; 15 | kfree(obj); 16 | } -------------------------------------------------------------------------------- /tests/c_files/git_fopen/git_fopen_1.c: -------------------------------------------------------------------------------- 1 | void *git_fopen(char *, char *); 2 | 3 | void exit(int); 4 | 5 | void fwrite(void *, char *); 6 | 7 | void fclose(void *); 8 | 9 | void good_1() { 10 | void *in; 11 | in = git_fopen("temp.txt", "w"); 12 | if (!in) return; 13 | fwrite(in, "asdfasdfadsfasdf"); 14 | fclose(in); 15 | } 16 | 17 | void bad_5() { 18 | void *in; 19 | in = git_fopen("temp.txt", "w"); 20 | } 21 | 22 | void bad_4() { 23 | void *in; 24 | in = git_fopen("temp.txt", "w"); 25 | if (!in) { 26 | fwrite(in, "asdfasf"); // Cannot write with null file pointer 27 | } 28 | fclose(in); 29 | } 30 | 31 | void bad_3() { 32 | void *in; 33 | in = git_fopen("temp.txt", "w"); 34 | if (!in) { 35 | fclose(in); // Cannot close null file pointer 36 | } 37 | fclose(in); 38 | } 39 | 40 | void bad_2() { 41 | void *in; 42 | in = git_fopen("temp.txt", "w"); 43 | if (!in) { 44 | exit(1); 45 | } 46 | // Doesn't close file 47 | } 48 | 49 | void bad_1() { 50 | void *in; 51 | in = git_fopen("temp.txt", "w"); 52 | // Doesn't check file pointer 53 | fwrite(in, "asdfadfs"); 54 | fclose(in); 55 | } 56 | -------------------------------------------------------------------------------- /tests/c_files/git_fopen/openssl_fopen.c: -------------------------------------------------------------------------------- 1 | void *openssl_fopen(char *, char *); 2 | 3 | void exit(int); 4 | 5 | void fwrite(void *, char *); 6 | 7 | void fclose(void *); 8 | 9 | void good_1() { 10 | void *in; 11 | in = openssl_fopen("temp.txt", "w"); 12 | if (!in) return; 13 | fwrite(in, "asdfasdfadsfasdf"); 14 | fclose(in); 15 | } 16 | 17 | void bad_5() { 18 | void *in; 19 | in = openssl_fopen("temp.txt", "w"); 20 | // No check, no fclose 21 | } 22 | 23 | void bad_4() { 24 | void *in; 25 | in = openssl_fopen("temp.txt", "w"); 26 | if (!in) { 27 | fwrite(in, "asdfasf"); // Cannot write with null file pointer 28 | } 29 | fclose(in); 30 | } 31 | 32 | void bad_3() { 33 | void *in; 34 | in = openssl_fopen("temp.txt", "w"); 35 | if (!in) { 36 | fclose(in); // Cannot close null file pointer 37 | } 38 | fclose(in); 39 | } 40 | 41 | void bad_2() { 42 | void *in; 43 | in = openssl_fopen("temp.txt", "w"); 44 | if (!in) { 45 | exit(1); 46 | } 47 | // Doesn't close file 48 | } 49 | 50 | void bad_1() { 51 | void *in; 52 | in = openssl_fopen("temp.txt", "w"); 53 | // Doesn't check file pointer 54 | fwrite(in, "asdfadfs"); 55 | fclose(in); 56 | } 57 | -------------------------------------------------------------------------------- /tests/c_files/kernel/acpi_lpat_free_conversion_table.c: -------------------------------------------------------------------------------- 1 | void kfree(void *ptr); 2 | 3 | struct acpi_lpat_conversion_table { 4 | void *lpat; 5 | }; 6 | 7 | void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table *lpat_table) { 8 | if (lpat_table) { 9 | kfree(lpat_table->lpat); 10 | kfree(lpat_table); 11 | } 12 | } -------------------------------------------------------------------------------- /tests/c_files/kernel/mce_amd.c: -------------------------------------------------------------------------------- 1 | #define u8 char 2 | #define u16 short 3 | #define bool char 4 | 5 | #define NULL 0 6 | 7 | #define ENODEV -1000 8 | #define ENOMEM -1010 9 | 10 | #define GFP_KERNEL 10 11 | #define X86_VENDOR_AMD 20 12 | 13 | struct cpuinfo_x86 { 14 | int x86_vendor; 15 | int x86; 16 | int x86_model; 17 | }; 18 | 19 | struct amd_decoder_ops { 20 | bool (* mc0_mce)(u16, u8); 21 | bool (* mc1_mce)(u16, u8); 22 | bool (* mc2_mce)(u16, u8); 23 | }; 24 | 25 | struct notifier_block { 26 | 27 | }; 28 | 29 | bool k8_mc0_mce(u16 ec, u8 xec); 30 | 31 | bool k8_mc1_mce(u16 ec, u8 xec); 32 | 33 | bool k8_mc2_mce(u16 ec, u8 xec); 34 | 35 | bool f10h_mc0_mce(u16 ec, u8 xec); 36 | 37 | bool f12h_mc0_mce(u16 ec, u8 xec); 38 | 39 | bool f15h_mc0_mce(u16 ec, u8 xec); 40 | 41 | bool f15h_mc1_mce(u16 ec, u8 xec); 42 | 43 | bool f15h_mc2_mce(u16 ec, u8 xec); 44 | 45 | bool f16h_mc2_mce(u16 ec, u8 xec); 46 | 47 | bool cat_mc0_mce(u16 ec, u8 xec); 48 | 49 | bool cat_mc1_mce(u16 ec, u8 xec); 50 | 51 | void mce_register_decode_chain(struct notifier_block *); 52 | 53 | void *kzalloc(int size, int flag); 54 | 55 | int printk(const char * format, ...); 56 | 57 | void kfree(void *); 58 | 59 | void pr_info(const char *); 60 | 61 | struct notifier_block amd_mce_dec_nb; 62 | 63 | struct cpuinfo_x86 boot_cpu_data; 64 | 65 | struct amd_decoder_ops *fam_ops; 66 | 67 | int xec_mask; 68 | 69 | int mce_amd_init(void) { 70 | struct cpuinfo_x86 *c = &boot_cpu_data; 71 | 72 | if (c->x86_vendor != X86_VENDOR_AMD) 73 | return -ENODEV; 74 | 75 | fam_ops = kzalloc(sizeof(struct amd_decoder_ops), GFP_KERNEL); 76 | if (!fam_ops) 77 | return -ENOMEM; 78 | 79 | switch (c->x86) { 80 | case 0xf: 81 | fam_ops->mc0_mce = k8_mc0_mce; 82 | fam_ops->mc1_mce = k8_mc1_mce; 83 | fam_ops->mc2_mce = k8_mc2_mce; 84 | break; 85 | 86 | case 0x10: 87 | fam_ops->mc0_mce = f10h_mc0_mce; 88 | fam_ops->mc1_mce = k8_mc1_mce; 89 | fam_ops->mc2_mce = k8_mc2_mce; 90 | break; 91 | 92 | case 0x11: 93 | fam_ops->mc0_mce = k8_mc0_mce; 94 | fam_ops->mc1_mce = k8_mc1_mce; 95 | fam_ops->mc2_mce = k8_mc2_mce; 96 | break; 97 | 98 | case 0x12: 99 | fam_ops->mc0_mce = f12h_mc0_mce; 100 | fam_ops->mc1_mce = k8_mc1_mce; 101 | fam_ops->mc2_mce = k8_mc2_mce; 102 | break; 103 | 104 | case 0x14: 105 | fam_ops->mc0_mce = cat_mc0_mce; 106 | fam_ops->mc1_mce = cat_mc1_mce; 107 | fam_ops->mc2_mce = k8_mc2_mce; 108 | break; 109 | 110 | case 0x15: 111 | xec_mask = c->x86_model == 0x60 ? 0x3f : 0x1f; 112 | 113 | fam_ops->mc0_mce = f15h_mc0_mce; 114 | fam_ops->mc1_mce = f15h_mc1_mce; 115 | fam_ops->mc2_mce = f15h_mc2_mce; 116 | break; 117 | 118 | case 0x16: 119 | xec_mask = 0x1f; 120 | fam_ops->mc0_mce = cat_mc0_mce; 121 | fam_ops->mc1_mce = cat_mc1_mce; 122 | fam_ops->mc2_mce = f16h_mc2_mce; 123 | break; 124 | 125 | default: 126 | printk("Huh? What family is it: 0x%x?!\n", c->x86); 127 | kfree(fam_ops); 128 | fam_ops = NULL; 129 | } 130 | 131 | pr_info("MCE: In-kernel MCE decoding enabled.\n"); 132 | 133 | mce_register_decode_chain(&amd_mce_dec_nb); 134 | 135 | return 0; 136 | } -------------------------------------------------------------------------------- /tests/c_files/kernel/rhashtable_free_and_destroy.c: -------------------------------------------------------------------------------- 1 | #define NULL 0 2 | #define bool char 3 | 4 | struct mutex { 5 | int i; 6 | }; 7 | 8 | struct rhash_head { 9 | struct rhash_head *next; 10 | }; 11 | 12 | struct bucket_table { 13 | struct bucket_table *future_tbl; 14 | int size; 15 | }; 16 | 17 | struct rhashtable { 18 | struct bucket_table *tbl; 19 | struct mutex mutex; 20 | int run_work; 21 | }; 22 | 23 | void mutex_lock(struct mutex *lock); 24 | void mutex_unlock(struct mutex *lock); 25 | void cancel_work_sync(int *work); 26 | void *rht_dereference(void *ptr, struct rhashtable *ht); 27 | void cond_resched(); 28 | bool rht_is_a_nulls(struct rhash_head *head); 29 | struct bucket_table *rht_bucket(struct bucket_table *tbl, int i); 30 | void *rht_ptr_exclusive(void *ptr); 31 | void rhashtable_free_one(struct rhashtable *ht, struct rhash_head *hd, void (*free_fn)(void *ptr, void *arg), void *arg); 32 | void bucket_table_free(struct bucket_table *bkt); 33 | 34 | void rhashtable_free_and_destroy(struct rhashtable *ht, void (*free_fn)(void *ptr, void *arg), void *arg) { 35 | struct bucket_table *tbl, *next_tbl; 36 | unsigned int i; 37 | 38 | cancel_work_sync(&ht->run_work); 39 | 40 | mutex_lock(&ht->mutex); 41 | tbl = rht_dereference(ht->tbl, ht); 42 | 43 | restart: 44 | if (free_fn) { 45 | for (i = 0; i < tbl->size; i++) { 46 | struct rhash_head *pos, *next; 47 | cond_resched(); 48 | for (pos = rht_ptr_exclusive(rht_bucket(tbl, i)), 49 | next = !rht_is_a_nulls(pos) ? 50 | rht_dereference(pos->next, ht) : NULL; 51 | !rht_is_a_nulls(pos); 52 | pos = next, 53 | next = !rht_is_a_nulls(pos) ? 54 | rht_dereference(pos->next, ht) : NULL) { 55 | 56 | rhashtable_free_one(ht, pos, free_fn, arg); 57 | } 58 | } 59 | } 60 | 61 | next_tbl = rht_dereference(tbl->future_tbl, ht); 62 | bucket_table_free(tbl); 63 | 64 | mutex_unlock(&ht->mutex); 65 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_1.c: -------------------------------------------------------------------------------- 1 | typedef struct mutex_lock { 2 | int i; 3 | } mutex_lock; 4 | 5 | void lock(mutex_lock *lock) { 6 | lock->i = 0; 7 | } 8 | 9 | void unlock(mutex_lock *lock) { 10 | lock->i = 1; 11 | } 12 | 13 | int main() { 14 | mutex_lock l; 15 | lock(&l); 16 | int b = 3; 17 | for (int i = 0; i < 10; i++) { 18 | b += i; 19 | } 20 | unlock(&l); 21 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_2.c: -------------------------------------------------------------------------------- 1 | // driver/gpu/drm/drm_ctrc.c 2 | 3 | #define NULL 0 4 | #define uint32_t int 5 | #define DRM_MODE_OBJECT_FB 10 6 | 7 | struct lock { 8 | int i; 9 | }; 10 | 11 | struct config { 12 | struct lock idr_mutex; 13 | struct lock fb_lock; 14 | int crtc_idr; 15 | }; 16 | 17 | struct drm_device { 18 | struct config mode_config; 19 | }; 20 | 21 | struct drm_framebuffer { 22 | int refcount; 23 | }; 24 | 25 | struct drm_mode_object { 26 | int type; 27 | int id; 28 | }; 29 | 30 | static void mutex_lock(struct lock *l) { 31 | l->i = 1; 32 | } 33 | 34 | static void mutex_unlock(struct lock *l) { 35 | l->i = 0; 36 | } 37 | 38 | static struct drm_mode_object *idr_find(int crtc_idr, int id) {} 39 | 40 | static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, uint32_t id) { 41 | struct drm_mode_object *obj = NULL; 42 | struct drm_framebuffer *fb; 43 | 44 | mutex_lock(&dev->mode_config.idr_mutex); 45 | obj = idr_find(&dev->mode_config.crtc_idr, id); 46 | if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id)) 47 | fb = NULL; 48 | else 49 | fb = obj_to_fb(obj); 50 | mutex_unlock(&dev->mode_config.idr_mutex); 51 | 52 | return fb; 53 | } 54 | 55 | /** 56 | * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference 57 | * @dev: drm device 58 | * @id: id of the fb object 59 | * 60 | * If successful, this grabs an additional reference to the framebuffer - 61 | * callers need to make sure to eventually unreference the returned framebuffer 62 | * again, using @drm_framebuffer_unreference. 63 | */ 64 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, uint32_t id) { 65 | struct drm_framebuffer *fb; 66 | 67 | mutex_lock(&dev->mode_config.fb_lock); 68 | fb = __drm_framebuffer_lookup(dev, id); 69 | if (fb) { 70 | if (!kref_get_unless_zero(&fb->refcount)) 71 | fb = NULL; 72 | } 73 | mutex_unlock(&dev->mode_config.fb_lock); 74 | 75 | return fb; 76 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_3.c: -------------------------------------------------------------------------------- 1 | // driver/gpu/drm/drm_ctrc.c 2 | 3 | #define NULL 0 4 | #define uint32_t int 5 | #define DRM_MODE_OBJECT_FB 10 6 | 7 | struct lock { 8 | int i; 9 | }; 10 | 11 | struct config { 12 | struct lock idr_mutex; 13 | struct lock fb_lock; 14 | int crtc_idr; 15 | }; 16 | 17 | struct drm_device { 18 | struct config mode_config; 19 | }; 20 | 21 | struct drm_framebuffer { 22 | int refcount; 23 | }; 24 | 25 | struct drm_mode_object { 26 | int type; 27 | int id; 28 | }; 29 | 30 | static void mutex_lock(struct lock *l); 31 | 32 | static void mutex_unlock(struct lock *l); 33 | 34 | static struct drm_mode_object *idr_find(int crtc_idr, int id); 35 | 36 | static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev, uint32_t id); 37 | 38 | struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev, uint32_t id) { 39 | struct drm_framebuffer *fb; 40 | 41 | mutex_lock(&dev->mode_config.fb_lock); 42 | fb = __drm_framebuffer_lookup(dev, id); 43 | if (fb) { 44 | if (!kref_get_unless_zero(&fb->refcount)) 45 | fb = NULL; 46 | } 47 | mutex_unlock(&dev->mode_config.fb_lock); 48 | 49 | return fb; 50 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_4.c: -------------------------------------------------------------------------------- 1 | typedef struct mutex_lock { 2 | int i; 3 | } mutex_lock; 4 | 5 | void lock(mutex_lock *lock) { 6 | lock->i = 0; 7 | } 8 | 9 | void unlock(mutex_lock *lock) { 10 | lock->i = 1; 11 | } 12 | 13 | void run(int i) { 14 | mutex_lock l; 15 | lock(&l); 16 | int b = 3; 17 | for (; i < 10; i++) { 18 | b += i; 19 | } 20 | unlock(&l); 21 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_with_alias.c: -------------------------------------------------------------------------------- 1 | typedef struct mutex_lock { 2 | int i; 3 | } mutex_lock; 4 | 5 | void lock(mutex_lock *lock) { 6 | lock->i = 0; 7 | } 8 | 9 | void unlock(mutex_lock *lock) { 10 | lock->i = 1; 11 | } 12 | 13 | int main() { 14 | mutex_lock l; 15 | lock(&l); 16 | int b = 3; 17 | for (int i = 0; i < 10; i++) { 18 | b += i; 19 | } 20 | mutex_lock *l2 = &l; 21 | unlock(l2); 22 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_with_global.c: -------------------------------------------------------------------------------- 1 | struct mutex { 2 | int flag; 3 | }; 4 | 5 | struct mutex global_lock; 6 | 7 | void mutex_lock(struct mutex *lock) { 8 | lock->flag = 1; 9 | } 10 | 11 | void mutex_unlock(struct mutex *lock) { 12 | lock->flag = 1; 13 | } 14 | 15 | int main() { 16 | global_lock.flag = 10; 17 | 18 | mutex_lock(&global_lock); 19 | int i = 0; 20 | for (i = 0; i < 10; i++) { 21 | printf("%d", i); 22 | } 23 | mutex_unlock(&global_lock); 24 | } -------------------------------------------------------------------------------- /tests/c_files/lock/lock_with_global_2.c: -------------------------------------------------------------------------------- 1 | struct mutex { 2 | int something; 3 | int flag; 4 | }; 5 | 6 | struct mutex global_lock; 7 | 8 | void mutex_lock(struct mutex *lock) { 9 | lock->flag = 1; 10 | } 11 | 12 | void mutex_unlock(struct mutex *lock) { 13 | lock->flag = 1; 14 | } 15 | 16 | int main() { 17 | if (global_lock.something) { 18 | mutex_lock(&global_lock); 19 | } 20 | 21 | int i = 0; 22 | for (i = 0; i < 10; i++) { 23 | printf("%d", i); 24 | } 25 | 26 | if (global_lock.something) { 27 | mutex_unlock(&global_lock); 28 | } 29 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/branch_malloc.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | void *ptr; 4 | if (i) { 5 | ptr = malloc(8); 6 | } else { 7 | ptr = 0; 8 | } 9 | return ptr; 10 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/dugraph_dup.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | if (i == 10) { 4 | int j = 1; 5 | } else { 6 | int k = 2; 7 | } 8 | int *ptr = (int *) malloc(4 * sizeof(int)); 9 | if (i == 20) { 10 | int j = 21; 11 | } else { 12 | int k = 22; 13 | } 14 | ptr[10] = 20; 15 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/dugraph_dup_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | int i = 0; 3 | if (i == 10) { 4 | int j = 1; 5 | } else { 6 | int k = 2; 7 | } 8 | int *ptr = (int *) malloc(4 * sizeof(int)); 9 | if (i == 20) { 10 | ptr[0] = 20; 11 | } else { 12 | ptr[1] = 21; 13 | } 14 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/indexed_1.c: -------------------------------------------------------------------------------- 1 | struct foo { 2 | int i; 3 | int *ptr; 4 | }; 5 | 6 | void *kzalloc(int size); 7 | 8 | int main() { 9 | struct foo foos[10]; 10 | int i, num_elems = 100; 11 | 12 | // Ptr/i 13 | foos[5].ptr = kzalloc(sizeof(int) * num_elems); 14 | foos[5].i = num_elems; 15 | 16 | // Check ptr 17 | if (foos[5].ptr) { 18 | for (i = 0; i < num_elems; i++) { 19 | foos[5].ptr[i] = i; 20 | } 21 | 22 | return 0; 23 | } 24 | 25 | // Return 26 | return 1; 27 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/kzalloc_1.c: -------------------------------------------------------------------------------- 1 | #define NULL 0 2 | #define GFP_KERNEL 0 3 | #define ENOMEM -1 4 | #define INIT_HLIST_HEAD(e) {} 5 | #define ERR_PTR(e) 0 6 | #define _RET_IP_ 100 7 | #define KMALLOC_MAX_CACHE_SIZE 1000 8 | #define size_t int 9 | #define gfp_t int 10 | 11 | struct kmem_cache { 12 | int size; 13 | }; 14 | 15 | extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); 16 | #define kmalloc_track_caller(size, flags) \ 17 | __kmalloc_track_caller(size, flags, _RET_IP_) 18 | 19 | void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller) { 20 | struct kmem_cache *s; 21 | void *ret; 22 | 23 | if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) 24 | return kmalloc_large(size, gfpflags); 25 | 26 | s = kmalloc_slab(size, gfpflags); 27 | 28 | if (unlikely(ZERO_OR_NULL_PTR(s))) 29 | return s; 30 | 31 | ret = slab_alloc(s, gfpflags, caller); 32 | 33 | /* Honor the call site pointer we received. */ 34 | trace_kmalloc(caller, ret, size, s->size, gfpflags); 35 | 36 | return ret; 37 | } 38 | 39 | void memcpy(void *p, void* src, int len); 40 | 41 | void *kmemdup(void *src, int len, int gfp) { 42 | void *p; 43 | p = kmalloc_track_caller(len, gfp); 44 | if (p) 45 | memcpy(p, src, len); 46 | return p; 47 | } 48 | 49 | void *kzalloc(int size, int type); 50 | 51 | void kfree(void *); 52 | 53 | struct hlist_head {}; 54 | 55 | struct net {}; 56 | 57 | struct cache_detail { 58 | struct hlist_head **hash_table; 59 | int hash_size; 60 | struct net *net; 61 | }; 62 | 63 | struct cache_detail *cache_create_net(struct cache_detail *tmpl, struct net *net) { 64 | struct cache_detail *cd; 65 | int i; 66 | 67 | cd = kmemdup(tmpl, sizeof(struct cache_detail), GFP_KERNEL); 68 | if (cd == NULL) 69 | return ERR_PTR(-ENOMEM); 70 | 71 | cd->hash_table = kzalloc(cd->hash_size * sizeof(struct hlist_head), GFP_KERNEL); 72 | if (cd->hash_table == NULL) { 73 | kfree(cd); 74 | return ERR_PTR(-ENOMEM); 75 | } 76 | 77 | for (i = 0; i < cd->hash_size; i++) 78 | INIT_HLIST_HEAD(&cd->hash_table[i]); 79 | cd->net = net; 80 | return cd; 81 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/kzalloc_2.c: -------------------------------------------------------------------------------- 1 | #define uint16_t short 2 | #define uint32_t int 3 | #define false 0 4 | #define true 1 5 | #define bool char 6 | #define NULL 0 7 | #define EINVAL 1000 8 | #define GFP_KERNEL 10000 9 | 10 | struct table_entry { 11 | uint16_t value; 12 | int smio_low; 13 | }; 14 | 15 | struct pp_atomctrl_voltage_table { 16 | int mask_low; 17 | int phase_delay; 18 | int count; 19 | struct table_entry *entries; 20 | }; 21 | 22 | void kfree(void *p); 23 | void memcpy(void *src, void *dst, int size); 24 | void *kzalloc(int size, int gfp); 25 | 26 | int phm_trim_voltage_table(struct pp_atomctrl_voltage_table *vol_table) 27 | { 28 | uint32_t i, j; 29 | uint16_t vvalue; 30 | bool found = false; 31 | struct pp_atomctrl_voltage_table *table; 32 | 33 | // PP_ASSERT_WITH_CODE((NULL != vol_table), 34 | // "Voltage Table empty.", return -EINVAL); 35 | 36 | table = kzalloc(sizeof(struct pp_atomctrl_voltage_table), GFP_KERNEL); 37 | 38 | if (NULL == table) 39 | return -EINVAL; 40 | 41 | table->mask_low = vol_table->mask_low; 42 | table->phase_delay = vol_table->phase_delay; 43 | 44 | for (i = 0; i < vol_table->count; i++) { 45 | vvalue = vol_table->entries[i].value; 46 | found = false; 47 | 48 | for (j = 0; j < table->count; j++) { 49 | if (vvalue == table->entries[j].value) { 50 | found = true; 51 | break; 52 | } 53 | } 54 | 55 | if (!found) { 56 | table->entries[table->count].value = vvalue; 57 | table->entries[table->count].smio_low = 58 | vol_table->entries[i].smio_low; 59 | table->count++; 60 | } 61 | } 62 | 63 | memcpy(vol_table, table, sizeof(struct pp_atomctrl_voltage_table)); 64 | kfree(table); 65 | 66 | return 0; 67 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/kzalloc_3.c: -------------------------------------------------------------------------------- 1 | #define unlikely(cond) (cond) 2 | #define ext4_lblk_t int 3 | #define ext4_fsblk_t int 4 | #define NULL 0 5 | #define EFSCORRUPTED 10000 6 | #define ENOMEM 1000 7 | #define GFP_NOFS 100 8 | 9 | struct ext4_extent_header { 10 | short int eh_magic; /* probably will support different formats */ 11 | short int eh_entries; /* number of valid entries */ 12 | short int eh_max; /* capacity of store in entries */ 13 | short int eh_depth; /* has tree real underlying blocks? */ 14 | int eh_generation; /* generation of the tree */ 15 | }; 16 | 17 | struct buffer_head { 18 | 19 | }; 20 | 21 | struct ext4_extent { 22 | int ee_block; /* first logical block extent covers */ 23 | int ee_len; /* number of blocks covered by extent */ 24 | int ee_start_hi; /* high 16 bits of physical block */ 25 | int ee_start_lo; /* low 32 bits of physical block */ 26 | }; 27 | 28 | struct ext4_extent_idx { 29 | int ei_block; /* index covers logical blocks from 'block' */ 30 | int ei_leaf_lo; /* pointer to the physical block of the next * 31 | * level. leaf or next index could be there */ 32 | short int ei_leaf_hi; /* high 16 bits of physical block */ 33 | short int ei_unused; 34 | }; 35 | 36 | struct ext4_ext_path { 37 | ext4_fsblk_t p_block; 38 | short int p_depth; 39 | short int p_maxdepth; 40 | struct ext4_extent *p_ext; 41 | struct ext4_extent_idx *p_idx; 42 | struct ext4_extent_header *p_hdr; 43 | struct buffer_head *p_bh; 44 | }; 45 | 46 | struct inode {}; 47 | 48 | struct ext4_extent_header *ext_inode_hdr(struct inode *inode); 49 | 50 | short int ext_depth(struct inode *inode); 51 | 52 | void *kzalloc(int size, int gfp); 53 | 54 | void kfree(void *); 55 | 56 | struct ext4_ext_path * 57 | ext4_find_extent(struct inode *inode, ext4_lblk_t block, 58 | struct ext4_ext_path **orig_path, int flags) 59 | { 60 | struct ext4_extent_header *eh; 61 | struct buffer_head *bh; 62 | struct ext4_ext_path *path = orig_path ? *orig_path : NULL; 63 | short int depth, i, ppos = 0; 64 | int ret; 65 | 66 | eh = ext_inode_hdr(inode); 67 | depth = ext_depth(inode); 68 | 69 | if (path) { 70 | ext4_ext_drop_refs(path); 71 | if (depth > path[0].p_maxdepth) { 72 | kfree(path); 73 | *orig_path = path = NULL; 74 | } 75 | } 76 | if (!path) { 77 | /* account possible depth increase */ 78 | path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2), 79 | GFP_NOFS); 80 | if (unlikely(!path)) 81 | return ERR_PTR(-ENOMEM); 82 | path[0].p_maxdepth = depth + 1; 83 | } 84 | path[0].p_hdr = eh; 85 | path[0].p_bh = NULL; 86 | 87 | i = depth; 88 | /* walk through the tree */ 89 | while (i) { 90 | ext_debug("depth %d: num %d, max %d\n", 91 | ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); 92 | 93 | ext4_ext_binsearch_idx(inode, path + ppos, block); 94 | path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx); 95 | path[ppos].p_depth = i; 96 | path[ppos].p_ext = NULL; 97 | 98 | bh = read_extent_tree_block(inode, path[ppos].p_block, --i, 99 | flags); 100 | if (IS_ERR(bh)) { 101 | ret = PTR_ERR(bh); 102 | goto err; 103 | } 104 | 105 | eh = ext_block_hdr(bh); 106 | ppos++; 107 | if (unlikely(ppos > depth)) { 108 | put_bh(bh); 109 | EXT4_ERROR_INODE(inode, 110 | "ppos %d > depth %d", ppos, depth); 111 | ret = -EFSCORRUPTED; 112 | goto err; 113 | } 114 | path[ppos].p_bh = bh; 115 | path[ppos].p_hdr = eh; 116 | } 117 | 118 | path[ppos].p_depth = i; 119 | path[ppos].p_ext = NULL; 120 | path[ppos].p_idx = NULL; 121 | 122 | /* find extent */ 123 | ext4_ext_binsearch(inode, path + ppos, block); 124 | /* if not an empty leaf */ 125 | if (path[ppos].p_ext) 126 | path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext); 127 | 128 | ext4_ext_show_path(inode, path); 129 | 130 | return path; 131 | 132 | err: 133 | ext4_ext_drop_refs(path); 134 | kfree(path); 135 | if (orig_path) 136 | *orig_path = NULL; 137 | return ERR_PTR(ret); 138 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/malloc_check_against_var.c: -------------------------------------------------------------------------------- 1 | struct obj { 2 | struct obj *child; 3 | int length; 4 | }; 5 | 6 | void *malloc(int size); 7 | 8 | void caller(struct obj *o) { 9 | struct obj *ptr = malloc(10); 10 | if (ptr >= o->child) { 11 | return; 12 | } 13 | ptr->length = 10; 14 | return; 15 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/malloc_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int *y() { 4 | return (int *) malloc(10); 5 | } 6 | 7 | int x1() { 8 | int *data = y(); 9 | data[0] = 10; 10 | } 11 | 12 | int x2() { 13 | int *data = y(); 14 | if (data != 0) { 15 | data[0] = 10; 16 | } 17 | } 18 | 19 | int main() { 20 | x1(); 21 | x2(); 22 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/malloc_wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int *malloc_wrapper() { 4 | return (int *) malloc(8); 5 | } 6 | 7 | void f() { 8 | int *ptr = malloc_wrapper(); 9 | if (ptr != 0) { 10 | ptr[5] = 10; 11 | } 12 | } 13 | 14 | int main() { 15 | f(); 16 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/malloc_wrapper_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int *malloc_wrapper() { 4 | return (int *) malloc(8); 5 | } 6 | 7 | int main() { 8 | int i = 0; 9 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/multi_result.c: -------------------------------------------------------------------------------- 1 | struct Object { int i; }; 2 | 3 | void *malloc(unsigned long size); 4 | 5 | int main() { 6 | struct Object *obj1 = malloc(sizeof(struct Object)); 7 | struct Object *obj2 = malloc(sizeof(struct Object)); 8 | if (!obj1 || !obj2) { 9 | return -1; 10 | } 11 | obj1->i = 10; 12 | obj2->i = 20; 13 | return 0; 14 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/sem_malloc.c: -------------------------------------------------------------------------------- 1 | char *new() { 2 | return (char *) malloc(sizeof(char) * 10); 3 | } 4 | 5 | int main() { 6 | char *p1 = new(); 7 | char *p2 = new(); 8 | if (p1 != 0) { 9 | p1[0] = 10; 10 | } 11 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/sem_malloc_2.c: -------------------------------------------------------------------------------- 1 | int main() { 2 | char *p1 = (char *) malloc(sizeof(char) * 10); 3 | char *p2 = (char *) malloc(sizeof(char) * 10); 4 | 5 | // p1 is checked 6 | if (p1 != 0) { 7 | p1[0] = 10; 8 | } 9 | 10 | // p2 is not 11 | p2[0] = 10; 12 | } -------------------------------------------------------------------------------- /tests/c_files/malloc/struct_1.c: -------------------------------------------------------------------------------- 1 | struct s { 2 | int *a; 3 | int *b; 4 | }; 5 | 6 | void *malloc(int size); 7 | 8 | void f() { 9 | struct s a; 10 | a.a = malloc(10); 11 | if (a.b) { 12 | a.b[10] = 10; 13 | } 14 | } 15 | 16 | void g() { 17 | struct s a; 18 | a.a = malloc(10); 19 | if (a.a) { 20 | a.a[10] = 10; 21 | } 22 | } 23 | 24 | int main() { 25 | f(); 26 | } -------------------------------------------------------------------------------- /tests/c_files/nested_loop/nested_loop_1.c: -------------------------------------------------------------------------------- 1 | void mutex_lock(int *lock); 2 | void mutex_unlock(int *unlock); 3 | 4 | int main() { 5 | int sum = 0; 6 | int lock = 0; 7 | mutex_lock(&lock); 8 | for (int i = 0; i < 10; i++) { 9 | for (int j = 0; j < 30; j++) { 10 | sum += i + j; 11 | } 12 | } 13 | mutex_unlock(&lock); 14 | } -------------------------------------------------------------------------------- /tests/c_files/path/path.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct lock { 4 | int i; 5 | }; 6 | 7 | static void mutex_lock(struct lock *l) { 8 | l->i = 1; 9 | } 10 | 11 | static void mutex_unlock(struct lock *l) { 12 | l->i = 0; 13 | } 14 | 15 | void run(int x, struct lock *l) { 16 | int *y = malloc(4); 17 | if (y != NULL) 18 | mutex_lock(l); 19 | if (y != NULL) 20 | mutex_unlock(l); 21 | } 22 | -------------------------------------------------------------------------------- /tests/c_files/path/path2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct lock { 4 | int i; 5 | }; 6 | 7 | static void mutex_lock(struct lock *l) { 8 | l->i = 1; 9 | } 10 | 11 | static void mutex_unlock(struct lock *l) { 12 | l->i = 0; 13 | } 14 | 15 | void run(int x, struct lock *l) { 16 | void *a = malloc(0); 17 | if (x != 0) 18 | mutex_lock(l); 19 | if (x != 0) 20 | mutex_unlock(l); 21 | } 22 | -------------------------------------------------------------------------------- /tests/c_files/path/path3.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct lock { 4 | int i; 5 | }; 6 | 7 | static void mutex_lock(struct lock *l) { 8 | l->i = 1; 9 | } 10 | 11 | static void mutex_unlock(struct lock *l) { 12 | l->i = 0; 13 | } 14 | 15 | void run(int x, struct lock *l) { 16 | void *a = malloc(0); 17 | x = x + 5; 18 | if (x != 0) 19 | mutex_lock(l); 20 | if (x != 0) 21 | mutex_unlock(l); 22 | } 23 | -------------------------------------------------------------------------------- /tests/c_files/path/path4.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct lock { 4 | int i; 5 | }; 6 | 7 | struct foo { 8 | int x; 9 | }; 10 | 11 | static void mutex_lock(struct lock *l) { 12 | l->i = 1; 13 | } 14 | 15 | static void mutex_unlock(struct lock *l) { 16 | l->i = 0; 17 | } 18 | 19 | void run(struct lock *l) { 20 | struct foo *a = malloc(sizeof(struct foo)); 21 | if (a->x != 0) 22 | mutex_lock(l); 23 | if (a->x != 0) 24 | mutex_unlock(l); 25 | } 26 | -------------------------------------------------------------------------------- /tests/c_files/path/path5.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct lock { 4 | int i; 5 | }; 6 | 7 | void *a; 8 | 9 | static void mutex_lock(struct lock *l) { 10 | l->i = 1; 11 | } 12 | 13 | static void mutex_unlock(struct lock *l) { 14 | l->i = 0; 15 | } 16 | 17 | void run(int x, struct lock *l) { 18 | void *b = malloc(4); 19 | if (a != 0) 20 | mutex_lock(l); 21 | if (a != 0) 22 | mutex_unlock(l); 23 | } 24 | -------------------------------------------------------------------------------- /tests/c_files/slice_reduction/slice_reduction_1.c: -------------------------------------------------------------------------------- 1 | void kzalloc(); 2 | void kfree(); 3 | void krealloc(); 4 | 5 | void z() { 6 | z(); 7 | } 8 | 9 | void x() { 10 | z(); 11 | } 12 | 13 | void y() { 14 | z(); 15 | } 16 | 17 | void c() { 18 | krealloc(); 19 | } 20 | 21 | void d() { 22 | x(); 23 | kzalloc(); 24 | kfree(); 25 | } 26 | 27 | void b() { 28 | c(); 29 | d(); 30 | } 31 | 32 | void a() { 33 | b(); 34 | } -------------------------------------------------------------------------------- /tests/c_files/slice_reduction/slice_reduction_2.c: -------------------------------------------------------------------------------- 1 | struct Object { 2 | int i; 3 | char *str; 4 | }; 5 | 6 | struct AnotherObject {}; 7 | 8 | void f(struct Object *); 9 | 10 | void g(int, struct Object *); 11 | 12 | struct Object *h(int); 13 | 14 | void x(); 15 | 16 | struct AnotherObject *y(char bool); 17 | 18 | void z(int); 19 | 20 | int main() { 21 | struct Object obj; 22 | obj.i = 0; 23 | obj.str = "asdadf"; 24 | f(&obj); 25 | g(3, &obj); 26 | struct Object *obj2 = h(5); 27 | } -------------------------------------------------------------------------------- /tests/c_files/switch/switch_1.c: -------------------------------------------------------------------------------- 1 | void *malloc(int i) { 2 | int j = 0; 3 | j += 10; 4 | return j; 5 | } 6 | 7 | int main() { 8 | void *ptr; 9 | int i = 1; 10 | if (i) { 11 | ptr = malloc(10); 12 | if (ptr) { 13 | i = 10; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /tests/c_files/switch/switch_2.c: -------------------------------------------------------------------------------- 1 | void *malloc(int i) { 2 | int j = 0; 3 | j += 10; 4 | return j; 5 | } 6 | 7 | int main() { 8 | void *ptr, *ptr2; 9 | int i = 100; 10 | switch (i) { 11 | case 1: ptr = malloc(10); break; 12 | case 2: ptr = malloc(20); break; 13 | case 100: i = 30; break; 14 | default: i = 40; 15 | } 16 | ptr2 = malloc(i); 17 | return 10; 18 | } -------------------------------------------------------------------------------- /tests/c_files/switch/switch_3.c: -------------------------------------------------------------------------------- 1 | void *malloc(int i) { 2 | int j = 0; 3 | j += 10; 4 | return j; 5 | } 6 | 7 | int main() { 8 | void *ptr, *ptr2; 9 | int i = 100; 10 | switch (i) { 11 | case 1: ptr = malloc(10); break; 12 | case 2: ptr = malloc(20); break; 13 | case 100: i = 30; break; 14 | } 15 | ptr2 = malloc(i); 16 | return 10; 17 | } -------------------------------------------------------------------------------- /tests/c_files/switch/switch_4.c: -------------------------------------------------------------------------------- 1 | const int SOME_NUMBER = 2; 2 | 3 | void *malloc(int i) { 4 | int j = 0; 5 | j += 10; 6 | return j; 7 | } 8 | 9 | int main() { 10 | void *ptr, *ptr2; 11 | int i = 100; 12 | switch (i) { 13 | case 1: ptr = malloc(10); break; 14 | case SOME_NUMBER: ptr = malloc(20); break; 15 | case 100: i = 30; break; 16 | } 17 | ptr2 = malloc(i); 18 | return 10; 19 | } -------------------------------------------------------------------------------- /tests/c_files/switch/switch_dot_dot_dot.c: -------------------------------------------------------------------------------- 1 | #define PT_LOPROC 0x70000000 2 | #define PT_HIPROC 0x7fffffff 3 | 4 | void kfree(void *); 5 | 6 | int main() { 7 | int i = 34; 8 | i++; 9 | switch (i) { 10 | case PT_LOPROC ... PT_HIPROC: 11 | i += 10; 12 | break; 13 | default: 14 | return 1; 15 | } 16 | kfree(&i); 17 | } -------------------------------------------------------------------------------- /tests/c_files/ty_cast/ty_cast_1.c: -------------------------------------------------------------------------------- 1 | int sum(int a, int b) { 2 | return a + b; 3 | } 4 | 5 | int main() { 6 | int res = sum(10, 20); 7 | return res; 8 | } -------------------------------------------------------------------------------- /tests/c_files/unreach/unreach1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct lock { 4 | int i; 5 | }; 6 | 7 | static void mutex_lock(struct lock *l) { 8 | l->i = 1; 9 | } 10 | 11 | static void mutex_unlock(struct lock *l) { 12 | l->i = 0; 13 | } 14 | 15 | int main(int argc, char **argv) { 16 | mutex_lock(NULL); 17 | if (argc < 2) { 18 | exit(1); 19 | } 20 | mutex_unlock(NULL); 21 | return argc; 22 | } 23 | -------------------------------------------------------------------------------- /tests/dbgmd.rs: -------------------------------------------------------------------------------- 1 | use llir; 2 | use llir::values::*; 3 | use std::path::Path; 4 | 5 | #[test] 6 | fn dbgmd_1() -> Result<(), String> { 7 | let path = Path::new("tests/c_files/nested_loop/nested_loop_1.bc"); 8 | let context = llir::Context::create(); 9 | let module = context.load_module(path)?; 10 | for func in module.iter_functions() { 11 | println!("Func {:?} - dbg mdnode: {:?}", func.name(), func.dbg_metadata()); 12 | for block in func.iter_blocks() { 13 | println!("Block - dbg mdnode: {:?}", block.dbg_metadata()); 14 | for instr in block.iter_instructions() { 15 | println!("{:?} - dbg mdnode: {:?}", instr, instr.dbg_metadata()); 16 | } 17 | } 18 | } 19 | Ok(()) 20 | } 21 | 22 | #[test] 23 | fn loop_mdnode_1() -> Result<(), String> { 24 | let path = Path::new("tests/c_files/nested_loop/nested_loop_1.bc"); 25 | let context = llir::Context::create(); 26 | let module = context.load_module(path)?; 27 | for func in module.iter_functions() { 28 | for block in func.iter_blocks() { 29 | for instr in block.iter_instructions() { 30 | match instr { 31 | Instruction::Branch(BranchInstruction::Unconditional(uc)) => { 32 | println!("{:?} - is loop: {:?}", uc, uc.is_loop_jump()); 33 | } 34 | _ => {} 35 | } 36 | } 37 | } 38 | } 39 | Ok(()) 40 | } 41 | -------------------------------------------------------------------------------- /tests/debug_loc.rs: -------------------------------------------------------------------------------- 1 | use llir; 2 | use llir::values::*; 3 | use std::path::Path; 4 | 5 | #[test] 6 | fn test_debug_loc() -> Result<(), String> { 7 | let path = Path::new("tests/c_files/free/free_struct.bc"); 8 | let context = llir::Context::create(); 9 | let module = context.load_module(path)?; 10 | for func in module.iter_functions() { 11 | println!("Func Loc: {}", func.debug_loc_string()); 12 | for block in func.iter_blocks() { 13 | for instr in block.iter_instructions() { 14 | println!("Instr Loc: {}", instr.debug_loc_string()); 15 | } 16 | } 17 | } 18 | Ok(()) 19 | } 20 | -------------------------------------------------------------------------------- /tests/fn_ptr.rs: -------------------------------------------------------------------------------- 1 | use llir; 2 | use std::path::Path; 3 | 4 | #[test] 5 | fn test_function_pointer_1() -> Result<(), String> { 6 | let path = Path::new("tests/c_files/fn_ptr/fn_ptr_1.bc"); 7 | let context = llir::Context::create(); 8 | let module = context.load_module(path)?; 9 | for func in module.iter_functions() { 10 | for block in func.iter_blocks() { 11 | for instr in block.iter_instructions() { 12 | use llir::values::Instruction; 13 | match instr { 14 | Instruction::Call(call) => { 15 | let f = call.callee_function(); 16 | match f { 17 | Some(f) => println!("{}", f.name()), 18 | None => println!("Calling function pointer"), 19 | } 20 | } 21 | _ => {} 22 | } 23 | } 24 | } 25 | } 26 | Ok(()) 27 | } 28 | -------------------------------------------------------------------------------- /tests/instr_structure.rs: -------------------------------------------------------------------------------- 1 | use llir; 2 | use std::path::Path; 3 | 4 | fn test_no_crash<'ctx>(module: &llir::Module<'ctx>) { 5 | for func in module.iter_functions() { 6 | for block in func.iter_blocks() { 7 | for instr in block.iter_instructions() { 8 | use llir::values::Instruction::*; 9 | use llir::values::*; 10 | match instr { 11 | Binary(bin) => { 12 | let _ = bin.opcode(); 13 | let _ = bin.op0(); 14 | let _ = bin.op1(); 15 | } 16 | Unary(una) => { 17 | let _ = una.opcode(); 18 | let _ = una.op0(); 19 | } 20 | Call(call) => { 21 | let _ = call.callee_function(); 22 | let _ = call.callee(); 23 | let _ = call.num_arguments(); 24 | let _ = call.arguments(); 25 | let _ = call.is_tail_call(); 26 | } 27 | Branch(br) => match br { 28 | BranchInstruction::Conditional(cond_br) => { 29 | let _ = cond_br.condition(); 30 | let _ = cond_br.then_block(); 31 | let _ = cond_br.else_block(); 32 | } 33 | BranchInstruction::Unconditional(uncond_br) => { 34 | let _ = uncond_br.destination(); 35 | } 36 | }, 37 | Switch(switch) => { 38 | let _ = switch.condition(); 39 | let _ = switch.default_destination(); 40 | let _ = switch.num_cases(); 41 | let _ = switch.cases(); 42 | } 43 | _ => (), 44 | } 45 | } 46 | } 47 | } 48 | } 49 | 50 | #[test] 51 | fn test_instr_struct_free_struct() -> Result<(), String> { 52 | let path = Path::new("tests/c_files/free/free_struct.bc"); 53 | let context = llir::Context::create(); 54 | let module = context.load_module(path)?; 55 | test_no_crash(&module); 56 | Ok(()) 57 | } 58 | 59 | #[test] 60 | fn test_load_fn_ptr_1() -> Result<(), String> { 61 | let path = Path::new("tests/c_files/fn_ptr/fn_ptr_1.bc"); 62 | let context = llir::Context::create(); 63 | let module = context.load_module(path)?; 64 | test_no_crash(&module); 65 | Ok(()) 66 | } 67 | -------------------------------------------------------------------------------- /tests/intrinsic.rs: -------------------------------------------------------------------------------- 1 | use llir; 2 | use llir::values::*; 3 | use std::path::Path; 4 | 5 | #[test] 6 | fn test_intrinsic_call() -> Result<(), String> { 7 | let path = Path::new("tests/c_files/br/br_1.bc"); 8 | let context = llir::Context::create(); 9 | let module = context.load_module(path)?; 10 | for func in module.iter_functions() { 11 | for block in func.iter_blocks() { 12 | for instr in block.iter_instructions() { 13 | match instr { 14 | Instruction::Call(c) => { 15 | println!("Instr {} is intrinsic: {}", c.to_string(), c.is_intrinsic_call()); 16 | } 17 | _ => {} 18 | } 19 | } 20 | } 21 | } 22 | Ok(()) 23 | } 24 | -------------------------------------------------------------------------------- /tests/load_bc.rs: -------------------------------------------------------------------------------- 1 | use llir::values::*; 2 | use std::path::Path; 3 | 4 | #[test] 5 | fn test_load_free_struct() -> Result<(), String> { 6 | let path = Path::new("tests/c_files/free/free_struct.bc"); 7 | let context = llir::Context::create(); 8 | let module = context.load_module(path)?; 9 | for func in module.iter_functions() { 10 | println!("{}, {}", func.name(), func.is_declaration_only()); 11 | for block in func.iter_blocks() { 12 | for instr in block.iter_instructions() { 13 | println!("{:?}", instr); 14 | } 15 | } 16 | } 17 | Ok(()) 18 | } 19 | 20 | #[test] 21 | fn test_load_fn_ptr_1() -> Result<(), String> { 22 | let path = Path::new("tests/c_files/fn_ptr/fn_ptr_1.bc"); 23 | let context = llir::Context::create(); 24 | let module = context.load_module(path)?; 25 | for func in module.iter_functions() { 26 | println!("{}, {}", func.name(), func.is_declaration_only()); 27 | for block in func.iter_blocks() { 28 | for instr in block.iter_instructions() { 29 | println!("{:?}", instr.to_string()); 30 | } 31 | } 32 | } 33 | Ok(()) 34 | } 35 | 36 | 37 | #[test] 38 | fn test_load_fn_ptr_2() -> Result<(), String> { 39 | let path = Path::new("tests/c_files/fn_ptr/fn_ptr_1.bc"); 40 | let context = llir::Context::create(); 41 | let module = context.load_module(path)?; 42 | for func in module.iter_functions() { 43 | println!("{}, {}", func.name(), func.is_declaration_only()); 44 | for instr in func.iter_instructions() { 45 | println!("{:?}", instr.to_string()); 46 | } 47 | } 48 | Ok(()) 49 | } 50 | -------------------------------------------------------------------------------- /tests/module_getters.rs: -------------------------------------------------------------------------------- 1 | use std::path::{Path}; 2 | use llir::*; 3 | 4 | #[test] 5 | fn get_function_1() -> Result<(), String> { 6 | let ctx = Context::create(); 7 | let module = ctx.load_module(Path::new("tests/c_files/br/br_1.bc"))?; 8 | let _ = module.get_function("main").unwrap(); 9 | Ok(()) 10 | } 11 | 12 | #[test] 13 | fn get_global_1() -> Result<(), String> { 14 | let ctx = Context::create(); 15 | let module = ctx.load_module(Path::new("tests/c_files/lock/lock_with_global.bc"))?; 16 | let _ = module.get_global_variable("global_lock").unwrap(); 17 | Ok(()) 18 | } --------------------------------------------------------------------------------