├── .gitmodules ├── .gitignore ├── .github ├── dependabot.yml └── workflows │ └── rust.yml ├── Cargo.toml ├── LICENSE.md ├── examples └── readme.rs ├── src ├── error.rs ├── message.rs ├── binary.rs ├── metadata.rs ├── memory_buffer.rs ├── pass_manager.rs ├── attribute.rs ├── jit.rs ├── context.rs ├── codegen.rs ├── basic_block.rs ├── tests.rs ├── lib.rs ├── execution_engine.rs ├── target.rs ├── instr.rs ├── module.rs ├── value.rs ├── type.rs ├── const.rs └── builder.rs └── README.md /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | build/target 3 | build/test 4 | Cargo.lock 5 | *.o 6 | wasm/target 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: cargo 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | time: "13:00" 8 | open-pull-requests-limit: 10 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "llama" 3 | version = "0.14.2" 4 | authors = ["Zach Shipko "] 5 | edition = "2018" 6 | readme = "README.md" 7 | repository = "https://github.com/zshipko/llama" 8 | documentation = "https://zshipko.github.io/llama/llama" 9 | description = "Friendly LLVM bindings" 10 | keywords = ["LLVM", "JIT", "compiler"] 11 | license = "ISC" 12 | 13 | [dependencies] 14 | thiserror = "1" 15 | lazy_static = "1" 16 | llvm-sys = {version = "140.0.2", features=["no-llvm-linking"]} 17 | 18 | [package.metadata.docs.rs] 19 | features = [ "docs-rs" ] 20 | 21 | [features] 22 | docs-rs = [] 23 | 24 | [workspace] 25 | members = [ 26 | "build", 27 | ] 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Zach Shipko 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /examples/readme.rs: -------------------------------------------------------------------------------- 1 | use llama::*; 2 | 3 | // Convenience type alias for the `sum` function. 4 | // 5 | // Calling this is innately `unsafe` because there's no guarantee it doesn't 6 | // do `unsafe` operations internally. 7 | type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64; 8 | 9 | fn compile_sum(jit: &mut Jit) -> Result { 10 | let i64 = Type::i64(jit.context())?; 11 | let sum_t = FuncType::new(i64, [i64, i64, i64])?; 12 | jit.declare_function("sum", sum_t, |build, f| { 13 | let params = f.params(); 14 | let x = params[0]; 15 | let y = params[1]; 16 | let z = params[2]; 17 | 18 | let sum = build.add(x, y, "sum")?; 19 | let sum = build.add(sum, z, "sum")?; 20 | build.ret(sum) 21 | })?; 22 | 23 | unsafe { jit.engine().function("sum") } 24 | } 25 | 26 | fn main() -> Result<(), Error> { 27 | let mut jit = Jit::new("sum", None)?; 28 | 29 | let sum = compile_sum(&mut jit)?; 30 | 31 | let x = 1u64; 32 | let y = 2u64; 33 | let z = 3u64; 34 | 35 | unsafe { 36 | println!("{} + {} + {} = {}", x, y, z, sum(x, y, z)); 37 | assert_eq!(sum(x, y, z), x + y + z); 38 | } 39 | 40 | Ok(()) 41 | } 42 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | /// An enumeration of all possible errors 2 | #[derive(Debug, thiserror::Error)] 3 | pub enum Error { 4 | /// NULL pointer encountered, this could be due to an invalid use of LLVM API or an actual 5 | /// error 6 | #[error("NULL pointer encountered")] 7 | NullPointer, 8 | 9 | /// UTF conversion failed 10 | #[error("String contains invalid Utf8 character: {0}")] 11 | Utf8Error(#[from] std::str::Utf8Error), 12 | 13 | /// LLVM message 14 | #[error("Message: {0}")] 15 | Message(crate::Message), 16 | 17 | /// IO error 18 | #[error("I/O: {0}")] 19 | IO(#[from] std::io::Error), 20 | 21 | /// Invalid path name 22 | #[error("Invalid path name")] 23 | InvalidPath, 24 | 25 | /// Invalid LLVM type was encountered 26 | #[error("Invalid type")] 27 | InvalidType, 28 | 29 | /// Invalid LLVM constant 30 | #[error("Value is not a constant")] 31 | InvalidConst, 32 | 33 | /// Invalid LLVM basic block 34 | #[error("Value is not a basic block")] 35 | InvalidBasicBlock, 36 | 37 | /// Invalid LLVM function 38 | #[error("Invalid function")] 39 | InvalidFunction, 40 | 41 | /// Module is already owned by another ExecutionEngine 42 | #[error("Module is already owned by another execution engine")] 43 | ModuleIsAlreadyOwned, 44 | 45 | /// Mutex guard poison error 46 | #[error("Poison error: {0}")] 47 | Poison(#[from] std::sync::PoisonError>), 48 | } 49 | -------------------------------------------------------------------------------- /src/message.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Wraps LLVM messages, these are strings that should be freed using LLVMDisposeMessage 4 | pub struct Message(pub(crate) *mut c_char); 5 | impl Message { 6 | pub(crate) fn from_raw(c: *mut c_char) -> Message { 7 | Message(c) 8 | } 9 | 10 | /// Message length 11 | pub fn len(&self) -> usize { 12 | if self.0.is_null() { 13 | return 0; 14 | } 15 | 16 | unsafe { strlen(self.0) } 17 | } 18 | 19 | /// Returns true when the message is empty 20 | pub fn is_empty(&self) -> bool { 21 | self.len() == 0 22 | } 23 | } 24 | 25 | impl AsRef for Message { 26 | fn as_ref(&self) -> &str { 27 | if self.0.is_null() { 28 | return ""; 29 | } 30 | 31 | unsafe { 32 | let st = std::slice::from_raw_parts(self.0 as *const u8, self.len()); 33 | std::str::from_utf8_unchecked(st) 34 | } 35 | } 36 | } 37 | 38 | impl From for String { 39 | fn from(m: Message) -> String { 40 | m.as_ref().into() 41 | } 42 | } 43 | 44 | impl Drop for Message { 45 | fn drop(&mut self) { 46 | if !self.0.is_null() { 47 | unsafe { llvm::core::LLVMDisposeMessage(self.0) } 48 | } 49 | } 50 | } 51 | 52 | impl std::fmt::Display for Message { 53 | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { 54 | write!(fmt, "{}", self.as_ref()) 55 | } 56 | } 57 | 58 | impl std::fmt::Debug for Message { 59 | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { 60 | write!(fmt, "{}", self) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/binary.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Binary is used to store compiled binary objects 4 | pub struct Binary(NonNull); 5 | 6 | llvm_inner_impl!(Binary, llvm::object::LLVMOpaqueBinary); 7 | 8 | impl<'a> Drop for Binary { 9 | fn drop(&mut self) { 10 | unsafe { llvm::object::LLVMDisposeBinary(self.llvm()) } 11 | } 12 | } 13 | 14 | impl<'a> Binary { 15 | /// Create a new binary object 16 | pub fn new(ctx: &Context, data: &MemoryBuffer) -> Result { 17 | let mut message = std::ptr::null_mut(); 18 | let bin = unsafe { llvm::object::LLVMCreateBinary(data.llvm(), ctx.llvm(), &mut message) }; 19 | 20 | let message = Message::from_raw(message); 21 | 22 | match wrap_inner(bin) { 23 | Ok(bin) => Ok(Binary(bin)), 24 | Err(_) => Err(Error::Message(message)), 25 | } 26 | } 27 | 28 | /// Get binary file type 29 | pub fn get_type(&self) -> BinaryType { 30 | unsafe { llvm::object::LLVMBinaryGetType(self.llvm()) } 31 | } 32 | 33 | /// Write binary object to file 34 | pub fn write_to_file(&self, path: impl AsRef) -> Result<(), Error> { 35 | let buffer = unsafe { llvm::object::LLVMBinaryCopyMemoryBuffer(self.llvm()) }; 36 | let buf = MemoryBuffer::from_raw(buffer)?; 37 | buf.write_to_file(path) 38 | } 39 | } 40 | 41 | impl<'a> AsRef<[u8]> for Binary { 42 | fn as_ref(&self) -> &[u8] { 43 | let buffer = unsafe { llvm::object::LLVMBinaryCopyMemoryBuffer(self.llvm()) }; 44 | let buf = MemoryBuffer::from_raw(buffer).unwrap(); 45 | let ptr = buf.as_ref().as_ptr(); 46 | let len = buf.len(); 47 | unsafe { std::slice::from_raw_parts(ptr, len) } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # llama 2 | 3 | A friendly LLVM library for Rust. 4 | 5 | Goals: 6 | - Support the latest `llvm-sys` release (as of LLVM 14 and llama 0.14.0 the version numbers match) 7 | - Provide an improved interface, while still remaining as close as possible to the LLVM C API. 8 | 9 | Due to the size of the LLVM API there is bound to be missing, broken or incomplete functionality in `llama`, please create an issue if something you need isn't implemented. 10 | 11 | **NOTE**: `llama` will let you generate invalid IR, take a look at [inkwell](https://github.com/TheDan64/inkwell) for LLVM bindings with a focus on type-safety 12 | 13 | ## Documentation 14 | 15 | - [llama](https://zshipko.github.io/llama/llama) 16 | - [llama-build](https://zshipko.github.io/llama/llama_build) 17 | 18 | ## Examples 19 | 20 | Inkwell's example using `llama`: 21 | 22 | ```rust 23 | use llama::*; 24 | 25 | // Convenience type alias for the `sum` function. 26 | // 27 | // Calling this is innately `unsafe` because there's no guarantee it doesn't 28 | // do `unsafe` operations internally. 29 | type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64; 30 | 31 | fn compile_sum(jit: &mut Jit) -> Result { 32 | let i64 = Type::i64(jit.context())?; 33 | let sum_t = FuncType::new(i64, [i64, i64, i64])?; 34 | jit.declare_function("sum", sum_t, |build, f| { 35 | let params = f.params(); 36 | let x = params[0]; 37 | let y = params[1]; 38 | let z = params[2]; 39 | 40 | let sum = build.add(x, y, "sum")?; 41 | let sum = build.add(sum, z, "sum")?; 42 | build.ret(sum) 43 | })?; 44 | 45 | unsafe { jit.engine().function("sum") } 46 | } 47 | 48 | fn main() -> Result<(), Error> { 49 | let mut jit = Jit::new("sum", None)?; 50 | 51 | let sum = compile_sum(&mut jit)?; 52 | 53 | let x = 1u64; 54 | let y = 2u64; 55 | let z = 3u64; 56 | 57 | unsafe { 58 | println!("{} + {} + {} = {}", x, y, z, sum(x, y, z)); 59 | assert_eq!(sum(x, y, z), x + y + z); 60 | } 61 | 62 | Ok(()) 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /src/metadata.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Metadata values 4 | #[derive(Clone, Copy)] 5 | pub struct Metadata<'a>(pub(crate) Value<'a>); 6 | 7 | impl<'a> AsRef> for Metadata<'a> { 8 | fn as_ref(&self) -> &Value<'a> { 9 | &self.0 10 | } 11 | } 12 | 13 | impl<'a> From> for Value<'a> { 14 | fn from(x: Metadata<'a>) -> Value<'a> { 15 | x.0 16 | } 17 | } 18 | 19 | impl<'a> Metadata<'a> { 20 | /// Create a string attribute 21 | pub fn new_string(ctx: &Context<'a>, k: impl AsRef) -> Result, Error> { 22 | let k = k.as_ref(); 23 | unsafe { 24 | Ok(Metadata(Value::from_inner( 25 | llvm::core::LLVMMetadataAsValue( 26 | ctx.llvm(), 27 | llvm::core::LLVMMDStringInContext2( 28 | ctx.llvm(), 29 | k.as_ptr() as *const c_char, 30 | k.len(), 31 | ), 32 | ), 33 | )?)) 34 | } 35 | } 36 | 37 | /// Create an enum attribute 38 | pub fn new_node( 39 | ctx: &Context<'a>, 40 | mds: impl AsRef<[Metadata<'a>]>, 41 | ) -> Result, Error> { 42 | let mut ptr: Vec<*mut llvm::LLVMOpaqueMetadata> = mds 43 | .as_ref() 44 | .iter() 45 | .map(|x| unsafe { llvm::core::LLVMValueAsMetadata(x.as_ref().llvm()) }) 46 | .collect(); 47 | unsafe { 48 | Ok(Metadata(Value::from_inner( 49 | llvm::core::LLVMMetadataAsValue( 50 | ctx.llvm(), 51 | llvm::core::LLVMMDNodeInContext2(ctx.llvm(), ptr.as_mut_ptr(), ptr.len()), 52 | ), 53 | )?)) 54 | } 55 | } 56 | 57 | /// Get string value 58 | pub fn as_str(self) -> Result<&'a str, Error> { 59 | unsafe { 60 | let mut len = 0; 61 | let ptr = llvm::core::LLVMGetMDString(self.as_ref().llvm(), &mut len); 62 | if ptr.is_null() { 63 | return Err(Error::NullPointer); 64 | } 65 | 66 | let slice = std::slice::from_raw_parts(ptr as *const u8, len as usize); 67 | let s = std::str::from_utf8(slice)?; 68 | Ok(s) 69 | } 70 | } 71 | 72 | /// Get node value 73 | pub fn node(self) -> Vec> { 74 | unsafe { 75 | let len = llvm::core::LLVMGetMDNodeNumOperands(self.as_ref().llvm()); 76 | let mut a = vec![std::ptr::null_mut(); len as usize]; 77 | llvm::core::LLVMGetMDNodeOperands(self.as_ref().llvm(), a.as_mut_ptr()); 78 | a.into_iter() 79 | .map(|x| Metadata(Value::from_inner(x).unwrap())) 80 | .collect() 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/memory_buffer.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Memory buffer wraps LLVMMemoryBufferRef 4 | pub struct MemoryBuffer(NonNull); 5 | 6 | llvm_inner_impl!(MemoryBuffer, llvm::LLVMMemoryBuffer); 7 | 8 | impl MemoryBuffer { 9 | pub(crate) fn from_raw(ptr: *mut llvm::LLVMMemoryBuffer) -> Result { 10 | Ok(MemoryBuffer(wrap_inner(ptr)?)) 11 | } 12 | 13 | /// Create new memory buffer from file 14 | pub fn from_file(path: impl AsRef) -> Result { 15 | let path = match path.as_ref().to_str() { 16 | Some(p) => cstr!(p), 17 | None => return Err(Error::InvalidPath), 18 | }; 19 | 20 | let mut mem = std::ptr::null_mut(); 21 | let mut message = std::ptr::null_mut(); 22 | 23 | let ok = unsafe { 24 | llvm::core::LLVMCreateMemoryBufferWithContentsOfFile( 25 | path.as_ptr(), 26 | &mut mem, 27 | &mut message, 28 | ) == 0 29 | }; 30 | 31 | let message = Message::from_raw(message); 32 | if !ok { 33 | return Err(Error::Message(message)); 34 | } 35 | 36 | Self::from_raw(mem) 37 | } 38 | 39 | /// Create new memory buffer from slice 40 | pub fn from_slice(name: impl AsRef, s: impl AsRef<[u8]>) -> Result { 41 | let name = cstr!(name.as_ref()); 42 | let s = s.as_ref(); 43 | let mem = unsafe { 44 | llvm::core::LLVMCreateMemoryBufferWithMemoryRangeCopy( 45 | s.as_ptr() as *const c_char, 46 | s.len(), 47 | name.as_ptr(), 48 | ) 49 | }; 50 | 51 | Self::from_raw(mem) 52 | } 53 | 54 | /// Number of bytes in buffer 55 | pub fn len(&self) -> usize { 56 | unsafe { llvm::core::LLVMGetBufferSize(self.0.as_ptr()) } 57 | } 58 | 59 | /// Returns true when the buffer is empty 60 | pub fn is_empty(&self) -> bool { 61 | self.len() == 0 62 | } 63 | 64 | /// Write buffer to the specified file 65 | pub fn write_to_file(&self, path: impl AsRef) -> Result<(), Error> { 66 | let mut f = std::fs::File::create(path)?; 67 | std::io::Write::write_all(&mut f, self.as_ref())?; 68 | Ok(()) 69 | } 70 | } 71 | 72 | impl AsRef<[u8]> for MemoryBuffer { 73 | fn as_ref(&self) -> &[u8] { 74 | let size = self.len(); 75 | unsafe { 76 | let data = llvm::core::LLVMGetBufferStart(self.0.as_ptr()); 77 | std::slice::from_raw_parts(data as *const u8, size) 78 | } 79 | } 80 | } 81 | 82 | impl Drop for MemoryBuffer { 83 | fn drop(&mut self) { 84 | unsafe { llvm::core::LLVMDisposeMemoryBuffer(self.0.as_ptr()) } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/pass_manager.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// PassManager for module optimizations 4 | pub struct ModulePassManager<'a>(NonNull, PhantomData<&'a ()>); 5 | 6 | /// PassManager for function optimizations 7 | pub struct FuncPassManager<'a>(NonNull, PhantomData<&'a ()>); 8 | 9 | /// PassManager trait is used to define common functionality between the two types of PassManagers 10 | pub trait PassManager: LLVM { 11 | /// Kind is used to designate the kind of value that can be optimized using this PassManager 12 | type Kind; 13 | 14 | /// Run configured optimization passes 15 | fn run(&self, f: &Self::Kind) -> bool; 16 | 17 | /// Add optimization passes 18 | /// 19 | /// # Safety 20 | /// This is marked as unsafe because `Transform` functions 21 | /// are unsafe 22 | unsafe fn add(&self, transforms: impl AsRef<[Transform]>) { 23 | for transform in transforms.as_ref().iter() { 24 | transform(self.llvm()) 25 | } 26 | } 27 | } 28 | 29 | llvm_inner_impl!(ModulePassManager<'a>, llvm::LLVMPassManager); 30 | llvm_inner_impl!(FuncPassManager<'a>, llvm::LLVMPassManager); 31 | 32 | /// An optimization pass 33 | pub type Transform = unsafe extern "C" fn(_: *mut llvm::LLVMPassManager); 34 | 35 | pub use llvm::transforms; 36 | 37 | impl<'a> Drop for ModulePassManager<'a> { 38 | fn drop(&mut self) { 39 | unsafe { llvm::core::LLVMDisposePassManager(self.llvm()) } 40 | } 41 | } 42 | 43 | impl<'a> Drop for FuncPassManager<'a> { 44 | fn drop(&mut self) { 45 | unsafe { llvm::core::LLVMDisposePassManager(self.llvm()) } 46 | } 47 | } 48 | 49 | impl<'a> FuncPassManager<'a> { 50 | /// Create new function pass manager 51 | pub fn new(module: &Module<'a>) -> Result, Error> { 52 | let ptr = unsafe { llvm::core::LLVMCreateFunctionPassManagerForModule(module.llvm()) }; 53 | 54 | Ok(FuncPassManager(wrap_inner(ptr)?, PhantomData)) 55 | } 56 | } 57 | 58 | impl<'a> ModulePassManager<'a> { 59 | /// Create new module pass manager 60 | pub fn new(module: &Module<'a>) -> Result, Error> { 61 | let ptr = unsafe { llvm::core::LLVMCreateFunctionPassManagerForModule(module.llvm()) }; 62 | 63 | Ok(ModulePassManager(wrap_inner(ptr)?, PhantomData)) 64 | } 65 | } 66 | 67 | impl<'a> PassManager for FuncPassManager<'a> { 68 | type Kind = Func<'a>; 69 | 70 | fn run(&self, f: &Func<'a>) -> bool { 71 | unsafe { llvm::core::LLVMRunFunctionPassManager(self.llvm(), f.as_ref().llvm()) == 1 } 72 | } 73 | } 74 | 75 | impl<'a> PassManager for ModulePassManager<'a> { 76 | type Kind = Module<'a>; 77 | 78 | fn run(&self, module: &Module<'a>) -> bool { 79 | unsafe { llvm::core::LLVMRunPassManager(self.llvm(), module.llvm()) == 1 } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/attribute.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// LLVM Attribute 4 | pub struct Attribute<'a>(NonNull, PhantomData<&'a ()>); 5 | 6 | llvm_inner_impl!(Attribute<'a>, llvm::LLVMOpaqueAttributeRef); 7 | 8 | impl<'a> Attribute<'a> { 9 | pub(crate) fn from_inner(x: *mut llvm::LLVMOpaqueAttributeRef) -> Result, Error> { 10 | Ok(Attribute(wrap_inner(x)?, PhantomData)) 11 | } 12 | 13 | /// Create a string attribute 14 | pub fn new_string( 15 | ctx: &Context<'a>, 16 | k: impl AsRef, 17 | v: impl AsRef, 18 | ) -> Result, Error> { 19 | let k = k.as_ref(); 20 | let v = v.as_ref(); 21 | unsafe { 22 | Attribute::from_inner(llvm::core::LLVMCreateStringAttribute( 23 | ctx.llvm(), 24 | k.as_ptr() as *const c_char, 25 | k.len() as c_uint, 26 | v.as_ptr() as *const c_char, 27 | v.len() as c_uint, 28 | )) 29 | } 30 | } 31 | 32 | /// Create an enum attribute 33 | pub fn new_enum(ctx: &Context<'a>, k: u32, v: u64) -> Result, Error> { 34 | unsafe { Attribute::from_inner(llvm::core::LLVMCreateEnumAttribute(ctx.llvm(), k, v)) } 35 | } 36 | 37 | /// Returns true when the attribute is an enum 38 | pub fn is_enum(&self) -> bool { 39 | unsafe { llvm::core::LLVMIsEnumAttribute(self.llvm()) == 1 } 40 | } 41 | 42 | /// Returns true when the attribute is a string 43 | pub fn is_string(&self) -> bool { 44 | unsafe { llvm::core::LLVMIsStringAttribute(self.llvm()) == 1 } 45 | } 46 | 47 | /// Get string attribute kind 48 | pub fn string_kind(&self) -> Option<&str> { 49 | if !self.is_string() { 50 | return None; 51 | } 52 | 53 | let mut len = 0; 54 | let ptr = unsafe { llvm::core::LLVMGetStringAttributeKind(self.llvm(), &mut len) }; 55 | let slice = unsafe { std::slice::from_raw_parts(ptr as *const u8, len as usize) }; 56 | match std::str::from_utf8(slice) { 57 | Ok(x) => Some(x), 58 | Err(_) => None, 59 | } 60 | } 61 | 62 | /// Get string attribute value 63 | pub fn string_value(&self) -> Option<&str> { 64 | if !self.is_string() { 65 | return None; 66 | } 67 | 68 | let mut len = 0; 69 | let ptr = unsafe { llvm::core::LLVMGetStringAttributeValue(self.llvm(), &mut len) }; 70 | let slice = unsafe { std::slice::from_raw_parts(ptr as *const u8, len as usize) }; 71 | match std::str::from_utf8(slice) { 72 | Ok(x) => Some(x), 73 | Err(_) => None, 74 | } 75 | } 76 | 77 | /// Get enum attribute kind 78 | pub fn enum_kind(&self) -> Option { 79 | if !self.is_enum() { 80 | return None; 81 | } 82 | unsafe { Some(llvm::core::LLVMGetEnumAttributeKind(self.llvm()) as i32) } 83 | } 84 | 85 | /// Get enum attribute value 86 | pub fn enum_value(&self) -> Option { 87 | if !self.is_enum() { 88 | return None; 89 | } 90 | unsafe { Some(llvm::core::LLVMGetEnumAttributeValue(self.llvm())) } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/jit.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Jit bundles LLVMContext, LLVMBuilder and LLVMExecutionEngine 4 | pub struct Jit<'ctx> { 5 | engine: ExecutionEngine<'ctx>, 6 | build: Builder<'ctx>, 7 | context: Context<'ctx>, 8 | } 9 | 10 | impl<'ctx> Jit<'ctx> { 11 | /// Create new Jit instance 12 | pub fn new(name: impl AsRef, opt: Option) -> Result, Error> { 13 | let context = Context::new()?; 14 | let module = Module::new(&context, name)?; 15 | let build = Builder::new(&context)?; 16 | let engine = ExecutionEngine::new_jit(module, opt.unwrap_or_default())?; 17 | Ok(Jit { 18 | context, 19 | build, 20 | engine, 21 | }) 22 | } 23 | 24 | /// Destruct 25 | pub fn into_inner(self) -> (Context<'ctx>, Builder<'ctx>, ExecutionEngine<'ctx>) { 26 | (self.context, self.build, self.engine) 27 | } 28 | 29 | /// Access ExecutionEngine 30 | pub fn engine(&self) -> &ExecutionEngine<'ctx> { 31 | &self.engine 32 | } 33 | 34 | /// Mutable access to ExecutionEngine 35 | pub fn engine_mut(&mut self) -> &mut ExecutionEngine<'ctx> { 36 | &mut self.engine 37 | } 38 | 39 | /// Access Builder 40 | pub fn build(&self) -> &Builder<'ctx> { 41 | &self.build 42 | } 43 | 44 | /// Mutable access to Builder 45 | pub fn build_mut(&mut self) -> &mut Builder<'ctx> { 46 | &mut self.build 47 | } 48 | 49 | /// Access Context 50 | pub fn context(&self) -> &Context<'ctx> { 51 | &self.context 52 | } 53 | 54 | /// Mutable access to Context 55 | pub fn context_mut(&mut self) -> &mut Context<'ctx> { 56 | &mut self.context 57 | } 58 | 59 | /// Access Module 60 | pub fn module(&self) -> &Module<'ctx> { 61 | self.engine.module() 62 | } 63 | 64 | /// Mutable access to Module 65 | pub fn module_mut(&mut self) -> &mut Module<'ctx> { 66 | self.engine.module_mut() 67 | } 68 | 69 | /// Declare a new function with function body 70 | pub fn declare_function< 71 | T: Into>, 72 | F: FnOnce(&Builder<'ctx>, Func<'ctx>) -> Result, 73 | >( 74 | &self, 75 | name: impl AsRef, 76 | ft: FuncType, 77 | def: F, 78 | ) -> Result, Error> { 79 | self.module() 80 | .declare_function(&self.build, name, ft, |x| def(&self.build, x)) 81 | } 82 | 83 | /// Define a new function without declaring a function body 84 | pub fn define_function(&self, name: impl AsRef, t: FuncType) -> Result, Error> { 85 | self.module().define_function(name, t) 86 | } 87 | 88 | /// Create a new global with an empty initializer 89 | pub fn define_global( 90 | &self, 91 | name: impl AsRef, 92 | ty: impl AsRef>, 93 | ) -> Result, Error> { 94 | self.module().define_global(name, ty) 95 | } 96 | 97 | /// Create a new global with the specified initializer 98 | pub fn declare_global( 99 | &self, 100 | name: impl AsRef, 101 | t: impl AsRef>, 102 | ) -> Result, Error> { 103 | self.module().declare_global(name, t) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | LLVM_VERSION: 14 11 | 12 | jobs: 13 | linux: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | 18 | - name: Install deps 19 | run: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh $LLVM_VERSION && sudo ln -sf /usr/bin/llvm-config-$LLVM_VERSION /usr/bin/llvm-config 20 | 21 | - name: Run tests 22 | run: cargo test --verbose 23 | macos: 24 | runs-on: macos-latest 25 | steps: 26 | - uses: actions/checkout@v2 27 | 28 | - name: Install deps 29 | run: brew update && brew install llvm@$LLVM_VERSION && brew upgrade llvm && ln -sf /usr/local/opt/llvm/bin/llvm-config /usr/local/bin/llvm-config 30 | 31 | - name: Run tests 32 | run: cargo test --verbose 33 | all_linux_nightly: 34 | runs-on: ubuntu-latest 35 | steps: 36 | - uses: actions/checkout@v2 37 | 38 | - name: Install deps 39 | run: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh $LLVM_VERSION && sudo ln -sf /usr/bin/llvm-config-$LLVM_VERSION /usr/bin/llvm-config 40 | 41 | - name: Nightly 42 | run: rustup toolchain install nightly 43 | 44 | - name: Run tests 45 | run: cargo +nightly test --verbose --all 46 | all_macos_nightly: 47 | runs-on: macos-latest 48 | steps: 49 | - uses: actions/checkout@v2 50 | 51 | - name: Install deps 52 | run: brew update && brew install llvm@$LLVM_VERSION && brew upgrade llvm && ln -sf /usr/local/opt/llvm/bin/llvm-config /usr/local/bin/llvm-config 53 | 54 | - name: Nightly 55 | run: rustup toolchain install nightly 56 | 57 | - name: Run tests 58 | run: cargo +nightly test --verbose --all 59 | clippy: 60 | runs-on: ubuntu-latest 61 | steps: 62 | - uses: actions/checkout@v2 63 | 64 | - name: Install deps 65 | run: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh $LLVM_VERSION && sudo ln -sf /usr/bin/llvm-config-$LLVM_VERSION /usr/bin/llvm-config 66 | 67 | - name: Nightly 68 | run: rustup toolchain install nightly --profile=default 69 | 70 | - name: Run tests 71 | run: cargo +nightly clippy --all 72 | doc: 73 | runs-on: ubuntu-latest 74 | env: 75 | RUSTFLAGS: -D warnings 76 | CARGO_INCREMENTAL: 0 77 | 78 | steps: 79 | - name: Checkout repository 80 | uses: actions/checkout@v2 81 | 82 | - name: Install dependencies 83 | run: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh $LLVM_VERSION && sudo ln -sf /usr/bin/llvm-config-$LLVM_VERSION /usr/bin/llvm-config 84 | 85 | - name: Install Rust toolchain 86 | uses: actions-rs/toolchain@v1 87 | with: 88 | toolchain: nightly 89 | profile: minimal 90 | override: true 91 | components: rustfmt, rust-src 92 | 93 | - name: Build Documentation 94 | run: cargo doc --all 95 | 96 | - name: Deploy Docs 97 | uses: peaceiris/actions-gh-pages@v3 98 | with: 99 | github_token: ${{ secrets.GITHUB_TOKEN }} 100 | publish_branch: gh-pages 101 | publish_dir: ./target/doc 102 | force_orphan: true 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/context.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Context wraps LLVMContext 4 | pub struct Context<'a>( 5 | pub(crate) NonNull, 6 | pub(crate) bool, 7 | pub(crate) PhantomData<&'a ()>, 8 | ); 9 | 10 | llvm_inner_impl!(Context<'a>, llvm::LLVMContext); 11 | 12 | impl<'a> Drop for Context<'a> { 13 | fn drop(&mut self) { 14 | if !self.1 { 15 | return; 16 | } 17 | 18 | unsafe { llvm::core::LLVMContextDispose(self.llvm()) } 19 | } 20 | } 21 | 22 | static INIT: std::sync::Once = std::sync::Once::new(); 23 | 24 | impl<'a> Clone for Context<'a> { 25 | fn clone(&self) -> Context<'a> { 26 | Context(self.0, false, PhantomData) 27 | } 28 | } 29 | 30 | impl<'a> Context<'a> { 31 | fn init() { 32 | INIT.call_once(|| unsafe { 33 | llvm::target::LLVM_InitializeAllTargetInfos(); 34 | llvm::target::LLVM_InitializeAllTargetMCs(); 35 | llvm::target::LLVM_InitializeAllDisassemblers(); 36 | llvm::target::LLVM_InitializeAllTargets(); 37 | llvm::target::LLVM_InitializeAllAsmParsers(); 38 | llvm::target::LLVM_InitializeAllAsmPrinters(); 39 | }); 40 | } 41 | 42 | /// Create a new context 43 | pub fn new() -> Result { 44 | Self::init(); 45 | let ctx = unsafe { wrap_inner(llvm::core::LLVMContextCreate())? }; 46 | Ok(Context(ctx, true, PhantomData)) 47 | } 48 | 49 | /// Return the global context 50 | pub fn global() -> Result { 51 | Self::init(); 52 | let ctx = unsafe { wrap_inner(llvm::core::LLVMGetGlobalContext())? }; 53 | Ok(Context(ctx, false, PhantomData)) 54 | } 55 | 56 | /// Allow context to discard value names, this can be used to save on runtime allocations 57 | pub fn set_discard_value_names(&mut self, discard: bool) { 58 | unsafe { 59 | llvm::core::LLVMContextSetDiscardValueNames(self.llvm(), if discard { 1 } else { 0 }) 60 | } 61 | } 62 | 63 | /// Returns true when the context is set to discard value names 64 | pub fn discard_value_names(&mut self) -> bool { 65 | unsafe { llvm::core::LLVMContextShouldDiscardValueNames(self.llvm()) == 1 } 66 | } 67 | 68 | /// Insert a new basic block 69 | pub fn insert_basic_block( 70 | &self, 71 | bb: BasicBlock<'a>, 72 | name: impl AsRef, 73 | ) -> Result, Error> { 74 | let name = cstr!(name.as_ref()); 75 | let bb = unsafe { 76 | llvm::core::LLVMInsertBasicBlockInContext(self.llvm(), bb.llvm(), name.as_ptr()) 77 | }; 78 | BasicBlock::from_inner(bb) 79 | } 80 | 81 | /// Get metadata kind ID 82 | pub fn md_kind_id(&self, name: impl AsRef) -> u32 { 83 | let len = name.as_ref().len(); 84 | let name = cstr!(name.as_ref()); 85 | unsafe { llvm::core::LLVMGetMDKindIDInContext(self.llvm(), name.as_ptr(), len as u32) } 86 | } 87 | 88 | /// Get enum attribute kind ID 89 | pub fn enum_attribute_kind_for_name(&self, name: impl AsRef) -> u32 { 90 | let len = name.as_ref().len(); 91 | let name = cstr!(name.as_ref()); 92 | unsafe { llvm::core::LLVMGetEnumAttributeKindForName(name.as_ptr(), len) } 93 | } 94 | 95 | /// Get type by name 96 | pub fn type_by_name(&self, name: impl AsRef) -> Result, Error> { 97 | let name = cstr!(name.as_ref()); 98 | unsafe { Type::from_inner(llvm::core::LLVMGetTypeByName2(self.llvm(), name.as_ptr())) } 99 | } 100 | 101 | // TODO: LLVMContextGetDiagnosticHandler, LLVMContextSetDiagnosticHandler, 102 | // LLVMContextSetYieldCallback, ... 103 | } 104 | -------------------------------------------------------------------------------- /src/codegen.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | use std::sync::Mutex; 4 | 5 | /// Platform-specific machine code 6 | pub struct Codegen(Vec, Vec, Binary); 7 | 8 | impl AsRef<[u8]> for Codegen { 9 | fn as_ref(&self) -> &[u8] { 10 | self.0.as_ref() 11 | } 12 | } 13 | 14 | impl From for Vec { 15 | fn from(x: Codegen) -> Vec { 16 | x.0 17 | } 18 | } 19 | 20 | lazy_static::lazy_static! { 21 | static ref MUTEX: Mutex<()> = Mutex::new(()); 22 | } 23 | 24 | impl Codegen { 25 | /// Create new `Codegen` context 26 | pub fn new<'a>( 27 | module: &Module, 28 | symbols: impl AsRef<[&'a str]>, 29 | opt: bool, 30 | ) -> Result { 31 | let _handle = MUTEX.lock()?; 32 | 33 | let lto = unsafe { wrap_inner(llvm::lto::lto_codegen_create_in_local_context())? }; 34 | 35 | let s = module.clone().write_bitcode_to_memory_buffer()?; 36 | let context = module.context()?; 37 | let bin = Binary::new(&context, &s)?; 38 | 39 | let mut cg = Codegen(Vec::new(), Vec::new(), bin); 40 | 41 | for sym in symbols.as_ref() { 42 | cg.preserve_symbol(lto.as_ptr(), sym) 43 | } 44 | 45 | cg.add_module(lto.as_ptr(), module)?; 46 | 47 | cg.0 = if opt { 48 | cg.compile_optimized(lto.as_ptr())? 49 | } else { 50 | cg.compile(lto.as_ptr())? 51 | }; 52 | unsafe { llvm::lto::lto_codegen_dispose(lto.as_ptr()) } 53 | Ok(cg) 54 | } 55 | 56 | fn add_module(&mut self, lto: llvm::lto::lto_code_gen_t, module: &Module) -> Result<(), Error> { 57 | if let Ok(func) = module.first_function() { 58 | let mut func = func; 59 | self.1.push(func.as_ref().name()?.to_string()); 60 | 61 | while let Ok(f) = func.next_function() { 62 | self.1.push(f.as_ref().name()?.to_string()); 63 | func = f; 64 | } 65 | } 66 | 67 | let module = unsafe { 68 | llvm::lto::lto_module_create_in_codegen_context( 69 | self.2.as_ref().as_ptr() as *mut c_void, 70 | self.2.as_ref().len(), 71 | std::ptr::null(), 72 | lto, 73 | ) 74 | }; 75 | 76 | if module.is_null() { 77 | let msg = unsafe { llvm::core::LLVMCreateMessage(llvm::lto::lto_get_error_message()) }; 78 | return Err(Error::Message(Message(msg))); 79 | } 80 | 81 | unsafe { llvm::lto::lto_codegen_set_module(lto, module) }; 82 | Ok(()) 83 | } 84 | 85 | fn compile(&self, lto: llvm::lto::lto_code_gen_t) -> Result, Error> { 86 | let mut len = 0; 87 | let ptr = unsafe { llvm::lto::lto_codegen_compile(lto, &mut len) }; 88 | 89 | if ptr.is_null() { 90 | let msg = unsafe { llvm::core::LLVMCreateMessage(llvm::lto::lto_get_error_message()) }; 91 | return Err(Error::Message(Message(msg))); 92 | } 93 | 94 | unsafe { Ok(std::slice::from_raw_parts(ptr as *const u8, len).into()) } 95 | } 96 | 97 | fn compile_optimized(&self, lto: llvm::lto::lto_code_gen_t) -> Result, Error> { 98 | let mut len = 0; 99 | let ptr = unsafe { llvm::lto::lto_codegen_compile_optimized(lto, &mut len) }; 100 | 101 | if ptr.is_null() { 102 | let msg = unsafe { llvm::core::LLVMCreateMessage(llvm::lto::lto_get_error_message()) }; 103 | return Err(Error::Message(Message(msg))); 104 | } 105 | 106 | unsafe { Ok(std::slice::from_raw_parts(ptr as *const u8, len).into()) } 107 | } 108 | 109 | fn preserve_symbol(&self, lto: llvm::lto::lto_code_gen_t, name: impl AsRef) { 110 | let name = cstr!(name.as_ref()); 111 | unsafe { llvm::lto::lto_codegen_add_must_preserve_symbol(lto, name.as_ptr()) } 112 | } 113 | 114 | /// Get a list of exported symbols 115 | pub fn symbols(&self) -> &Vec { 116 | &self.1 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/basic_block.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// BasicBlock wraps LLVMBasicBlock 4 | #[derive(Copy)] 5 | pub struct BasicBlock<'a>(NonNull, PhantomData<&'a ()>); 6 | 7 | llvm_inner_impl!(BasicBlock<'a>, llvm::LLVMBasicBlock); 8 | 9 | impl<'a> Clone for BasicBlock<'a> { 10 | fn clone(&self) -> BasicBlock<'a> { 11 | BasicBlock(self.0, PhantomData) 12 | } 13 | } 14 | 15 | impl<'a> BasicBlock<'a> { 16 | /// Wrap a raw pointer 17 | pub fn from_inner(ptr: *mut llvm::LLVMBasicBlock) -> Result { 18 | Ok(BasicBlock(wrap_inner(ptr)?, PhantomData)) 19 | } 20 | 21 | /// Create a new basic block 22 | pub fn new(ctx: &Context<'a>, name: impl AsRef) -> Result { 23 | let name = cstr!(name.as_ref()); 24 | let bb = unsafe { llvm::core::LLVMCreateBasicBlockInContext(ctx.llvm(), name.as_ptr()) }; 25 | Self::from_inner(bb) 26 | } 27 | 28 | /// Get the context used to create the basic block 29 | pub fn context(self) -> Result, Error> { 30 | self.to_value()?.into_context() 31 | } 32 | 33 | /// Append a new value to the basic block 34 | pub fn append( 35 | ctx: &Context<'a>, 36 | f: impl AsRef>, 37 | name: impl AsRef, 38 | ) -> Result { 39 | let name = cstr!(name.as_ref()); 40 | let bb = unsafe { 41 | llvm::core::LLVMAppendBasicBlockInContext(ctx.llvm(), f.as_ref().llvm(), name.as_ptr()) 42 | }; 43 | Self::from_inner(bb) 44 | } 45 | 46 | /// Remove and destroy basic block 47 | pub fn delete(self) { 48 | unsafe { llvm::core::LLVMDeleteBasicBlock(self.llvm()) } 49 | } 50 | 51 | /// Remove basic block, keeping the block alive 52 | pub fn remove_from_parent(self) { 53 | unsafe { llvm::core::LLVMRemoveBasicBlockFromParent(self.llvm()) } 54 | } 55 | 56 | /// Move basic block before another basic block 57 | pub fn move_before(self, bb: BasicBlock<'a>) { 58 | unsafe { llvm::core::LLVMMoveBasicBlockBefore(self.llvm(), bb.llvm()) } 59 | } 60 | 61 | /// Move basic block after another basic block 62 | pub fn move_after(self, bb: BasicBlock<'a>) { 63 | unsafe { llvm::core::LLVMMoveBasicBlockAfter(self.llvm(), bb.llvm()) } 64 | } 65 | 66 | /// Convert a basic block to a `Value` 67 | pub fn to_value(self) -> Result, Error> { 68 | let ptr = unsafe { llvm::core::LLVMBasicBlockAsValue(self.llvm()) }; 69 | Value::from_inner(ptr) 70 | } 71 | 72 | /// Get the basic block name 73 | pub fn name(self) -> Result<&'a str, Error> { 74 | unsafe { 75 | let s = llvm::core::LLVMGetBasicBlockName(self.llvm()); 76 | let s = std::slice::from_raw_parts(s as *const u8, strlen(s)); 77 | let s = std::str::from_utf8(s)?; 78 | Ok(s) 79 | } 80 | } 81 | 82 | /// Get the basic block parent value 83 | pub fn parent(self) -> Result, Error> { 84 | unsafe { 85 | let ptr = llvm::core::LLVMGetBasicBlockParent(self.llvm()); 86 | Value::from_inner(ptr) 87 | } 88 | } 89 | 90 | /// Get the basic block terminator value 91 | pub fn terminator(self) -> Result, Error> { 92 | unsafe { 93 | let ptr = llvm::core::LLVMGetBasicBlockTerminator(self.llvm()); 94 | Value::from_inner(ptr) 95 | } 96 | } 97 | 98 | /// Get the first instruction in a basic block 99 | pub fn first_instruction(self) -> Result, Error> { 100 | unsafe { 101 | let ptr = llvm::core::LLVMGetFirstInstruction(self.llvm()); 102 | Value::from_inner(ptr) 103 | } 104 | } 105 | 106 | /// Get the last instruction in a basic block 107 | pub fn last_instruction(self) -> Result, Error> { 108 | unsafe { 109 | let ptr = llvm::core::LLVMGetLastInstruction(self.llvm()); 110 | Value::from_inner(ptr) 111 | } 112 | } 113 | 114 | /// Get the next basic block 115 | pub fn next_basic_block(self) -> Result, Error> { 116 | unsafe { 117 | let ptr = llvm::core::LLVMGetNextBasicBlock(self.llvm()); 118 | Self::from_inner(ptr) 119 | } 120 | } 121 | 122 | /// Get the previous basic_block 123 | pub fn prev_basic_block(self) -> Result, Error> { 124 | unsafe { 125 | let ptr = llvm::core::LLVMGetPreviousBasicBlock(self.llvm()); 126 | Self::from_inner(ptr) 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | #[test] 4 | fn codegen() -> Result<(), Error> { 5 | let jit = Jit::new("test_codegen", Some(2))?; 6 | 7 | let i32 = Type::of::(jit.context())?; 8 | 9 | let ft = FuncType::new(i32, &[i32, i32])?; 10 | jit.declare_function("testing", ft, |builder, f| { 11 | let params = f.params(); 12 | let a = builder.add(params[0], params[1], "a")?; 13 | builder.ret(&a) 14 | })?; 15 | 16 | println!("{}", jit.module()); 17 | 18 | jit.module().verify()?; 19 | 20 | let testing: extern "C" fn(i32, i32) -> i32 = unsafe { jit.engine().function("testing")? }; 21 | 22 | let x: i32 = testing(1i32, 2i32); 23 | assert_eq!(x, 3); 24 | 25 | Codegen::new(jit.module(), &["testing"], true)?; 26 | 27 | Ok(()) 28 | } 29 | 30 | #[test] 31 | fn if_then_else() -> Result<(), Error> { 32 | let jit = Jit::new("test_if_then_else", None)?; 33 | 34 | let f32 = Type::float(jit.context())?; 35 | let ft = FuncType::new(f32, &[f32])?; 36 | 37 | jit.declare_function("testing", ft, |builder, f| { 38 | let params = f.params(); 39 | let cond = builder.fcmp( 40 | Fcmp::LLVMRealULT, 41 | ¶ms[0], 42 | Const::real(f32, 10.0)?, 43 | "cond", 44 | )?; 45 | let a = Const::real(f32, 1.0)?; 46 | let b = Const::real(f32, 2.0)?; 47 | let ite = builder.if_then_else(cond, |_| Ok(a), |_| Ok(b))?; 48 | 49 | let ret = builder.ret(ite); 50 | f.verify()?; 51 | ret 52 | })?; 53 | 54 | println!("{}", jit.module()); 55 | 56 | let testing: extern "C" fn(f32) -> f32 = unsafe { jit.engine().function("testing")? }; 57 | let x = testing(11.0); 58 | let y = testing(9.0); 59 | 60 | assert_eq!(x, 2.0); 61 | assert_eq!(y, 1.0); 62 | 63 | Codegen::new(jit.module(), &["testing"], false)?; 64 | 65 | Ok(()) 66 | } 67 | 68 | #[test] 69 | fn for_loop() -> Result<(), Error> { 70 | let jit = Jit::new("test_for_loop", None)?; 71 | 72 | let i64 = Type::int(jit.context(), 64)?; 73 | 74 | let ft = FuncType::new(i64, &[i64])?; 75 | jit.declare_function("testing", ft, |build, f| { 76 | let params = f.params(); 77 | let one = Const::int_sext(i64, 1)?; 78 | let f = build.for_loop( 79 | Const::int_sext(i64, 0)?, 80 | |x| build.icmp(Icmp::LLVMIntSLT, x, params[0], "cond"), 81 | |x| build.add(x, one, "add"), 82 | |x| Ok(*x), 83 | )?; 84 | build.ret(f) 85 | })?; 86 | 87 | println!("{}", jit.module()); 88 | 89 | let testing: extern "C" fn(i64) -> i64 = unsafe { jit.engine().function("testing")? }; 90 | let x = testing(10); 91 | 92 | println!("{}", x); 93 | assert_eq!(x, 9); 94 | 95 | let x = testing(100); 96 | assert_eq!(x, 99); 97 | 98 | let (_ctx, _builder, engine) = jit.into_inner(); 99 | Codegen::new(&engine.into_module()?, &["testing"], true)?; 100 | 101 | Ok(()) 102 | } 103 | 104 | extern "C" fn testing123() -> i32 { 105 | 123 106 | } 107 | 108 | extern "C" fn testing1234() -> i32 { 109 | 1234 110 | } 111 | 112 | #[test] 113 | fn test_add_symbol() -> Result<(), Error> { 114 | let jit = Jit::new("test_add_symbol", None)?; 115 | 116 | symbol!(testing123, testing1234); 117 | 118 | let i32 = Type::int(jit.context(), 32)?; 119 | 120 | let testing123_t = FuncType::new(i32, &[])?; 121 | let testing1234_t = FuncType::new(i32, &[])?; 122 | let testing123 = jit.define_function("testing123", testing123_t)?; 123 | let testing1234 = jit.define_function("testing1234", testing1234_t)?; 124 | 125 | jit.declare_function("testing", testing123.func_type()?, |build, _| { 126 | build.ret(build.call(testing123, &[], "call")?) 127 | })?; 128 | 129 | jit.declare_function("testing1", testing1234.func_type()?, |build, _| { 130 | build.ret(build.call(testing1234, &[], "call")?) 131 | })?; 132 | 133 | let testing: extern "C" fn() -> i32 = unsafe { jit.engine().function("testing")? }; 134 | let testing1: extern "C" fn() -> i32 = unsafe { jit.engine().function("testing1")? }; 135 | let x = testing(); 136 | let y = testing1(); 137 | 138 | println!("{}", x); 139 | assert_eq!(x, 123); 140 | 141 | println!("{}", y); 142 | assert_eq!(y, 1234); 143 | 144 | Ok(()) 145 | } 146 | 147 | #[test] 148 | fn test_rust_struct() -> Result<(), Error> { 149 | struct Test { 150 | a: i64, 151 | b: i64, 152 | } 153 | 154 | #[no_mangle] 155 | unsafe extern "C" fn test_add(t: *mut Test) -> i64 { 156 | let x = &*t; 157 | x.a + x.b 158 | } 159 | 160 | #[no_mangle] 161 | unsafe extern "C" fn test_free(t: *mut Test) { 162 | println!("FREE"); 163 | drop(Box::from_raw(t)) 164 | } 165 | 166 | #[no_mangle] 167 | unsafe extern "C" fn mk_test(a: i64, b: i64) -> *mut Test { 168 | Box::into_raw(Box::new(Test { a, b })) 169 | } 170 | 171 | let jit = Jit::new("test_rust_struct", None)?; 172 | let ctx = jit.context(); 173 | let module = jit.module(); 174 | 175 | symbol!(test_add, mk_test, test_free); 176 | 177 | let i8 = Type::int(ctx, 8)?; 178 | let ptr = i8.pointer(None)?; 179 | 180 | let i64 = Type::int(ctx, 64)?; 181 | 182 | let mk_test = jit.define_function("mk_test", FuncType::new(ptr, &[i64, i64])?)?; 183 | let test_add = jit.define_function("test_add", FuncType::new(i64, &[ptr])?)?; 184 | let test_free = jit.define_function("test_free", FuncType::new(Type::void(ctx)?, &[ptr])?)?; 185 | 186 | let run_test_t = FuncType::new(i64, &[i64, i64])?; 187 | 188 | jit.declare_function("run_test", run_test_t, |build, f| { 189 | let a = f.param(0)?; 190 | let b = f.param(1)?; 191 | 192 | let x = build.call(mk_test, &[a, b], "mk_test")?; 193 | let y = build.call(test_add, &[x.into()], "test_add")?; 194 | build.call(test_free, &[x.into()], "free")?; 195 | 196 | build.ret(y) 197 | })?; 198 | 199 | println!("{}", module); 200 | 201 | let run_test: extern "C" fn(i64, i64) -> i64 = unsafe { jit.engine().function("run_test")? }; 202 | 203 | let x = run_test(10, 20); 204 | assert_eq!(30, x); 205 | 206 | Ok(()) 207 | } 208 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::should_implement_trait)] 2 | #![deny(missing_docs)] 3 | 4 | //! `llama` is a friendly LLVM wrapper 5 | //! 6 | //! # Getting started 7 | //! ```rust, no_run 8 | //! use llama::*; 9 | //! 10 | //! // Convenience type alias for the `sum` function. 11 | //! // 12 | //! // Calling this is innately `unsafe` because there's no guarantee it doesn't 13 | //! // do `unsafe` operations internally. 14 | //! type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64; 15 | //! 16 | //! fn compile_sum(jit: &mut Jit) -> Result { 17 | //! let i64 = Type::i64(jit.context())?; 18 | //! let sum_t = FuncType::new(i64, [i64, i64, i64])?; 19 | //! jit.declare_function("sum", sum_t, |build, f| { 20 | //! let params = f.params(); 21 | //! let x = params[0]; 22 | //! let y = params[1]; 23 | //! let z = params[2]; 24 | //! 25 | //! let sum = build.add(x, y, "sum")?; 26 | //! let sum = build.add(sum, z, "sum")?; 27 | //! build.ret(sum) 28 | //! })?; 29 | //! 30 | //! unsafe { jit.engine().function("sum") } 31 | //! } 32 | //! 33 | //! fn main() -> Result<(), Error> { 34 | //! let mut jit = Jit::new("sum", None)?; 35 | //! 36 | //! let sum = compile_sum(&mut jit)?; 37 | //! 38 | //! let x = 1u64; 39 | //! let y = 2u64; 40 | //! let z = 3u64; 41 | //! 42 | //! unsafe { 43 | //! println!("{} + {} + {} = {}", x, y, z, sum(x, y, z)); 44 | //! assert_eq!(sum(x, y, z), x + y + z); 45 | //! } 46 | //! 47 | //! Ok(()) 48 | //! } 49 | //! ``` 50 | 51 | #[allow(non_snake_case)] 52 | macro_rules! cstr { 53 | ($x:expr) => { 54 | std::ffi::CString::new($x).expect("Invalid C string") 55 | }; 56 | } 57 | 58 | macro_rules! llvm_inner_impl { 59 | ($t:ty, $u:ty) => { 60 | impl<'a> LLVM<$u> for $t { 61 | fn llvm(&self) -> *mut $u { 62 | self.0.as_ptr() 63 | } 64 | } 65 | }; 66 | } 67 | 68 | macro_rules! const_func { 69 | ($x:ident($(& $amp:ident$(,)?)? $($n:ident : $t:ty),*$(,)?) $b:block) => { 70 | pub fn $x<'b>($($amp,)? $($n : $t),*) -> Result, Error> { 71 | unsafe { 72 | Ok(Const(Value::from_inner($b)?)) 73 | } 74 | } 75 | } 76 | } 77 | 78 | macro_rules! instr { 79 | ($x:ident($(&$amp:ident$(,)?)? $($n:ident : $t:ty),*$(,)?) $b:block) => { 80 | pub fn $x<'b>($(& $amp,)? $($n : $t),*) -> Result, Error> { 81 | unsafe { 82 | Instr::from_inner($b) 83 | } 84 | } 85 | }; 86 | 87 | ($ret:ident: $x:ident($(&$amp:ident$(,)?)? $($n:ident : $t:ty),*$(,)?) $b:block) => { 88 | pub fn $x<'b>($(& $amp,)? $($n : $t),*) -> Result<$ret<'b>, Error> { 89 | unsafe { 90 | Ok($ret::from_instr(Instr::from_inner($b)?)) 91 | } 92 | } 93 | } 94 | } 95 | 96 | extern "C" { 97 | fn strlen(_: *const std::os::raw::c_char) -> usize; 98 | } 99 | 100 | mod attribute; 101 | mod basic_block; 102 | mod binary; 103 | mod builder; 104 | mod codegen; 105 | mod r#const; 106 | mod context; 107 | mod error; 108 | mod execution_engine; 109 | mod instr; 110 | mod jit; 111 | mod memory_buffer; 112 | mod message; 113 | mod metadata; 114 | mod module; 115 | mod pass_manager; 116 | mod target; 117 | mod r#type; 118 | mod value; 119 | 120 | pub(crate) use std::ffi::c_void; 121 | pub(crate) use std::marker::PhantomData; 122 | pub(crate) use std::os::raw::{c_char, c_int, c_uint}; 123 | pub(crate) use std::ptr::NonNull; 124 | 125 | /// Re-export `llvm_sys` to provide access to any missing functionality 126 | pub use llvm_sys as llvm; 127 | 128 | pub use crate::attribute::Attribute; 129 | pub use crate::basic_block::BasicBlock; 130 | pub use crate::binary::Binary; 131 | pub use crate::builder::Builder; 132 | pub use crate::codegen::Codegen; 133 | pub use crate::context::Context; 134 | pub use crate::error::Error; 135 | pub use crate::execution_engine::ExecutionEngine; 136 | pub use crate::instr::*; 137 | pub use crate::jit::Jit; 138 | pub use crate::memory_buffer::MemoryBuffer; 139 | pub use crate::message::Message; 140 | pub use crate::metadata::Metadata; 141 | pub use crate::module::Module; 142 | pub use crate::pass_manager::{ 143 | transforms, FuncPassManager, ModulePassManager, PassManager, Transform, 144 | }; 145 | pub use crate::r#const::Const; 146 | pub use crate::r#type::{FuncType, StructType, Type, TypeKind}; 147 | pub use crate::target::{Target, TargetData, TargetMachine}; 148 | pub use crate::value::{AttributeIndex, Func, Value, ValueKind}; 149 | 150 | pub use llvm::{ 151 | object::LLVMBinaryType as BinaryType, 152 | target::LLVMByteOrdering as ByteOrder, 153 | target_machine::{ 154 | LLVMCodeGenOptLevel as CodeGenOptLevel, LLVMCodeModel as CodeModel, 155 | LLVMRelocMode as RelocMode, 156 | }, 157 | LLVMAtomicOrdering as AtomicOrdering, LLVMAtomicRMWBinOp as AtomicRMWBinOp, 158 | LLVMCallConv as CallConv, LLVMDiagnosticSeverity as DiagnosticSeverity, 159 | LLVMInlineAsmDialect as InlineAsmDialect, LLVMIntPredicate as Icmp, LLVMLinkage as Linkage, 160 | LLVMModuleFlagBehavior as ModuleFlagBehavior, LLVMOpcode as OpCode, LLVMRealPredicate as Fcmp, 161 | LLVMThreadLocalMode as ThreadLocalMode, LLVMUnnamedAddr as UnnamedAddr, 162 | LLVMVisibility as Visibility, 163 | }; 164 | 165 | /// Allows for llama types to be converted into LLVM pointers 166 | pub trait LLVM { 167 | /// Return a LLVM pointer 168 | fn llvm(&self) -> *mut T; 169 | } 170 | 171 | pub(crate) fn wrap_inner(x: *mut T) -> Result, Error> { 172 | match NonNull::new(x) { 173 | Some(x) => Ok(x), 174 | None => Err(Error::NullPointer), 175 | } 176 | } 177 | 178 | /// Load a shared library 179 | pub fn load_library(filename: impl AsRef) -> bool { 180 | let filename = cstr!(filename 181 | .as_ref() 182 | .to_str() 183 | .expect("Invalid filename in call to load_library")); 184 | unsafe { llvm::support::LLVMLoadLibraryPermanently(filename.as_ptr()) == 0 } 185 | } 186 | 187 | /// Add a symbol 188 | pub fn add_symbol(name: impl AsRef, x: *mut T) { 189 | let name = cstr!(name.as_ref()); 190 | unsafe { llvm::support::LLVMAddSymbol(name.as_ptr(), x as *mut c_void) } 191 | } 192 | 193 | #[macro_export] 194 | /// Add symbols to the global namespace 195 | /// 196 | /// There are a few ways to use this macro: 197 | /// 198 | /// 1) `symbol!(foo, bar)`: adds symbols for `foo` and `bar` in the local namespace, this 199 | /// is particularly useful for adding symbols for C functions 200 | /// 2) `symbol!(foo: something::my_foo)`: adds a symbol for `foo` which maps to the rust function 201 | /// `something::my_foo` 202 | macro_rules! symbol { 203 | ($($name:ident),*) => { 204 | $( 205 | $crate::add_symbol(stringify!($name), $name as *mut std::ffi::c_void); 206 | )* 207 | }; 208 | 209 | ($($name:ident : $path:path),*) => { 210 | $( 211 | $crate::add_symbol(stringify!($name), $path as *mut std::ffi::c_void); 212 | )* 213 | }; 214 | } 215 | 216 | /// Get the default target triple 217 | pub fn default_target_triple() -> &'static str { 218 | unsafe { 219 | let ptr = llvm::target_machine::LLVMGetDefaultTargetTriple(); 220 | let slice = std::slice::from_raw_parts(ptr as *const u8, strlen(ptr)); 221 | std::str::from_utf8_unchecked(slice) 222 | } 223 | } 224 | 225 | #[cfg(test)] 226 | mod tests; 227 | -------------------------------------------------------------------------------- /src/execution_engine.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// An execution engine can be used to execute JIT compiled code 4 | pub struct ExecutionEngine<'a>( 5 | NonNull, 6 | Module<'a>, 7 | PhantomData<&'a ()>, 8 | ); 9 | 10 | llvm_inner_impl!( 11 | ExecutionEngine<'a>, 12 | llvm::execution_engine::LLVMOpaqueExecutionEngine 13 | ); 14 | 15 | impl<'a> Drop for ExecutionEngine<'a> { 16 | fn drop(&mut self) { 17 | unsafe { llvm::execution_engine::LLVMDisposeExecutionEngine(self.llvm()) } 18 | } 19 | } 20 | 21 | impl<'a> ExecutionEngine<'a> { 22 | /// Create a new execution engine using `LLVMCreateExectionEngineForModule` 23 | pub fn new(module: Module<'a>) -> Result, Error> { 24 | unsafe { llvm::execution_engine::LLVMLinkInInterpreter() } 25 | 26 | if module 27 | .1 28 | .compare_exchange( 29 | true, 30 | false, 31 | std::sync::atomic::Ordering::Relaxed, 32 | std::sync::atomic::Ordering::Relaxed, 33 | ) 34 | .is_err() 35 | { 36 | return Err(Error::ModuleIsAlreadyOwned); 37 | } 38 | 39 | let mut engine = std::ptr::null_mut(); 40 | let mut message = std::ptr::null_mut(); 41 | let r = unsafe { 42 | llvm::execution_engine::LLVMCreateExecutionEngineForModule( 43 | &mut engine, 44 | module.llvm(), 45 | &mut message, 46 | ) == 1 47 | }; 48 | 49 | let message = Message::from_raw(message); 50 | if r { 51 | module.1.store(true, std::sync::atomic::Ordering::Relaxed); 52 | return Err(Error::Message(message)); 53 | } 54 | 55 | Ok(ExecutionEngine(wrap_inner(engine)?, module, PhantomData)) 56 | } 57 | 58 | /// Create new JIT compiler with optimization level 59 | pub fn new_jit(module: Module<'a>, opt: usize) -> Result, Error> { 60 | unsafe { llvm::execution_engine::LLVMLinkInMCJIT() } 61 | 62 | if module 63 | .1 64 | .compare_exchange( 65 | true, 66 | false, 67 | std::sync::atomic::Ordering::Relaxed, 68 | std::sync::atomic::Ordering::Relaxed, 69 | ) 70 | .is_err() 71 | { 72 | return Err(Error::ModuleIsAlreadyOwned); 73 | } 74 | 75 | let mut opts = llvm::execution_engine::LLVMMCJITCompilerOptions { 76 | OptLevel: opt as c_uint, 77 | CodeModel: llvm::target_machine::LLVMCodeModel::LLVMCodeModelJITDefault, 78 | NoFramePointerElim: 0, 79 | EnableFastISel: 0, 80 | MCJMM: std::ptr::null_mut(), 81 | }; 82 | let mut engine = std::ptr::null_mut(); 83 | let mut message = std::ptr::null_mut(); 84 | let r = unsafe { 85 | llvm::execution_engine::LLVMCreateMCJITCompilerForModule( 86 | &mut engine, 87 | module.llvm(), 88 | &mut opts, 89 | std::mem::size_of::(), 90 | &mut message, 91 | ) == 1 92 | }; 93 | 94 | let message = Message::from_raw(message); 95 | if r { 96 | module.1.store(true, std::sync::atomic::Ordering::Relaxed); 97 | return Err(Error::Message(message)); 98 | } 99 | 100 | Ok(ExecutionEngine(wrap_inner(engine)?, module, PhantomData)) 101 | } 102 | 103 | /// Get a function from within the execution engine 104 | /// 105 | /// # Safety 106 | /// This function does nothing to ensure that the function actually matches the type you give 107 | /// it 108 | pub unsafe fn function(&self, name: impl AsRef) -> Result { 109 | let name = cstr!(name.as_ref()); 110 | let ptr = llvm::execution_engine::LLVMGetFunctionAddress(self.llvm(), name.as_ptr()); 111 | Ok(std::mem::transmute_copy(&(ptr as *mut c_void))) 112 | } 113 | 114 | /// Get a pointer to a global value from within the execution engine 115 | /// 116 | /// # Safety 117 | /// This function does nothing to ensure that the function actually matches the type you give 118 | /// it 119 | pub unsafe fn global_value(&self, name: impl AsRef) -> Result, Error> { 120 | let name = cstr!(name.as_ref()); 121 | let ptr = llvm::execution_engine::LLVMGetGlobalValueAddress(self.llvm(), name.as_ptr()) 122 | as *mut llvm::LLVMValue; 123 | Value::from_inner(ptr) 124 | } 125 | 126 | /// Get a pointer to a global from within the execution engine 127 | /// 128 | /// # Safety 129 | /// This function does nothing to ensure that the function actually matches the type you give 130 | /// it 131 | pub unsafe fn global(&self, global: impl AsRef>) -> Result<&mut T, Error> { 132 | let ptr = 133 | llvm::execution_engine::LLVMGetPointerToGlobal(self.llvm(), global.as_ref().llvm()); 134 | 135 | Ok(&mut *(ptr as *mut T)) 136 | } 137 | 138 | /// Run static constructors 139 | pub fn run_static_constructors(&self) { 140 | unsafe { llvm::execution_engine::LLVMRunStaticConstructors(self.llvm()) } 141 | } 142 | 143 | /// Run static destructors 144 | pub fn run_static_destructors(&self) { 145 | unsafe { llvm::execution_engine::LLVMRunStaticDestructors(self.llvm()) } 146 | } 147 | 148 | /// Add mapping between global value and a local object 149 | pub fn add_global_mapping(&mut self, global: impl AsRef>, data: *mut T) { 150 | unsafe { 151 | llvm::execution_engine::LLVMAddGlobalMapping( 152 | self.llvm(), 153 | global.as_ref().llvm(), 154 | data as *mut c_void, 155 | ) 156 | } 157 | } 158 | 159 | /// Get target data 160 | pub fn target_data(&self) -> Result { 161 | let x = unsafe { llvm::execution_engine::LLVMGetExecutionEngineTargetData(self.llvm()) }; 162 | TargetData::from_inner(x) 163 | } 164 | 165 | /// Get handle to underlying module 166 | pub fn module(&self) -> &Module<'a> { 167 | &self.1 168 | } 169 | 170 | /// Get mutable handle to underlying module 171 | pub fn module_mut(&mut self) -> &mut Module<'a> { 172 | &mut self.1 173 | } 174 | 175 | /// Get inner module 176 | pub fn into_module(self) -> Result, Error> { 177 | let mut message = std::ptr::null_mut(); 178 | let mut ptr = std::ptr::null_mut(); 179 | let rc = unsafe { 180 | llvm::execution_engine::LLVMRemoveModule( 181 | self.llvm(), 182 | self.1.llvm(), 183 | &mut ptr, 184 | &mut message as *mut *mut std::os::raw::c_char, 185 | ) 186 | }; 187 | 188 | let message = Message::from_raw(message); 189 | if rc > 0 { 190 | return Err(Error::Message(message)); 191 | } 192 | 193 | let ptr = match std::ptr::NonNull::new(ptr) { 194 | Some(x) => x, 195 | None => return Err(Error::NullPointer), 196 | }; 197 | 198 | Ok(Module( 199 | ptr, 200 | std::sync::atomic::AtomicBool::new(true), 201 | PhantomData, 202 | )) 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/target.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// LLVMTargetData wrapper 4 | pub struct TargetData<'a>( 5 | NonNull, 6 | PhantomData<&'a ()>, 7 | ); 8 | 9 | llvm_inner_impl!(TargetData<'a>, llvm::target::LLVMOpaqueTargetData); 10 | 11 | impl<'a> Drop for TargetData<'a> { 12 | fn drop(&mut self) { 13 | unsafe { llvm::target::LLVMDisposeTargetData(self.llvm()) } 14 | } 15 | } 16 | 17 | impl<'a> TargetData<'a> { 18 | pub(crate) fn from_inner( 19 | x: *mut llvm::target::LLVMOpaqueTargetData, 20 | ) -> Result, Error> { 21 | Ok(TargetData(wrap_inner(x)?, PhantomData)) 22 | } 23 | 24 | /// Create new target data with the given triple 25 | pub fn new(s: impl AsRef) -> Result, Error> { 26 | let s = cstr!(s.as_ref()); 27 | unsafe { TargetData::from_inner(llvm::target::LLVMCreateTargetData(s.as_ptr())) } 28 | } 29 | 30 | /// Return a string representation 31 | pub fn string_rep(&self) -> Message { 32 | let ptr = unsafe { llvm::target::LLVMCopyStringRepOfTargetData(self.llvm()) }; 33 | Message::from_raw(ptr) 34 | } 35 | 36 | /// Get configured byte order 37 | pub fn byte_order(&self) -> ByteOrder { 38 | unsafe { llvm::target::LLVMByteOrder(self.llvm()) } 39 | } 40 | 41 | /// Get configured pointer size 42 | pub fn pointer_size(&self) -> usize { 43 | unsafe { llvm::target::LLVMPointerSize(self.llvm()) as usize } 44 | } 45 | 46 | /// Get pointer size for the given address space 47 | pub fn pointer_size_for_address_space(&self, addr_space: usize) -> usize { 48 | unsafe { llvm::target::LLVMPointerSizeForAS(self.llvm(), addr_space as c_uint) as usize } 49 | } 50 | 51 | /// Get the type used for integer pointers 52 | pub fn int_ptr_type(&self, ctx: &Context<'a>) -> Result, Error> { 53 | unsafe { 54 | Type::from_inner(llvm::target::LLVMIntPtrTypeInContext( 55 | ctx.llvm(), 56 | self.llvm(), 57 | )) 58 | } 59 | } 60 | 61 | /// Get the type used for integer pointers in the given address space 62 | pub fn int_ptr_type_for_address_space( 63 | &self, 64 | ctx: &Context<'a>, 65 | addr_space: usize, 66 | ) -> Result, Error> { 67 | unsafe { 68 | Type::from_inner(llvm::target::LLVMIntPtrTypeForASInContext( 69 | ctx.llvm(), 70 | self.llvm(), 71 | addr_space as c_uint, 72 | )) 73 | } 74 | } 75 | 76 | /// Get the size of a type in bits 77 | pub fn size_of_type_in_bits(&self, t: impl AsRef>) -> usize { 78 | unsafe { llvm::target::LLVMSizeOfTypeInBits(self.llvm(), t.as_ref().llvm()) as usize } 79 | } 80 | 81 | /// Get the storage size of a type 82 | pub fn store_size_of_type(&self, t: impl AsRef>) -> usize { 83 | unsafe { llvm::target::LLVMStoreSizeOfType(self.llvm(), t.as_ref().llvm()) as usize } 84 | } 85 | 86 | /// Get the ABI size of a type 87 | pub fn abi_size_of_type(&self, t: impl AsRef>) -> usize { 88 | unsafe { llvm::target::LLVMABISizeOfType(self.llvm(), t.as_ref().llvm()) as usize } 89 | } 90 | 91 | /// Get the ABI alignment of a type 92 | pub fn abi_alignment_of_type(&self, t: impl AsRef>) -> usize { 93 | unsafe { llvm::target::LLVMABIAlignmentOfType(self.llvm(), t.as_ref().llvm()) as usize } 94 | } 95 | 96 | /// Get the call frame alignment of a type 97 | pub fn call_frame_alignment_of_type(&self, t: impl AsRef>) -> usize { 98 | unsafe { 99 | llvm::target::LLVMCallFrameAlignmentOfType(self.llvm(), t.as_ref().llvm()) as usize 100 | } 101 | } 102 | 103 | /// Get type's preferred alignment 104 | pub fn preferred_alignment_of_type(&self, t: impl AsRef>) -> usize { 105 | unsafe { 106 | llvm::target::LLVMPreferredAlignmentOfType(self.llvm(), t.as_ref().llvm()) as usize 107 | } 108 | } 109 | 110 | /// Get preferred alignment for a global value 111 | pub fn preferred_alignment_of_global(&self, t: impl AsRef>) -> usize { 112 | unsafe { 113 | llvm::target::LLVMPreferredAlignmentOfGlobal(self.llvm(), t.as_ref().llvm()) as usize 114 | } 115 | } 116 | 117 | /// Get the index of the struct element at the given offset 118 | pub fn struct_element_at_offset(&self, t: impl AsRef>, offset: usize) -> usize { 119 | unsafe { 120 | llvm::target::LLVMElementAtOffset(self.llvm(), t.as_ref().llvm(), offset as u64) 121 | as usize 122 | } 123 | } 124 | 125 | /// Get the offset of the element at the given index 126 | pub fn struct_offset_of_element(&self, t: impl AsRef>, index: usize) -> usize { 127 | unsafe { 128 | llvm::target::LLVMOffsetOfElement(self.llvm(), t.as_ref().llvm(), index as c_uint) 129 | as usize 130 | } 131 | } 132 | } 133 | 134 | /// LLVMTarget wrapper 135 | pub struct Target(llvm::target_machine::LLVMTargetRef); 136 | 137 | impl<'a> Target { 138 | /// Get target from triple 139 | pub fn new(s: impl AsRef) -> Result { 140 | let s = cstr!(s.as_ref()); 141 | unsafe { 142 | let ptr = llvm::target_machine::LLVMGetTargetFromName(s.as_ptr()); 143 | if ptr.is_null() { 144 | return Err(Error::NullPointer); 145 | } 146 | Ok(Target(ptr)) 147 | } 148 | } 149 | 150 | /// Get the default target 151 | pub fn default() -> Result { 152 | Target::new(default_target_triple()) 153 | } 154 | 155 | /// Get host CPU name 156 | pub fn host_cpu_name() -> Message { 157 | unsafe { Message::from_raw(llvm::target_machine::LLVMGetHostCPUName()) } 158 | } 159 | 160 | /// Get host CPU features 161 | pub fn host_cpu_features() -> Message { 162 | unsafe { Message::from_raw(llvm::target_machine::LLVMGetHostCPUFeatures()) } 163 | } 164 | 165 | /// Get first registered target 166 | pub fn first() -> Result { 167 | unsafe { 168 | let ptr = llvm::target_machine::LLVMGetFirstTarget(); 169 | if ptr.is_null() { 170 | return Err(Error::NullPointer); 171 | } 172 | Ok(Target(ptr)) 173 | } 174 | } 175 | 176 | /// Get next targer 177 | pub fn next_target(&self) -> Result { 178 | unsafe { 179 | let ptr = llvm::target_machine::LLVMGetNextTarget(self.0); 180 | if ptr.is_null() { 181 | return Err(Error::NullPointer); 182 | } 183 | Ok(Target(ptr)) 184 | } 185 | } 186 | 187 | /// Get target name 188 | pub fn name(&self) -> Result<&str, Error> { 189 | unsafe { 190 | let s = llvm::target_machine::LLVMGetTargetName(self.0); 191 | let s = std::slice::from_raw_parts(s as *const u8, strlen(s)); 192 | let s = std::str::from_utf8(s)?; 193 | Ok(s) 194 | } 195 | } 196 | 197 | /// Returns true when the target has JIT capabilities 198 | pub fn has_jit(&self) -> bool { 199 | unsafe { llvm::target_machine::LLVMTargetHasJIT(self.0) == 1 } 200 | } 201 | 202 | /// Returns true when the target has an ASM backend 203 | pub fn has_asm_backend(&self) -> bool { 204 | unsafe { llvm::target_machine::LLVMTargetHasAsmBackend(self.0) == 1 } 205 | } 206 | } 207 | 208 | /// Information about the target machine 209 | pub struct TargetMachine<'a>( 210 | NonNull, 211 | PhantomData<&'a ()>, 212 | ); 213 | 214 | llvm_inner_impl!( 215 | TargetMachine<'a>, 216 | llvm::target_machine::LLVMOpaqueTargetMachine 217 | ); 218 | 219 | impl<'a> Drop for TargetMachine<'a> { 220 | fn drop(&mut self) { 221 | unsafe { llvm::target_machine::LLVMDisposeTargetMachine(self.llvm()) } 222 | } 223 | } 224 | 225 | impl<'a> TargetMachine<'a> { 226 | /// Create a new `TargetMachine` 227 | pub fn new( 228 | target: &Target, 229 | triple: impl AsRef, 230 | cpu: impl AsRef, 231 | features: impl AsRef, 232 | opt_level: CodeGenOptLevel, 233 | reloc: RelocMode, 234 | code_model: CodeModel, 235 | ) -> Result, Error> { 236 | let triple = cstr!(triple.as_ref()); 237 | let cpu = cstr!(cpu.as_ref()); 238 | let features = cstr!(features.as_ref()); 239 | unsafe { 240 | Ok(TargetMachine( 241 | wrap_inner(llvm::target_machine::LLVMCreateTargetMachine( 242 | target.0, 243 | triple.as_ptr(), 244 | cpu.as_ptr(), 245 | features.as_ptr(), 246 | opt_level, 247 | reloc, 248 | code_model, 249 | ))?, 250 | PhantomData, 251 | )) 252 | } 253 | } 254 | 255 | /// Get the target machine triple 256 | pub fn triple(&self) -> Message { 257 | unsafe { 258 | Message::from_raw(llvm::target_machine::LLVMGetTargetMachineTriple( 259 | self.llvm(), 260 | )) 261 | } 262 | } 263 | 264 | /// Get CPU name 265 | pub fn cpu(&self) -> Message { 266 | unsafe { Message::from_raw(llvm::target_machine::LLVMGetTargetMachineCPU(self.llvm())) } 267 | } 268 | 269 | /// Get feature string 270 | pub fn features(&self) -> Message { 271 | unsafe { 272 | Message::from_raw(llvm::target_machine::LLVMGetTargetMachineFeatureString( 273 | self.llvm(), 274 | )) 275 | } 276 | } 277 | 278 | /// Get data layout 279 | pub fn data_layout(&self) -> Result, Error> { 280 | unsafe { 281 | TargetData::from_inner(llvm::target_machine::LLVMCreateTargetDataLayout( 282 | self.llvm(), 283 | )) 284 | } 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /src/instr.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Instruction value 4 | #[derive(Copy)] 5 | pub struct Instr<'a>(pub(crate) Value<'a>); 6 | 7 | macro_rules! instr_type { 8 | ($(#[$meta:meta])* $name:ident) => { 9 | #[derive(Clone, Copy)] 10 | $(#[$meta])* 11 | pub struct $name<'a>(pub(crate) Value<'a>); 12 | impl<'a> AsRef> for $name<'a> { 13 | fn as_ref(&self) -> &Value<'a> { 14 | &self.0 15 | } 16 | } 17 | 18 | impl<'a> From<$name<'a>> for Value<'a> { 19 | fn from(x: $name<'a>) -> Value<'a> { 20 | x.0 21 | } 22 | } 23 | 24 | impl<'a> $name<'a> { 25 | /// Convert from `Instr` 26 | pub fn from_instr(i: Instr<'a>) -> Self { 27 | $name(i.into()) 28 | } 29 | 30 | /// Convert to `Instr` 31 | pub fn to_instr(self) -> Instr<'a> { 32 | Instr(self.0) 33 | } 34 | } 35 | }; 36 | } 37 | 38 | impl<'a> AsRef> for Instr<'a> { 39 | fn as_ref(&self) -> &Value<'a> { 40 | &self.0 41 | } 42 | } 43 | 44 | impl<'a> From> for Value<'a> { 45 | fn from(x: Instr<'a>) -> Value<'a> { 46 | x.0 47 | } 48 | } 49 | 50 | instr_type!( 51 | #[doc = "GEP instruction"] 52 | InstrGep 53 | ); 54 | instr_type!( 55 | #[doc = "Alloca instruction"] 56 | InstrAlloca 57 | ); 58 | instr_type!( 59 | #[doc = "Icmp instruction"] 60 | InstrIcmp 61 | ); 62 | instr_type!( 63 | #[doc = "Fcmp instruction"] 64 | InstrFcmp 65 | ); 66 | instr_type!( 67 | #[doc = "Phi instruction"] 68 | InstrPhi 69 | ); 70 | instr_type!( 71 | #[doc = "Call instruction"] 72 | InstrCall 73 | ); 74 | instr_type!( 75 | #[doc = "Switch instruction"] 76 | InstrSwitch 77 | ); 78 | instr_type!( 79 | #[doc = "IndirectBr instruction"] 80 | InstrIndirectBr 81 | ); 82 | 83 | impl<'a> Instr<'a> { 84 | /// Wrap an LLVMValue as `Instr` 85 | pub fn from_inner(ptr: *mut llvm::LLVMValue) -> Result { 86 | Ok(Instr(Value::from_inner(ptr)?)) 87 | } 88 | 89 | /// Get the parent block 90 | pub fn parent(self) -> Result, Error> { 91 | unsafe { 92 | BasicBlock::from_inner(llvm::core::LLVMGetInstructionParent(self.as_ref().llvm())) 93 | } 94 | } 95 | 96 | /// Get the next instruction 97 | pub fn next_instruction(self) -> Result, Error> { 98 | unsafe { 99 | Ok(Instr(Value::from_inner( 100 | llvm::core::LLVMGetNextInstruction(self.as_ref().llvm()), 101 | )?)) 102 | } 103 | } 104 | 105 | /// Get the previous instruction 106 | pub fn prev_instruction(self) -> Result, Error> { 107 | unsafe { 108 | Ok(Instr(Value::from_inner( 109 | llvm::core::LLVMGetPreviousInstruction(self.as_ref().llvm()), 110 | )?)) 111 | } 112 | } 113 | 114 | /// Remove and erase an instruction from its parent 115 | pub fn delete(self) { 116 | unsafe { llvm::core::LLVMInstructionEraseFromParent(self.as_ref().llvm()) } 117 | } 118 | 119 | /// Remove an instruction from its parent 120 | pub fn remove_from_parent(self) { 121 | unsafe { llvm::core::LLVMInstructionRemoveFromParent(self.as_ref().llvm()) } 122 | } 123 | 124 | /// Get an instruction's OpCode 125 | pub fn op_code(self) -> OpCode { 126 | unsafe { llvm::core::LLVMGetInstructionOpcode(self.as_ref().llvm()) } 127 | } 128 | 129 | /// Returns true when an instruction has associated metadata 130 | pub fn has_metadata(self) -> bool { 131 | unsafe { llvm::core::LLVMHasMetadata(self.as_ref().llvm()) == 1 } 132 | } 133 | 134 | /// Get associated metadata 135 | pub fn get_metadata(self, id: u32) -> Result, Error> { 136 | unsafe { 137 | Ok(Metadata(Value::from_inner(llvm::core::LLVMGetMetadata( 138 | self.as_ref().llvm(), 139 | id, 140 | ))?)) 141 | } 142 | } 143 | 144 | /// Set associated metadata 145 | pub fn set_metadata(self, id: u32, meta: Metadata<'a>) { 146 | unsafe { llvm::core::LLVMSetMetadata(self.as_ref().llvm(), id, meta.as_ref().llvm()) } 147 | } 148 | 149 | /// Get number of successors 150 | pub fn num_successors(self) -> usize { 151 | unsafe { llvm::core::LLVMGetNumSuccessors(self.as_ref().llvm()) as usize } 152 | } 153 | 154 | /// Get a successor by index 155 | pub fn successor(self, index: usize) -> Result, Error> { 156 | unsafe { 157 | BasicBlock::from_inner(llvm::core::LLVMGetSuccessor( 158 | self.as_ref().llvm(), 159 | index as c_uint, 160 | )) 161 | } 162 | } 163 | 164 | /// Set a successor block 165 | pub fn set_successor(&mut self, index: usize, bb: BasicBlock<'a>) { 166 | unsafe { llvm::core::LLVMSetSuccessor(self.as_ref().llvm(), index as c_uint, bb.llvm()) } 167 | } 168 | 169 | /// Returns true if the instruction is conditional 170 | pub fn is_conditional(self) -> bool { 171 | unsafe { llvm::core::LLVMIsConditional(self.as_ref().llvm()) == 1 } 172 | } 173 | 174 | /// Get the condition of a conditional 175 | pub fn condition(self) -> Result, Error> { 176 | unsafe { Value::from_inner(llvm::core::LLVMGetCondition(self.as_ref().llvm())) } 177 | } 178 | 179 | /// Set the condition of a conditional 180 | pub fn set_condition(&mut self, cond: impl AsRef>) { 181 | unsafe { llvm::core::LLVMSetCondition(self.as_ref().llvm(), cond.as_ref().llvm()) } 182 | } 183 | } 184 | 185 | impl<'a> InstrIcmp<'a> { 186 | /// Get integer comparison predicate 187 | pub fn predicate(self) -> Icmp { 188 | unsafe { llvm::core::LLVMGetICmpPredicate(self.as_ref().llvm()) } 189 | } 190 | } 191 | 192 | impl<'a> InstrFcmp<'a> { 193 | /// Get float comparison predicate 194 | pub fn predicate(self) -> Fcmp { 195 | unsafe { llvm::core::LLVMGetFCmpPredicate(self.as_ref().llvm()) } 196 | } 197 | } 198 | 199 | impl<'a> InstrAlloca<'a> { 200 | /// Get alloca type 201 | pub fn get_type(self) -> Result, Error> { 202 | unsafe { Type::from_inner(llvm::core::LLVMGetAllocatedType(self.as_ref().llvm())) } 203 | } 204 | } 205 | 206 | impl<'a> InstrPhi<'a> { 207 | /// Add incoming items 208 | pub fn add_incoming(&mut self, items: impl AsRef<[(Value<'a>, BasicBlock<'a>)]>) { 209 | let mut values: Vec<*mut llvm::LLVMValue> = 210 | items.as_ref().iter().map(|(v, _)| v.llvm()).collect(); 211 | 212 | let mut blocks: Vec<*mut llvm::LLVMBasicBlock> = 213 | items.as_ref().iter().map(|(_, v)| v.llvm()).collect(); 214 | 215 | let count = values.len(); 216 | unsafe { 217 | llvm::core::LLVMAddIncoming( 218 | self.as_ref().llvm(), 219 | values.as_mut_ptr(), 220 | blocks.as_mut_ptr(), 221 | count as c_uint, 222 | ) 223 | } 224 | } 225 | 226 | /// Return the number of incoming blocks/values 227 | pub fn count_incoming(self) -> usize { 228 | unsafe { llvm::core::LLVMCountIncoming(self.as_ref().llvm()) as usize } 229 | } 230 | 231 | /// Get incoming block 232 | pub fn incoming_value(self, index: usize) -> Result, Error> { 233 | unsafe { 234 | Value::from_inner(llvm::core::LLVMGetIncomingValue( 235 | self.as_ref().llvm(), 236 | index as c_uint, 237 | )) 238 | } 239 | } 240 | 241 | /// Get incoming value 242 | pub fn incoming_block(self, index: usize) -> Result, Error> { 243 | unsafe { 244 | BasicBlock::from_inner(llvm::core::LLVMGetIncomingBlock( 245 | self.as_ref().llvm(), 246 | index as c_uint, 247 | )) 248 | } 249 | } 250 | } 251 | 252 | impl<'a> InstrGep<'a> { 253 | /// Returns true when the GEP instruction is marked as in-bounds 254 | pub fn in_bounds(self) -> bool { 255 | unsafe { llvm::core::LLVMIsInBounds(self.as_ref().llvm()) == 1 } 256 | } 257 | 258 | /// Mark the GEP instruction as in-bounds 259 | pub fn set_in_bounds(&mut self, b: bool) { 260 | unsafe { llvm::core::LLVMSetIsInBounds(self.as_ref().llvm(), if b { 1 } else { 0 }) } 261 | } 262 | } 263 | 264 | impl<'a> InstrCall<'a> { 265 | /// Get number of operands for a call instruction 266 | pub fn num_operands(self) -> usize { 267 | unsafe { llvm::core::LLVMGetNumArgOperands(self.as_ref().llvm()) as usize } 268 | } 269 | 270 | /// Get called function type 271 | pub fn function_type(self) -> Result, Error> { 272 | unsafe { Type::from_inner(llvm::core::LLVMGetCalledFunctionType(self.as_ref().llvm())) } 273 | } 274 | 275 | /// Get called value 276 | pub fn value(self) -> Result, Error> { 277 | unsafe { Value::from_inner(llvm::core::LLVMGetCalledValue(self.as_ref().llvm())) } 278 | } 279 | 280 | /// Returns true when the call is marked as a tail call 281 | pub fn is_tail_call(self) -> bool { 282 | unsafe { llvm::core::LLVMIsTailCall(self.as_ref().llvm()) == 1 } 283 | } 284 | 285 | /// Mark the call as a tail call 286 | pub fn set_tail_call(&mut self, b: bool) { 287 | unsafe { llvm::core::LLVMSetTailCall(self.as_ref().llvm(), if b { 1 } else { 0 }) } 288 | } 289 | } 290 | 291 | impl<'a> InstrSwitch<'a> { 292 | /// Get the default destination block 293 | pub fn default_dest(self) -> Result, Error> { 294 | unsafe { 295 | BasicBlock::from_inner(llvm::core::LLVMGetSwitchDefaultDest(self.as_ref().llvm())) 296 | } 297 | } 298 | 299 | /// Add a new case 300 | pub fn add_case(&mut self, on_val: impl AsRef>, dest: BasicBlock<'a>) { 301 | unsafe { 302 | llvm::core::LLVMAddCase(self.as_ref().llvm(), on_val.as_ref().llvm(), dest.llvm()) 303 | } 304 | } 305 | } 306 | 307 | impl<'a> InstrIndirectBr<'a> { 308 | /// Add a destination 309 | pub fn add_dest(&mut self, dest: BasicBlock<'a>) { 310 | unsafe { llvm::core::LLVMAddDestination(self.as_ref().llvm(), dest.llvm()) } 311 | } 312 | } 313 | 314 | impl<'a> Clone for Instr<'a> { 315 | fn clone(&self) -> Instr<'a> { 316 | unsafe { 317 | Instr( 318 | Value::from_inner(llvm::core::LLVMInstructionClone(self.as_ref().llvm())).unwrap(), 319 | ) 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/module.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// Wraps LLVMModule 4 | pub struct Module<'a>( 5 | pub(crate) NonNull, 6 | pub(crate) std::sync::atomic::AtomicBool, 7 | pub(crate) PhantomData<&'a ()>, 8 | ); 9 | 10 | llvm_inner_impl!(Module<'a>, llvm::LLVMModule); 11 | 12 | impl<'a> Drop for Module<'a> { 13 | fn drop(&mut self) { 14 | if !self.1.load(std::sync::atomic::Ordering::Relaxed) { 15 | return; 16 | } 17 | 18 | unsafe { llvm::core::LLVMDisposeModule(self.llvm()) } 19 | } 20 | } 21 | 22 | impl<'a> Clone for Module<'a> { 23 | fn clone(&self) -> Module<'a> { 24 | let m = unsafe { 25 | wrap_inner(llvm::core::LLVMCloneModule(self.llvm())).expect("Invalid module") 26 | }; 27 | Module(m, std::sync::atomic::AtomicBool::new(true), PhantomData) 28 | } 29 | } 30 | 31 | impl<'a> Module<'a> { 32 | /// Create a new module 33 | pub fn new(ctx: &Context<'a>, name: impl AsRef) -> Result, Error> { 34 | let name = cstr!(name.as_ref()); 35 | let m = unsafe { 36 | wrap_inner(llvm::core::LLVMModuleCreateWithNameInContext( 37 | name.as_ptr(), 38 | ctx.llvm(), 39 | ))? 40 | }; 41 | Ok(Module( 42 | m, 43 | std::sync::atomic::AtomicBool::new(true), 44 | PhantomData, 45 | )) 46 | } 47 | 48 | /// Get the associated context 49 | pub fn context(&self) -> Result, Error> { 50 | let ctx = unsafe { wrap_inner(llvm::core::LLVMGetModuleContext(self.llvm()))? }; 51 | Ok(Context(ctx, false, PhantomData)) 52 | } 53 | 54 | /// Get the module identifier 55 | pub fn identifier(&self) -> Result<&str, Error> { 56 | let mut size = 0usize; 57 | unsafe { 58 | let s = llvm::core::LLVMGetModuleIdentifier(self.llvm(), &mut size); 59 | let s = std::slice::from_raw_parts(s as *const u8, size); 60 | let s = std::str::from_utf8(s)?; 61 | Ok(s) 62 | } 63 | } 64 | 65 | /// Set the module source file name 66 | pub fn set_source_file(&mut self, name: impl AsRef) { 67 | let len = name.as_ref().len(); 68 | let name = cstr!(name.as_ref()); 69 | unsafe { llvm::core::LLVMSetSourceFileName(self.llvm(), name.as_ptr(), len) } 70 | } 71 | 72 | /// Get the source file name 73 | pub fn source_file(&self) -> Result<&str, Error> { 74 | let mut size = 0; 75 | unsafe { 76 | let s = llvm::core::LLVMGetSourceFileName(self.llvm(), &mut size); 77 | let s = std::slice::from_raw_parts(s as *const u8, size); 78 | let s = std::str::from_utf8_unchecked(s); 79 | Ok(s) 80 | } 81 | } 82 | 83 | /// Set the module target string 84 | pub fn set_target(&mut self, target: impl AsRef) { 85 | let target = cstr!(target.as_ref()); 86 | unsafe { llvm::core::LLVMSetTarget(self.llvm(), target.as_ptr()) } 87 | } 88 | 89 | /// Get the target string 90 | pub fn target(&self) -> Result<&str, Error> { 91 | unsafe { 92 | let s = llvm::core::LLVMGetTarget(self.llvm()); 93 | let s = std::slice::from_raw_parts(s as *const u8, strlen(s)); 94 | let s = std::str::from_utf8_unchecked(s); 95 | Ok(s) 96 | } 97 | } 98 | 99 | /// Set the module data layout string 100 | pub fn set_data_layout(&mut self, layout: impl AsRef) { 101 | let layout = cstr!(layout.as_ref()); 102 | unsafe { llvm::core::LLVMSetDataLayout(self.llvm(), layout.as_ptr()) } 103 | } 104 | 105 | /// Get data layout string 106 | pub fn data_layout(&self) -> Result<&str, Error> { 107 | unsafe { 108 | let s = llvm::core::LLVMGetDataLayoutStr(self.llvm()); 109 | let s = std::slice::from_raw_parts(s as *const u8, strlen(s)); 110 | let s = std::str::from_utf8_unchecked(s); 111 | Ok(s) 112 | } 113 | } 114 | 115 | /// Set module inline assembly 116 | pub fn set_inline_asm(&mut self, asm: impl AsRef) { 117 | let len = asm.as_ref().len(); 118 | let asm = cstr!(asm.as_ref()); 119 | unsafe { llvm::core::LLVMSetModuleInlineAsm2(self.llvm(), asm.as_ptr(), len) } 120 | } 121 | 122 | /// Append module inline assembly 123 | pub fn append_inline_asm(&mut self, asm: impl AsRef) { 124 | let len = asm.as_ref().len(); 125 | let asm = cstr!(asm.as_ref()); 126 | unsafe { llvm::core::LLVMAppendModuleInlineAsm(self.llvm(), asm.as_ptr(), len) } 127 | } 128 | 129 | /// Get module inline assembly 130 | pub fn inline_asm(&self) -> Result<&str, Error> { 131 | let mut len = 0; 132 | unsafe { 133 | let s = llvm::core::LLVMGetModuleInlineAsm(self.llvm(), &mut len); 134 | let s = std::slice::from_raw_parts(s as *const u8, len); 135 | let s = std::str::from_utf8_unchecked(s); 136 | Ok(s) 137 | } 138 | } 139 | 140 | /// Verify the module, returning an error on failure 141 | pub fn verify(&self) -> Result<(), Error> { 142 | let mut message = std::ptr::null_mut(); 143 | let ok = unsafe { 144 | llvm::analysis::LLVMVerifyModule( 145 | self.llvm(), 146 | llvm::analysis::LLVMVerifierFailureAction::LLVMReturnStatusAction, 147 | &mut message, 148 | ) == 0 149 | }; 150 | 151 | let message = Message::from_raw(message); 152 | 153 | if !ok { 154 | return Err(Error::Message(message)); 155 | } 156 | 157 | Ok(()) 158 | } 159 | 160 | /// Define a new function without declaring a function body 161 | pub fn define_function(&self, name: impl AsRef, t: FuncType) -> Result, Error> { 162 | let name = cstr!(name.as_ref()); 163 | let value = 164 | unsafe { llvm::core::LLVMAddFunction(self.llvm(), name.as_ptr(), t.as_ref().llvm()) }; 165 | let x = Value::from_inner(value)?; 166 | Ok(Func(x)) 167 | } 168 | 169 | /// Declare a new function with function body 170 | pub fn declare_function>, F: FnOnce(Func<'a>) -> Result>( 171 | &self, 172 | builder: &Builder<'a>, 173 | name: impl AsRef, 174 | ft: FuncType, 175 | def: F, 176 | ) -> Result, Error> { 177 | let f = self.define_function(name, ft)?; 178 | builder.function_body(f, |_, _| def(f))?; 179 | Ok(f) 180 | } 181 | 182 | /// Create a new global with an empty initializer 183 | pub fn define_global( 184 | &self, 185 | name: impl AsRef, 186 | ty: impl AsRef>, 187 | ) -> Result, Error> { 188 | let name = cstr!(name.as_ref()); 189 | let value = 190 | unsafe { llvm::core::LLVMAddGlobal(self.llvm(), ty.as_ref().llvm(), name.as_ptr()) }; 191 | Value::from_inner(value) 192 | } 193 | 194 | /// Define a new global in the given address space with an empty initializer 195 | pub fn define_global_in_address_space( 196 | &self, 197 | name: impl AsRef, 198 | ty: impl AsRef>, 199 | addr: usize, 200 | ) -> Result, Error> { 201 | let name = cstr!(name.as_ref()); 202 | let value = unsafe { 203 | llvm::core::LLVMAddGlobalInAddressSpace( 204 | self.llvm(), 205 | ty.as_ref().llvm(), 206 | name.as_ptr(), 207 | addr as c_uint, 208 | ) 209 | }; 210 | Value::from_inner(value) 211 | } 212 | 213 | /// Create a new global with the specified initializer 214 | pub fn declare_global( 215 | &self, 216 | name: impl AsRef, 217 | t: impl AsRef>, 218 | ) -> Result, Error> { 219 | let name = cstr!(name.as_ref()); 220 | let ty = t.as_ref().type_of()?; 221 | let value = 222 | unsafe { llvm::core::LLVMAddGlobal(self.llvm(), ty.as_ref().llvm(), name.as_ptr()) }; 223 | unsafe { 224 | llvm::core::LLVMSetInitializer(value, t.as_ref().llvm()); 225 | } 226 | Value::from_inner(value) 227 | } 228 | 229 | /// Create a new global in the given address space with the specified initializer 230 | pub fn declare_global_in_address_space( 231 | &self, 232 | name: impl AsRef, 233 | t: impl AsRef>, 234 | addr: usize, 235 | ) -> Result, Error> { 236 | let name = cstr!(name.as_ref()); 237 | let ty = t.as_ref().type_of()?; 238 | let value = unsafe { 239 | llvm::core::LLVMAddGlobalInAddressSpace( 240 | self.llvm(), 241 | ty.llvm(), 242 | name.as_ptr(), 243 | addr as c_uint, 244 | ) 245 | }; 246 | unsafe { 247 | llvm::core::LLVMSetInitializer(value, t.as_ref().llvm()); 248 | } 249 | Value::from_inner(value) 250 | } 251 | 252 | /// Get a function by name 253 | pub fn function(&self, name: impl AsRef) -> Result, Error> { 254 | let name = cstr!(name.as_ref()); 255 | let value = unsafe { llvm::core::LLVMGetNamedFunction(self.llvm(), name.as_ptr()) }; 256 | Ok(Func(Value::from_inner(value)?)) 257 | } 258 | 259 | /// Get a global value by name 260 | pub fn global(&self, name: impl AsRef) -> Result, Error> { 261 | let name = cstr!(name.as_ref()); 262 | let value = unsafe { llvm::core::LLVMGetNamedGlobal(self.llvm(), name.as_ptr()) }; 263 | Value::from_inner(value) 264 | } 265 | 266 | /// Get the first global 267 | pub fn first_global(&self) -> Result, Error> { 268 | let value = unsafe { llvm::core::LLVMGetFirstGlobal(self.llvm()) }; 269 | Value::from_inner(value) 270 | } 271 | 272 | /// Get the last global 273 | pub fn last_global(&self) -> Result, Error> { 274 | let value = unsafe { llvm::core::LLVMGetLastGlobal(self.llvm()) }; 275 | Value::from_inner(value) 276 | } 277 | 278 | /// Get the next global 279 | pub fn next_global(&self, global: impl AsRef>) -> Result, Error> { 280 | let value = unsafe { llvm::core::LLVMGetNextGlobal(global.as_ref().llvm()) }; 281 | Value::from_inner(value) 282 | } 283 | 284 | /// Get the first function 285 | pub fn first_function(&self) -> Result, Error> { 286 | let value = unsafe { llvm::core::LLVMGetFirstFunction(self.llvm()) }; 287 | Ok(Func(Value::from_inner(value)?)) 288 | } 289 | 290 | /// Get the last function 291 | pub fn last_function(&self) -> Result, Error> { 292 | let value = unsafe { llvm::core::LLVMGetLastFunction(self.llvm()) }; 293 | Ok(Func(Value::from_inner(value)?)) 294 | } 295 | 296 | /// Create a new module from existing IR 297 | pub fn parse_ir(ctx: &Context, mem_buf: &MemoryBuffer) -> Result, Error> { 298 | let mut module = std::ptr::null_mut(); 299 | let mut message = std::ptr::null_mut(); 300 | let ok = unsafe { 301 | llvm::ir_reader::LLVMParseIRInContext( 302 | ctx.llvm(), 303 | mem_buf.llvm(), 304 | &mut module, 305 | &mut message, 306 | ) == 1 307 | }; 308 | 309 | let message = Message::from_raw(message); 310 | 311 | if !ok { 312 | return Err(Error::Message(message)); 313 | } 314 | 315 | let module = wrap_inner(module)?; 316 | 317 | Ok(Module( 318 | module, 319 | std::sync::atomic::AtomicBool::new(true), 320 | PhantomData, 321 | )) 322 | } 323 | 324 | /// Create a new module from existing bitcode 325 | pub fn parse_bitcode(ctx: &Context, mem_buf: &MemoryBuffer) -> Option> { 326 | let mut module = std::ptr::null_mut(); 327 | let ok = unsafe { 328 | llvm::bit_reader::LLVMParseBitcodeInContext2(ctx.llvm(), mem_buf.llvm(), &mut module) 329 | == 1 330 | }; 331 | 332 | if !ok { 333 | return None; 334 | } 335 | 336 | let module = match wrap_inner(module) { 337 | Ok(m) => m, 338 | Err(_) => return None, 339 | }; 340 | 341 | Some(Module( 342 | module, 343 | std::sync::atomic::AtomicBool::new(true), 344 | PhantomData, 345 | )) 346 | } 347 | 348 | /// Write module bitcode to file 349 | pub fn write_bitcode_to_file(&self, path: impl AsRef) -> Result { 350 | let path = match path.as_ref().to_str() { 351 | Some(p) => cstr!(p), 352 | None => return Err(Error::InvalidPath), 353 | }; 354 | 355 | let r = 356 | unsafe { llvm::bit_writer::LLVMWriteBitcodeToFile(self.llvm(), path.as_ptr()) == 0 }; 357 | 358 | Ok(r) 359 | } 360 | 361 | /// Write module bitcode to in-memory buffer 362 | pub fn write_bitcode_to_memory_buffer(&self) -> Result { 363 | let mem = unsafe { llvm::bit_writer::LLVMWriteBitcodeToMemoryBuffer(self.llvm()) }; 364 | MemoryBuffer::from_raw(mem) 365 | } 366 | 367 | /// Link another module into `self` 368 | pub fn link(&self, other: &Module) -> bool { 369 | unsafe { 370 | let other = llvm::core::LLVMCloneModule(other.llvm()); 371 | llvm::linker::LLVMLinkModules2(self.llvm(), other) == 1 372 | } 373 | } 374 | 375 | /// Set WASM32 target/data layout 376 | pub fn set_wasm32(&mut self) { 377 | self.set_target("wasm32"); 378 | self.set_data_layout("p:32:32:32"); 379 | } 380 | 381 | /// Set target data 382 | pub fn set_target_data(&mut self, target: &TargetData) { 383 | unsafe { llvm::target::LLVMSetModuleDataLayout(self.llvm(), target.llvm()) } 384 | } 385 | 386 | /// Get target data 387 | pub fn target_data(&self) -> Result { 388 | let x = unsafe { llvm::target::LLVMGetModuleDataLayout(self.llvm()) }; 389 | TargetData::from_inner(x) 390 | } 391 | } 392 | 393 | impl<'a> std::fmt::Display for Module<'a> { 394 | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { 395 | let message = 396 | unsafe { Message::from_raw(llvm::core::LLVMPrintModuleToString(self.llvm())) }; 397 | write!(fmt, "{}", message.as_ref()) 398 | } 399 | } 400 | -------------------------------------------------------------------------------- /src/value.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// LLVM Value wrapper 4 | #[derive(Copy)] 5 | pub struct Value<'a>(NonNull, PhantomData<&'a ()>); 6 | 7 | llvm_inner_impl!(Value<'a>, llvm::LLVMValue); 8 | 9 | /// An enumeration of possible Value kinds 10 | pub type ValueKind = llvm::LLVMValueKind; 11 | 12 | /// Attribute placement index 13 | #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 14 | pub enum AttributeIndex { 15 | /// Return attribute 16 | Return, 17 | 18 | /// Param attribute 19 | Param(u32), 20 | 21 | /// Func attribute 22 | Func, 23 | } 24 | 25 | impl AttributeIndex { 26 | pub(crate) fn get_index(self) -> u32 { 27 | match self { 28 | AttributeIndex::Return => llvm::LLVMAttributeReturnIndex, 29 | AttributeIndex::Param(index) => { 30 | assert!( 31 | index <= u32::max_value() - 2, 32 | "Param index must be <= u32::max_value() - 2" 33 | ); 34 | 35 | index + 1 36 | } 37 | AttributeIndex::Func => llvm::LLVMAttributeFunctionIndex, 38 | } 39 | } 40 | } 41 | 42 | impl<'a> AsRef> for Value<'a> { 43 | fn as_ref(&self) -> &Value<'a> { 44 | self 45 | } 46 | } 47 | 48 | impl<'a> Clone for Value<'a> { 49 | fn clone(&self) -> Value<'a> { 50 | Value(self.0, PhantomData) 51 | } 52 | } 53 | 54 | impl<'a> Value<'a> { 55 | /// Wrap an LLVMValue pointer 56 | pub fn from_inner(ptr: *mut llvm::LLVMValue) -> Result, Error> { 57 | let t = wrap_inner(ptr)?; 58 | Ok(Value(t, PhantomData)) 59 | } 60 | 61 | /// Convert from value to metadata 62 | pub fn to_metadata(self) -> Metadata<'a> { 63 | Metadata(self) 64 | } 65 | 66 | /// Returns true if the value is a `BasicBlock` 67 | pub fn is_basic_block(self) -> bool { 68 | unsafe { llvm::core::LLVMValueIsBasicBlock(self.llvm()) == 0 } 69 | } 70 | 71 | /// Get the value kind 72 | pub fn kind(self) -> ValueKind { 73 | unsafe { llvm::core::LLVMGetValueKind(self.llvm()) } 74 | } 75 | 76 | /// Returns true when the value kind matches `kind` 77 | pub fn is(self, kind: ValueKind) -> bool { 78 | self.kind() == kind 79 | } 80 | 81 | /// Get the `Type` of a value 82 | pub fn type_of(self) -> Result, Error> { 83 | let t = unsafe { llvm::core::LLVMTypeOf(self.llvm()) }; 84 | Type::from_inner(t) 85 | } 86 | 87 | pub(crate) fn into_context(self) -> Result, Error> { 88 | self.type_of()?.into_context() 89 | } 90 | 91 | /// Get the context associated with a value 92 | pub fn context(self) -> Result, Error> { 93 | self.type_of()?.into_context() 94 | } 95 | 96 | /// Get the name of a value 97 | pub fn name(self) -> Result<&'a str, Error> { 98 | let mut size = 0; 99 | unsafe { 100 | let s = llvm::core::LLVMGetValueName2(self.llvm(), &mut size); 101 | let s = std::slice::from_raw_parts(s as *const u8, size); 102 | let s = std::str::from_utf8(s)?; 103 | Ok(s) 104 | } 105 | } 106 | 107 | /// Set the name of a value 108 | pub fn set_name(&mut self, name: impl AsRef) { 109 | let len = name.as_ref().len(); 110 | let name = cstr!(name.as_ref()); 111 | unsafe { llvm::core::LLVMSetValueName2(self.llvm(), name.as_ptr(), len) } 112 | } 113 | 114 | /// Replace all uses of a value with another value 115 | pub fn replace_all_uses_with(self, other: impl AsRef>) { 116 | unsafe { llvm::core::LLVMReplaceAllUsesWith(self.llvm(), other.as_ref().llvm()) } 117 | } 118 | 119 | /// Delete a global value 120 | pub fn delete_global(self) { 121 | unsafe { llvm::core::LLVMDeleteGlobal(self.llvm()) } 122 | } 123 | 124 | /// Get value initializer 125 | pub fn initializer(self) -> Result, Error> { 126 | unsafe { Value::from_inner(llvm::core::LLVMGetInitializer(self.llvm())) } 127 | } 128 | 129 | /// Set value initializer 130 | pub fn set_initializer(&mut self, val: Const<'a>) { 131 | unsafe { llvm::core::LLVMSetInitializer(self.llvm(), val.as_ref().llvm()) } 132 | } 133 | 134 | /// Returns true if the value is a global constant 135 | pub fn is_global_constant(self) -> bool { 136 | unsafe { llvm::core::LLVMIsGlobalConstant(self.llvm()) == 1 } 137 | } 138 | 139 | /// Toggle whether or not the value is a global constant 140 | pub fn set_global_constant(&mut self, b: bool) { 141 | unsafe { llvm::core::LLVMSetGlobalConstant(self.llvm(), b as c_int) } 142 | } 143 | 144 | /// Returns true if the value is externally defined 145 | pub fn is_extern(self) -> bool { 146 | unsafe { llvm::core::LLVMIsExternallyInitialized(self.llvm()) == 1 } 147 | } 148 | 149 | /// Toggle whether or not the value is externally declared 150 | pub fn set_extern(&mut self, b: bool) { 151 | unsafe { llvm::core::LLVMSetExternallyInitialized(self.llvm(), if b { 1 } else { 0 }) } 152 | } 153 | 154 | /// Returns true if the value is thread local 155 | pub fn is_thread_local(self) -> bool { 156 | unsafe { llvm::core::LLVMIsThreadLocal(self.llvm()) == 1 } 157 | } 158 | 159 | /// Set whether or not a value is thread local 160 | pub fn set_thread_local(&mut self, b: bool) { 161 | unsafe { llvm::core::LLVMSetThreadLocal(self.llvm(), if b { 1 } else { 0 }) } 162 | } 163 | 164 | /// Returns true when the value is a `Const` 165 | pub fn is_const(self) -> bool { 166 | unsafe { llvm::core::LLVMIsConstant(self.llvm()) == 1 } 167 | } 168 | 169 | /// Convert from value to `Const` 170 | pub fn to_const(self) -> Result, Error> { 171 | if !self.is_const() { 172 | return Err(Error::InvalidConst); 173 | } 174 | 175 | Ok(Const(self)) 176 | } 177 | 178 | /// Convert from value to `BasicBlock` 179 | pub fn to_basic_block(self) -> Result, Error> { 180 | if !self.is_basic_block() { 181 | return Err(Error::InvalidBasicBlock); 182 | } 183 | 184 | let ptr = unsafe { llvm::core::LLVMValueAsBasicBlock(self.llvm()) }; 185 | BasicBlock::from_inner(ptr) 186 | } 187 | 188 | /// Returns true if the value is undefined 189 | pub fn is_undef(self) -> bool { 190 | unsafe { llvm::core::LLVMIsUndef(self.llvm()) == 1 } 191 | } 192 | 193 | /// Returns true if the value is null 194 | pub fn is_null(self) -> bool { 195 | unsafe { llvm::core::LLVMIsNull(self.llvm()) == 1 } 196 | } 197 | 198 | /// Returns true if the value is a constant string 199 | pub fn is_constant_string(self) -> bool { 200 | unsafe { llvm::core::LLVMIsConstantString(self.llvm()) == 1 } 201 | } 202 | } 203 | 204 | impl<'a> std::fmt::Display for Value<'a> { 205 | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { 206 | let message = unsafe { Message::from_raw(llvm::core::LLVMPrintValueToString(self.llvm())) }; 207 | write!(fmt, "{}", message.as_ref()) 208 | } 209 | } 210 | 211 | /// Functions 212 | #[derive(Clone, Copy)] 213 | pub struct Func<'a>(pub Value<'a>); 214 | 215 | impl<'a> AsRef> for Func<'a> { 216 | fn as_ref(&self) -> &Value<'a> { 217 | &self.0 218 | } 219 | } 220 | 221 | impl<'a> From> for Value<'a> { 222 | fn from(x: Func<'a>) -> Value<'a> { 223 | x.0 224 | } 225 | } 226 | 227 | impl<'a> Func<'a> { 228 | /// Get the name of a value 229 | pub fn name(self) -> Result<&'a str, Error> { 230 | self.0.name() 231 | } 232 | 233 | /// Get the number of params 234 | pub fn param_count(self) -> usize { 235 | let n = unsafe { llvm::core::LLVMCountParams(self.as_ref().llvm()) }; 236 | n as usize 237 | } 238 | 239 | /// Get the `FuncType` 240 | pub fn func_type(self) -> Result, Error> { 241 | let t = self.0.type_of()?; 242 | t.to_func_type() 243 | } 244 | 245 | /// Get a single param by index 246 | pub fn param(self, i: usize) -> Result, Error> { 247 | unsafe { Value::from_inner(llvm::core::LLVMGetParam(self.as_ref().llvm(), i as u32)) } 248 | } 249 | 250 | /// Get all params 251 | pub fn params(self) -> Vec> { 252 | let len = self.param_count(); 253 | let mut data = vec![std::ptr::null_mut(); len]; 254 | 255 | unsafe { llvm::core::LLVMGetParams(self.as_ref().llvm(), data.as_mut_ptr()) } 256 | data.into_iter() 257 | .map(|x| Value::from_inner(x).unwrap()) 258 | .collect() 259 | } 260 | 261 | /// Verify the function, returning an error on failure 262 | pub fn verify(self) -> Result<(), Error> { 263 | let ok = unsafe { 264 | llvm::analysis::LLVMVerifyFunction( 265 | self.as_ref().llvm(), 266 | llvm::analysis::LLVMVerifierFailureAction::LLVMPrintMessageAction, 267 | ) == 0 268 | }; 269 | 270 | if !ok { 271 | return Err(Error::InvalidFunction); 272 | } 273 | 274 | Ok(()) 275 | } 276 | 277 | /// Get the next function 278 | pub fn next_function(self) -> Result, Error> { 279 | let v = unsafe { llvm::core::LLVMGetNextFunction(self.as_ref().llvm()) }; 280 | Value::from_inner(v).map(Func) 281 | } 282 | 283 | /// Get the previous function 284 | pub fn prev_function(self) -> Result, Error> { 285 | let v = unsafe { llvm::core::LLVMGetPreviousFunction(self.as_ref().llvm()) }; 286 | Value::from_inner(v).map(Func) 287 | } 288 | 289 | /// Delete a function 290 | pub fn delete(self) { 291 | unsafe { llvm::core::LLVMDeleteFunction(self.as_ref().llvm()) } 292 | } 293 | 294 | /// Returns true when the value has a `personality_fn` 295 | pub fn has_personality_fn(self) -> bool { 296 | unsafe { llvm::core::LLVMHasPersonalityFn(self.as_ref().llvm()) == 1 } 297 | } 298 | 299 | /// Returns the `personality_fn` 300 | pub fn personality_fn(self) -> Result, Error> { 301 | unsafe { Value::from_inner(llvm::core::LLVMGetPersonalityFn(self.as_ref().llvm())) } 302 | } 303 | 304 | /// Set the `personality_fn` 305 | pub fn set_personality_fn(&mut self, f: impl AsRef>) { 306 | unsafe { llvm::core::LLVMSetPersonalityFn(self.as_ref().llvm(), f.as_ref().llvm()) } 307 | } 308 | 309 | /// Get garbage collection scheme name 310 | pub fn gc(self) -> Option<&'a str> { 311 | let gc = unsafe { llvm::core::LLVMGetGC(self.as_ref().llvm()) }; 312 | if gc.is_null() { 313 | return None; 314 | } 315 | 316 | unsafe { 317 | let slice = std::slice::from_raw_parts(gc as *const u8, strlen(gc)); 318 | Some(std::str::from_utf8_unchecked(slice)) 319 | } 320 | } 321 | 322 | /// Set garbage collection scheme name 323 | pub fn set_gc(&mut self, name: impl AsRef) { 324 | let name = cstr!(name.as_ref()); 325 | unsafe { llvm::core::LLVMSetGC(self.as_ref().llvm(), name.as_ptr()) } 326 | } 327 | 328 | /// Get calling convention 329 | pub fn call_conv(self) -> CallConv { 330 | unsafe { std::mem::transmute(llvm::core::LLVMGetFunctionCallConv(self.as_ref().llvm())) } 331 | } 332 | 333 | /// Set calling convention 334 | pub fn set_call_conv(&mut self, conv: CallConv) { 335 | unsafe { llvm::core::LLVMSetFunctionCallConv(self.as_ref().llvm(), conv as u32) } 336 | } 337 | 338 | /// Set attribute 339 | pub fn add_attribute(&mut self, index: AttributeIndex, attr: &Attribute<'a>) { 340 | unsafe { 341 | llvm::core::LLVMAddAttributeAtIndex( 342 | self.as_ref().llvm(), 343 | index.get_index(), 344 | attr.llvm(), 345 | ) 346 | } 347 | } 348 | 349 | /// Remove an enum attribute 350 | pub fn remove_enum_atribute(&mut self, index: AttributeIndex, kind_id: u32) { 351 | unsafe { 352 | llvm::core::LLVMRemoveEnumAttributeAtIndex( 353 | self.as_ref().llvm(), 354 | index.get_index(), 355 | kind_id, 356 | ) 357 | } 358 | } 359 | 360 | /// Remove a string attribute 361 | pub fn remove_string_atribute(&mut self, index: AttributeIndex, k: impl AsRef) { 362 | let len = k.as_ref().len(); 363 | let k = cstr!(k.as_ref()); 364 | unsafe { 365 | llvm::core::LLVMRemoveStringAttributeAtIndex( 366 | self.as_ref().llvm(), 367 | index.get_index(), 368 | k.as_ptr(), 369 | len as u32, 370 | ) 371 | } 372 | } 373 | 374 | /// Get all attributes 375 | pub fn attributes(self, index: usize) -> Vec> { 376 | let count = unsafe { 377 | llvm::core::LLVMGetAttributeCountAtIndex(self.as_ref().llvm(), index as c_uint) 378 | }; 379 | 380 | let mut output = vec![std::ptr::null_mut(); count as usize]; 381 | 382 | unsafe { 383 | llvm::core::LLVMGetAttributesAtIndex( 384 | self.as_ref().llvm(), 385 | index as c_uint, 386 | output.as_mut_ptr(), 387 | ); 388 | } 389 | 390 | output 391 | .into_iter() 392 | .map(|x| Attribute::from_inner(x).unwrap()) 393 | .collect() 394 | } 395 | 396 | /// Create specified uniqued inline asm string (intel syntax) 397 | pub fn inline_asm_intel( 398 | t: impl AsRef>, 399 | s: impl AsRef, 400 | constraints: impl AsRef, 401 | has_side_effects: bool, 402 | is_align_stack: bool, 403 | can_throw: bool, 404 | ) -> Result, Error> { 405 | unsafe { 406 | Value::from_inner(llvm::core::LLVMGetInlineAsm( 407 | t.as_ref().llvm(), 408 | s.as_ref().as_ptr() as *mut c_char, 409 | s.as_ref().len(), 410 | constraints.as_ref().as_ptr() as *mut c_char, 411 | constraints.as_ref().len(), 412 | has_side_effects as c_int, 413 | is_align_stack as c_int, 414 | llvm::LLVMInlineAsmDialect::LLVMInlineAsmDialectIntel, 415 | can_throw as c_int, 416 | )) 417 | } 418 | } 419 | 420 | /// Create specified uniqued inline asm string (att syntax) 421 | pub fn inline_asm_att( 422 | t: impl AsRef>, 423 | s: impl AsRef, 424 | constraints: impl AsRef, 425 | has_side_effects: bool, 426 | is_align_stack: bool, 427 | can_throw: bool, 428 | ) -> Result, Error> { 429 | unsafe { 430 | Value::from_inner(llvm::core::LLVMGetInlineAsm( 431 | t.as_ref().llvm(), 432 | s.as_ref().as_ptr() as *mut c_char, 433 | s.as_ref().len(), 434 | constraints.as_ref().as_ptr() as *mut c_char, 435 | constraints.as_ref().len(), 436 | has_side_effects as c_int, 437 | is_align_stack as c_int, 438 | llvm::LLVMInlineAsmDialect::LLVMInlineAsmDialectATT, 439 | can_throw as c_int, 440 | )) 441 | } 442 | } 443 | 444 | /// Get value alignment 445 | pub fn alignment(self) -> usize { 446 | unsafe { llvm::core::LLVMGetAlignment(self.as_ref().llvm()) as usize } 447 | } 448 | 449 | /// Set value alignment 450 | pub fn set_alignment(&mut self, align: usize) { 451 | unsafe { llvm::core::LLVMSetAlignment(self.as_ref().llvm(), align as u32) } 452 | } 453 | 454 | /// Get global linkage 455 | pub fn global_linkage(self) -> Linkage { 456 | unsafe { llvm::core::LLVMGetLinkage(self.as_ref().llvm()) } 457 | } 458 | 459 | /// Set global linkage 460 | pub fn set_global_linkage(&mut self, l: Linkage) { 461 | unsafe { llvm::core::LLVMSetLinkage(self.as_ref().llvm(), l) } 462 | } 463 | 464 | /// Get global visibility 465 | pub fn global_visibility(self) -> Visibility { 466 | unsafe { llvm::core::LLVMGetVisibility(self.as_ref().llvm()) } 467 | } 468 | 469 | /// Set global visibility 470 | pub fn set_global_visibility(&mut self, l: Visibility) { 471 | unsafe { llvm::core::LLVMSetVisibility(self.as_ref().llvm(), l) } 472 | } 473 | 474 | /// Count the number of basic blocks 475 | pub fn count_basic_blocks(self) -> usize { 476 | unsafe { llvm::core::LLVMCountBasicBlocks(self.0.llvm()) as usize } 477 | } 478 | 479 | /// Get a list of all basic blocks 480 | pub fn basic_blocks(self) -> Vec> { 481 | let count = self.count_basic_blocks(); 482 | let ptr = std::ptr::null_mut(); 483 | unsafe { llvm::core::LLVMGetBasicBlocks(self.0.llvm(), ptr) } 484 | let slice = unsafe { std::slice::from_raw_parts(ptr, count) }; 485 | slice 486 | .iter() 487 | .map(|x| BasicBlock::from_inner(*x).unwrap()) 488 | .collect() 489 | } 490 | 491 | /// Get first basic block 492 | pub fn first_basic_block(self) -> Result, Error> { 493 | BasicBlock::from_inner(unsafe { llvm::core::LLVMGetFirstBasicBlock(self.0.llvm()) }) 494 | } 495 | 496 | /// Get last basic block 497 | pub fn last_basic_block(self) -> Result, Error> { 498 | BasicBlock::from_inner(unsafe { llvm::core::LLVMGetLastBasicBlock(self.0.llvm()) }) 499 | } 500 | 501 | /// Get entry block 502 | pub fn entry_basic_block(self) -> Result, Error> { 503 | BasicBlock::from_inner(unsafe { llvm::core::LLVMGetEntryBasicBlock(self.0.llvm()) }) 504 | } 505 | 506 | /// Append a new block 507 | pub fn append_basic_block(self, bb: BasicBlock<'a>) { 508 | unsafe { llvm::core::LLVMAppendExistingBasicBlock(self.0.llvm(), bb.llvm()) } 509 | } 510 | } 511 | -------------------------------------------------------------------------------- /src/type.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | /// LLVMType wrapper 4 | #[derive(Copy)] 5 | pub struct Type<'a>(NonNull, PhantomData<&'a ()>); 6 | 7 | llvm_inner_impl!(Type<'a>, llvm::LLVMType); 8 | 9 | /// Enumerates all possible kinds of types 10 | pub type TypeKind = llvm::LLVMTypeKind; 11 | 12 | /// Function type 13 | #[derive(Clone, Copy)] 14 | pub struct FuncType<'a>(pub(crate) Type<'a>); 15 | 16 | impl<'a> Clone for Type<'a> { 17 | fn clone(&self) -> Type<'a> { 18 | Type(self.0, PhantomData) 19 | } 20 | } 21 | 22 | impl<'a> AsRef> for Type<'a> { 23 | fn as_ref(&self) -> &Type<'a> { 24 | self 25 | } 26 | } 27 | 28 | impl<'a> AsRef> for FuncType<'a> { 29 | fn as_ref(&self) -> &Type<'a> { 30 | &self.0 31 | } 32 | } 33 | 34 | impl<'a> From> for Type<'a> { 35 | fn from(x: FuncType<'a>) -> Type<'a> { 36 | x.0 37 | } 38 | } 39 | 40 | /// Struct type 41 | #[derive(Clone, Copy)] 42 | pub struct StructType<'a>(pub(crate) Type<'a>); 43 | 44 | impl<'a> AsRef> for StructType<'a> { 45 | fn as_ref(&self) -> &Type<'a> { 46 | &self.0 47 | } 48 | } 49 | 50 | impl<'a> From> for Type<'a> { 51 | fn from(x: StructType<'a>) -> Type<'a> { 52 | x.0 53 | } 54 | } 55 | 56 | pub trait LLVMType<'a> { 57 | fn llvm_type(ctx: &Context<'a>) -> Result, Error>; 58 | } 59 | 60 | impl<'a> Type<'a> { 61 | /// Wrap an LLVMType pointer 62 | pub fn from_inner(ptr: *mut llvm::LLVMType) -> Result, Error> { 63 | let t = wrap_inner(ptr)?; 64 | Ok(Type(t, PhantomData)) 65 | } 66 | 67 | /// Allows for conversion between Rust/LLVM types 68 | pub fn of>(ctx: &Context<'a>) -> Result, Error> { 69 | T::llvm_type(ctx) 70 | } 71 | 72 | /// Get type by name 73 | pub fn by_name(ctx: &'a Context, name: impl AsRef) -> Result, Error> { 74 | ctx.type_by_name(name) 75 | } 76 | 77 | /// Get width of integer type 78 | pub fn int_width(self) -> usize { 79 | unsafe { llvm::core::LLVMGetIntTypeWidth(self.llvm()) as usize } 80 | } 81 | 82 | /// Get associated context 83 | pub fn context(self) -> Result, Error> { 84 | let ctx = unsafe { wrap_inner(llvm::core::LLVMGetTypeContext(self.llvm()))? }; 85 | Ok(Context(ctx, false, PhantomData)) 86 | } 87 | 88 | pub(crate) fn into_context(self) -> Result, Error> { 89 | let ctx = unsafe { wrap_inner(llvm::core::LLVMGetTypeContext(self.llvm()))? }; 90 | Ok(Context(ctx, false, PhantomData)) 91 | } 92 | 93 | /// Create int type 94 | pub fn int(ctx: &Context<'a>, bits: usize) -> Result, Error> { 95 | unsafe { 96 | Self::from_inner(llvm::core::LLVMIntTypeInContext( 97 | ctx.llvm(), 98 | bits as std::os::raw::c_uint, 99 | )) 100 | } 101 | } 102 | 103 | /// Create i64 type 104 | pub fn i64(ctx: &Context<'a>) -> Result, Error> { 105 | Self::int(ctx, 64) 106 | } 107 | 108 | /// Create i32 type 109 | pub fn i32(ctx: &Context<'a>) -> Result, Error> { 110 | Self::int(ctx, 32) 111 | } 112 | 113 | /// Create i16 type 114 | pub fn i16(ctx: &Context<'a>) -> Result, Error> { 115 | Self::int(ctx, 16) 116 | } 117 | 118 | /// Create i8 type 119 | pub fn i8(ctx: &Context<'a>) -> Result, Error> { 120 | Self::int(ctx, 8) 121 | } 122 | 123 | /// Create i1 type 124 | pub fn i1(ctx: &Context<'a>) -> Result, Error> { 125 | Self::int(ctx, 1) 126 | } 127 | 128 | /// Returns true if the types kind matches `kind` 129 | pub fn is(self, kind: TypeKind) -> bool { 130 | self.kind() == kind 131 | } 132 | 133 | /// Create void type 134 | pub fn void(ctx: &Context<'a>) -> Result, Error> { 135 | unsafe { Self::from_inner(llvm::core::LLVMVoidTypeInContext(ctx.llvm())) } 136 | } 137 | 138 | /// Create label type 139 | pub fn label(ctx: &Context<'a>) -> Result, Error> { 140 | unsafe { Self::from_inner(llvm::core::LLVMLabelTypeInContext(ctx.llvm())) } 141 | } 142 | 143 | /// Create token type 144 | pub fn token(ctx: &Context<'a>) -> Result, Error> { 145 | unsafe { Self::from_inner(llvm::core::LLVMTokenTypeInContext(ctx.llvm())) } 146 | } 147 | 148 | /// Create metadata type 149 | pub fn metadata(ctx: &Context<'a>) -> Result, Error> { 150 | unsafe { Self::from_inner(llvm::core::LLVMMetadataTypeInContext(ctx.llvm())) } 151 | } 152 | 153 | /// Create x86MMX type 154 | pub fn x86_mmx(ctx: &Context<'a>) -> Result, Error> { 155 | unsafe { Self::from_inner(llvm::core::LLVMX86MMXTypeInContext(ctx.llvm())) } 156 | } 157 | 158 | /// Create half/float16 type 159 | pub fn half(ctx: &Context<'a>) -> Result, Error> { 160 | unsafe { Self::from_inner(llvm::core::LLVMHalfTypeInContext(ctx.llvm())) } 161 | } 162 | 163 | /// Create float type 164 | pub fn float(ctx: &Context<'a>) -> Result, Error> { 165 | unsafe { Self::from_inner(llvm::core::LLVMFloatTypeInContext(ctx.llvm())) } 166 | } 167 | 168 | /// Create double type 169 | pub fn double(ctx: &Context<'a>) -> Result, Error> { 170 | unsafe { Self::from_inner(llvm::core::LLVMDoubleTypeInContext(ctx.llvm())) } 171 | } 172 | 173 | /// Create FP128 type 174 | pub fn fp128(ctx: &Context<'a>) -> Result, Error> { 175 | unsafe { Self::from_inner(llvm::core::LLVMFP128TypeInContext(ctx.llvm())) } 176 | } 177 | 178 | /// Get type of element 179 | pub fn element_type(self) -> Result, Error> { 180 | let t = unsafe { llvm::core::LLVMGetElementType(self.llvm()) }; 181 | Self::from_inner(t) 182 | } 183 | 184 | /// Convert to function type 185 | pub fn to_func_type(self) -> Result, Error> { 186 | if self.is(TypeKind::LLVMPointerTypeKind) { 187 | return self.element_type()?.to_func_type(); 188 | } 189 | 190 | if !self.is(TypeKind::LLVMFunctionTypeKind) { 191 | return Err(Error::InvalidType); 192 | } 193 | 194 | Ok(FuncType(self)) 195 | } 196 | 197 | /// Convert to struct type 198 | pub fn to_struct_type(self) -> Result, Error> { 199 | if self.is(TypeKind::LLVMPointerTypeKind) { 200 | return self.element_type()?.to_struct_type(); 201 | } 202 | 203 | if !self.is(TypeKind::LLVMStructTypeKind) { 204 | return Err(Error::InvalidType); 205 | } 206 | 207 | Ok(StructType(self)) 208 | } 209 | 210 | /// Make pointer type 211 | pub fn pointer(self, address_space: Option) -> Result, Error> { 212 | let address_space = address_space.unwrap_or(0) as c_uint; 213 | unsafe { Self::from_inner(llvm::core::LLVMPointerType(self.llvm(), address_space)) } 214 | } 215 | 216 | /// Make vector type 217 | pub fn vector(self, count: usize) -> Result, Error> { 218 | unsafe { Self::from_inner(llvm::core::LLVMVectorType(self.llvm(), count as c_uint)) } 219 | } 220 | 221 | /// Make array type 222 | pub fn array(self, count: usize) -> Result, Error> { 223 | unsafe { Self::from_inner(llvm::core::LLVMArrayType(self.llvm(), count as c_uint)) } 224 | } 225 | 226 | /// Get type kind 227 | pub fn kind(self) -> TypeKind { 228 | unsafe { llvm::core::LLVMGetTypeKind(self.llvm()) } 229 | } 230 | 231 | /// Returns true if a type is sized 232 | pub fn is_sized(self) -> bool { 233 | unsafe { llvm::core::LLVMTypeIsSized(self.llvm()) == 1 } 234 | } 235 | 236 | /// Get array length 237 | pub fn array_len(self) -> usize { 238 | unsafe { llvm::core::LLVMGetArrayLength(self.llvm()) as usize } 239 | } 240 | 241 | /// Get vector length 242 | pub fn vector_len(self) -> usize { 243 | unsafe { llvm::core::LLVMGetArrayLength(self.llvm()) as usize } 244 | } 245 | 246 | /// Get pointer address space 247 | pub fn pointer_address_space(self) -> usize { 248 | unsafe { llvm::core::LLVMGetArrayLength(self.llvm()) as usize } 249 | } 250 | 251 | /// Get alignment of type 252 | pub fn align_of(self) -> Result, Error> { 253 | unsafe { Value::from_inner(llvm::core::LLVMAlignOf(self.llvm())) } 254 | } 255 | 256 | /// Get size of type 257 | pub fn size_of(self) -> Result, Error> { 258 | unsafe { Value::from_inner(llvm::core::LLVMSizeOf(self.llvm())) } 259 | } 260 | } 261 | 262 | impl<'a> FuncType<'a> { 263 | /// Create a new function type with the given return type and parameter types 264 | pub fn new( 265 | return_type: impl AsRef>, 266 | params: impl AsRef<[Type<'a>]>, 267 | ) -> Result, Error> { 268 | let mut params: Vec<*mut llvm::LLVMType> = 269 | params.as_ref().iter().map(|x| x.llvm()).collect(); 270 | let len = params.len(); 271 | let t = unsafe { 272 | llvm::core::LLVMFunctionType( 273 | return_type.as_ref().llvm(), 274 | params.as_mut_ptr(), 275 | len as u32, 276 | 0, 277 | ) 278 | }; 279 | let x = Type::from_inner(t)?; 280 | x.to_func_type() 281 | } 282 | 283 | /// Create a new var arg function type with the given return type and parameter types 284 | pub fn new_var_arg( 285 | return_type: impl AsRef>, 286 | params: impl AsRef<[Type<'a>]>, 287 | ) -> Result, Error> { 288 | let mut params: Vec<*mut llvm::LLVMType> = 289 | params.as_ref().iter().map(|x| x.llvm()).collect(); 290 | let len = params.len(); 291 | let t = unsafe { 292 | llvm::core::LLVMFunctionType( 293 | return_type.as_ref().llvm(), 294 | params.as_mut_ptr(), 295 | len as u32, 296 | 1, 297 | ) 298 | }; 299 | let x = Type::from_inner(t)?; 300 | x.to_func_type() 301 | } 302 | 303 | /// Returns true if the function type has a variable number of arguments 304 | pub fn is_var_arg(self) -> bool { 305 | unsafe { llvm::core::LLVMIsFunctionVarArg(self.as_ref().llvm()) == 1 } 306 | } 307 | 308 | /// Get the return type 309 | pub fn return_type(self) -> Result, Error> { 310 | let t = unsafe { llvm::core::LLVMGetReturnType(self.as_ref().llvm()) }; 311 | Type::from_inner(t) 312 | } 313 | 314 | /// Get the number of parameters 315 | pub fn param_count(self) -> usize { 316 | let n = unsafe { llvm::core::LLVMCountParamTypes(self.as_ref().llvm()) }; 317 | n as usize 318 | } 319 | 320 | /// Get all parameter types 321 | pub fn params(self) -> Vec> { 322 | let len = self.param_count(); 323 | let mut data = vec![std::ptr::null_mut(); len]; 324 | 325 | unsafe { llvm::core::LLVMGetParamTypes(self.as_ref().llvm(), data.as_mut_ptr()) } 326 | data.into_iter() 327 | .map(|x| Type::from_inner(x).unwrap()) 328 | .collect() 329 | } 330 | } 331 | 332 | impl<'a> StructType<'a> { 333 | /// Create a new struct with the given fields 334 | pub fn new(ctx: &Context<'a>, fields: impl AsRef<[Type<'a>]>) -> Result, Error> { 335 | let mut fields: Vec<*mut llvm::LLVMType> = 336 | fields.as_ref().iter().map(|x| x.llvm()).collect(); 337 | let len = fields.len(); 338 | let t = unsafe { 339 | llvm::core::LLVMStructTypeInContext(ctx.llvm(), fields.as_mut_ptr(), len as u32, 0) 340 | }; 341 | Type::from_inner(t)?.to_struct_type() 342 | } 343 | 344 | /// Create a new packed struct with the given fields 345 | pub fn new_packed( 346 | ctx: &Context<'a>, 347 | fields: impl AsRef<[Type<'a>]>, 348 | ) -> Result, Error> { 349 | let mut fields: Vec<*mut llvm::LLVMType> = 350 | fields.as_ref().iter().map(|x| x.llvm()).collect(); 351 | let len = fields.len(); 352 | let t = unsafe { 353 | llvm::core::LLVMStructTypeInContext(ctx.llvm(), fields.as_mut_ptr(), len as u32, 1) 354 | }; 355 | Type::from_inner(t)?.to_struct_type() 356 | } 357 | 358 | /// Create a new named struct 359 | pub fn new_with_name( 360 | ctx: &Context<'a>, 361 | name: impl AsRef, 362 | ) -> Result, Error> { 363 | let name = cstr!(name.as_ref()); 364 | let t = unsafe { llvm::core::LLVMStructCreateNamed(ctx.llvm(), name.as_ptr()) }; 365 | Type::from_inner(t)?.to_struct_type() 366 | } 367 | 368 | /// Get struct name 369 | pub fn name(self) -> Result, Error> { 370 | unsafe { 371 | let s = llvm::core::LLVMGetStructName(self.as_ref().llvm()); 372 | if s.is_null() { 373 | return Ok(None); 374 | } 375 | let s = std::slice::from_raw_parts(s as *const u8, strlen(s)); 376 | let s = std::str::from_utf8(s)?; 377 | Ok(Some(s)) 378 | } 379 | } 380 | 381 | /// Set named struct body 382 | pub fn set_body(&mut self, fields: impl AsRef<[Type<'a>]>) { 383 | let mut fields: Vec<*mut llvm::LLVMType> = 384 | fields.as_ref().iter().map(|x| x.llvm()).collect(); 385 | let len = fields.len(); 386 | unsafe { 387 | llvm::core::LLVMStructSetBody(self.as_ref().llvm(), fields.as_mut_ptr(), len as u32, 0) 388 | }; 389 | } 390 | 391 | /// Set packed, named struct's body 392 | pub fn set_body_packed(&mut self, fields: impl AsRef<[Type<'a>]>) { 393 | let mut fields: Vec<*mut llvm::LLVMType> = 394 | fields.as_ref().iter().map(|x| x.llvm()).collect(); 395 | let len = fields.len(); 396 | unsafe { 397 | llvm::core::LLVMStructSetBody(self.as_ref().llvm(), fields.as_mut_ptr(), len as u32, 1) 398 | }; 399 | } 400 | 401 | /// Get number of fields 402 | pub fn field_count(self) -> usize { 403 | let n = unsafe { llvm::core::LLVMCountStructElementTypes(self.as_ref().llvm()) }; 404 | n as usize 405 | } 406 | 407 | /// Get all fields 408 | pub fn fields(self) -> Vec> { 409 | let len = self.field_count(); 410 | let mut ptr = std::ptr::null_mut(); 411 | 412 | unsafe { llvm::core::LLVMGetStructElementTypes(self.as_ref().llvm(), &mut ptr) } 413 | let slice = unsafe { std::slice::from_raw_parts_mut(ptr, len) }; 414 | slice 415 | .iter_mut() 416 | .map(|x| Type::from_inner(x).unwrap()) 417 | .collect() 418 | } 419 | 420 | /// Get a single field by index 421 | pub fn field(self, index: usize) -> Result, Error> { 422 | let t = 423 | unsafe { llvm::core::LLVMStructGetTypeAtIndex(self.as_ref().llvm(), index as c_uint) }; 424 | 425 | Type::from_inner(t) 426 | } 427 | 428 | /// Returns true if the struct is packed 429 | pub fn is_packed(self) -> bool { 430 | unsafe { llvm::core::LLVMIsPackedStruct(self.as_ref().llvm()) == 1 } 431 | } 432 | 433 | /// Returns true if the struct is an opaque type 434 | pub fn is_opaque(self) -> bool { 435 | unsafe { llvm::core::LLVMIsOpaqueStruct(self.as_ref().llvm()) == 1 } 436 | } 437 | 438 | /// Returns true if the struct is a literal 439 | pub fn is_literal(self) -> bool { 440 | unsafe { llvm::core::LLVMIsLiteralStruct(self.as_ref().llvm()) == 1 } 441 | } 442 | } 443 | 444 | impl<'a> std::fmt::Display for Type<'a> { 445 | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result { 446 | unsafe { 447 | let s = Message::from_raw(llvm::core::LLVMPrintTypeToString(self.llvm())); 448 | write!(fmt, "{}", s.as_ref()) 449 | } 450 | } 451 | } 452 | 453 | impl<'a> LLVMType<'a> for u8 { 454 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 455 | Type::int(ctx, 8) 456 | } 457 | } 458 | 459 | impl<'a> LLVMType<'a> for i8 { 460 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 461 | Type::int(ctx, 8) 462 | } 463 | } 464 | 465 | impl<'a> LLVMType<'a> for u16 { 466 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 467 | Type::int(ctx, 16) 468 | } 469 | } 470 | 471 | impl<'a> LLVMType<'a> for i16 { 472 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 473 | Type::int(ctx, 16) 474 | } 475 | } 476 | 477 | impl<'a> LLVMType<'a> for u32 { 478 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 479 | Type::int(ctx, 32) 480 | } 481 | } 482 | 483 | impl<'a> LLVMType<'a> for i32 { 484 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 485 | Type::int(ctx, 32) 486 | } 487 | } 488 | 489 | impl<'a> LLVMType<'a> for u64 { 490 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 491 | Type::int(ctx, 64) 492 | } 493 | } 494 | 495 | impl<'a> LLVMType<'a> for i64 { 496 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 497 | Type::int(ctx, 64) 498 | } 499 | } 500 | 501 | impl<'a> LLVMType<'a> for u128 { 502 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 503 | Type::int(ctx, 128) 504 | } 505 | } 506 | 507 | impl<'a> LLVMType<'a> for i128 { 508 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 509 | Type::int(ctx, 128) 510 | } 511 | } 512 | 513 | impl<'a> LLVMType<'a> for f32 { 514 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 515 | Type::float(ctx) 516 | } 517 | } 518 | 519 | impl<'a> LLVMType<'a> for f64 { 520 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 521 | Type::double(ctx) 522 | } 523 | } 524 | 525 | impl<'a> LLVMType<'a> for () { 526 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 527 | Type::void(ctx) 528 | } 529 | } 530 | 531 | impl<'a, T: LLVMType<'a>> LLVMType<'a> for *const T { 532 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 533 | T::llvm_type(ctx)?.pointer(None) 534 | } 535 | } 536 | 537 | impl<'a, T: LLVMType<'a>> LLVMType<'a> for *mut T { 538 | fn llvm_type(ctx: &Context<'a>) -> Result, Error> { 539 | T::llvm_type(ctx)?.pointer(None) 540 | } 541 | } 542 | -------------------------------------------------------------------------------- /src/const.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | use crate::*; 4 | 5 | /// Constant values 6 | #[derive(Clone, Copy)] 7 | pub struct Const<'a>(pub(crate) Value<'a>); 8 | 9 | impl<'a> AsRef> for Const<'a> { 10 | fn as_ref(&self) -> &Value<'a> { 11 | &self.0 12 | } 13 | } 14 | 15 | impl<'a> From> for Value<'a> { 16 | fn from(x: Const<'a>) -> Value<'a> { 17 | x.0 18 | } 19 | } 20 | 21 | impl<'a> Const<'a> { 22 | const_func!(int(t: impl AsRef>, i: i64) { 23 | llvm::core::LLVMConstInt( 24 | t.as_ref().llvm(), 25 | i as u64, 26 | 0 27 | ) 28 | }); 29 | 30 | const_func!(int_sext(t: impl AsRef>, i: i64) { 31 | llvm::core::LLVMConstInt( 32 | t.as_ref().llvm(), 33 | i as u64, 34 | 1 35 | ) 36 | }); 37 | 38 | const_func!(int_s( 39 | t: impl AsRef>, 40 | i: impl AsRef, 41 | radix: u8, 42 | ) { 43 | let s = cstr!(i.as_ref()); 44 | llvm::core::LLVMConstIntOfString( 45 | t.as_ref().llvm(), 46 | s.as_ptr(), 47 | radix, 48 | ) 49 | }); 50 | 51 | const_func!(real(t: impl AsRef>, i: f64) { 52 | llvm::core::LLVMConstReal(t.as_ref().llvm(), i as f64) 53 | }); 54 | 55 | const_func!(real_s( 56 | t: impl AsRef>, 57 | i: impl AsRef, 58 | ) { 59 | let s = cstr!(i.as_ref()); 60 | llvm::core::LLVMConstRealOfString( 61 | t.as_ref().llvm(), 62 | s.as_ptr(), 63 | ) 64 | }); 65 | 66 | const_func!(undef(t: impl AsRef>) { 67 | llvm::core::LLVMGetUndef(t.as_ref().llvm()) 68 | }); 69 | 70 | const_func!(pointer_null(t: impl AsRef>){ 71 | llvm::core::LLVMConstPointerNull(t.as_ref().llvm()) 72 | }); 73 | 74 | const_func!(null(t: impl AsRef>){ 75 | llvm::core::LLVMConstNull(t.as_ref().llvm()) 76 | }); 77 | 78 | const_func!(all_ones(t: impl AsRef>){ 79 | llvm::core::LLVMConstAllOnes(t.as_ref().llvm()) 80 | }); 81 | 82 | const_func!(string( 83 | ctx: &Context<'a>, 84 | s: impl AsRef, 85 | ) { 86 | let len = s.as_ref().len(); 87 | let s = cstr!(s.as_ref()); 88 | llvm::core::LLVMConstStringInContext( 89 | ctx.llvm(), 90 | s.as_ptr(), 91 | len as c_uint, 92 | 0 93 | ) 94 | }); 95 | 96 | const_func!(string_no_null( 97 | ctx: &Context<'a>, 98 | s: impl AsRef, 99 | ) { 100 | let len = s.as_ref().len(); 101 | let s = cstr!(s.as_ref()); 102 | llvm::core::LLVMConstStringInContext( 103 | ctx.llvm(), 104 | s.as_ptr(), 105 | len as c_uint, 106 | 1 107 | ) 108 | }); 109 | 110 | pub fn get_unsigned_int(self) -> Option { 111 | if !self.as_ref().is(ValueKind::LLVMConstantIntValueKind) { 112 | return None; 113 | } 114 | 115 | unsafe { Some(llvm::core::LLVMConstIntGetZExtValue(self.as_ref().llvm())) } 116 | } 117 | 118 | pub fn get_signed_int(self) -> Option { 119 | if !self.as_ref().is(ValueKind::LLVMConstantIntValueKind) { 120 | return None; 121 | } 122 | 123 | unsafe { Some(llvm::core::LLVMConstIntGetSExtValue(self.as_ref().llvm())) } 124 | } 125 | 126 | pub fn get_double(self) -> Option { 127 | if !self.as_ref().is(ValueKind::LLVMConstantFPValueKind) { 128 | return None; 129 | } 130 | 131 | let mut _l = 0; 132 | unsafe { 133 | Some(llvm::core::LLVMConstRealGetDouble( 134 | self.as_ref().llvm(), 135 | &mut _l, 136 | )) 137 | } 138 | } 139 | 140 | pub fn get_string(self) -> Option<&'a str> { 141 | let mut size = 0; 142 | unsafe { 143 | let s = llvm::core::LLVMGetAsString(self.as_ref().llvm(), &mut size); 144 | let s = std::slice::from_raw_parts(s as *const u8, strlen(s)); 145 | match std::str::from_utf8(s) { 146 | Ok(x) => Some(x), 147 | Err(_) => None, 148 | } 149 | } 150 | } 151 | 152 | const_func!(get_element(&self, index: usize) { 153 | llvm::core::LLVMGetElementAsConstant(self.as_ref().llvm(), index as c_uint) 154 | }); 155 | 156 | pub fn crate_struct( 157 | ctx: &Context<'a>, 158 | vals: impl AsRef<[Value<'a>]>, 159 | ) -> Result, Error> { 160 | let len = vals.as_ref().len(); 161 | let mut vals: Vec<*mut llvm::LLVMValue> = vals.as_ref().iter().map(|x| x.llvm()).collect(); 162 | let v = unsafe { 163 | llvm::core::LLVMConstStructInContext(ctx.llvm(), vals.as_mut_ptr(), len as c_uint, 0) 164 | }; 165 | Value::from_inner(v)?.to_const() 166 | } 167 | 168 | pub fn crate_packed_struct( 169 | ctx: &Context<'a>, 170 | vals: impl AsRef<[Value<'a>]>, 171 | ) -> Result, Error> { 172 | let len = vals.as_ref().len(); 173 | let mut vals: Vec<*mut llvm::LLVMValue> = vals.as_ref().iter().map(|x| x.llvm()).collect(); 174 | let v = unsafe { 175 | llvm::core::LLVMConstStructInContext(ctx.llvm(), vals.as_mut_ptr(), len as c_uint, 1) 176 | }; 177 | Value::from_inner(v)?.to_const() 178 | } 179 | 180 | pub fn create_named_struct( 181 | t: impl AsRef>, 182 | vals: impl AsRef<[Value<'a>]>, 183 | ) -> Result, Error> { 184 | let len = vals.as_ref().len(); 185 | let mut vals: Vec<*mut llvm::LLVMValue> = vals.as_ref().iter().map(|x| x.llvm()).collect(); 186 | let v = unsafe { 187 | llvm::core::LLVMConstNamedStruct(t.as_ref().llvm(), vals.as_mut_ptr(), len as c_uint) 188 | }; 189 | Value::from_inner(v)?.to_const() 190 | } 191 | 192 | pub fn create_array( 193 | t: impl AsRef>, 194 | vals: impl AsRef<[Value<'a>]>, 195 | ) -> Result, Error> { 196 | let len = vals.as_ref().len(); 197 | let mut vals: Vec<*mut llvm::LLVMValue> = vals.as_ref().iter().map(|x| x.llvm()).collect(); 198 | let v = unsafe { 199 | llvm::core::LLVMConstArray(t.as_ref().llvm(), vals.as_mut_ptr(), len as c_uint) 200 | }; 201 | Value::from_inner(v)?.to_const() 202 | } 203 | 204 | pub fn create_vector(vals: impl AsRef<[Value<'a>]>) -> Result, Error> { 205 | let len = vals.as_ref().len(); 206 | let mut vals: Vec<*mut llvm::LLVMValue> = vals.as_ref().iter().map(|x| x.llvm()).collect(); 207 | let v = unsafe { llvm::core::LLVMConstVector(vals.as_mut_ptr(), len as c_uint) }; 208 | Value::from_inner(v)?.to_const() 209 | } 210 | 211 | pub fn op_code(self) -> OpCode { 212 | unsafe { llvm::core::LLVMGetConstOpcode(self.as_ref().llvm()) } 213 | } 214 | 215 | pub fn neg(self) -> Result, Error> { 216 | unsafe { Value::from_inner(llvm::core::LLVMConstNeg(self.as_ref().llvm()))?.to_const() } 217 | } 218 | 219 | pub fn nsw_neg(self) -> Result, Error> { 220 | unsafe { Value::from_inner(llvm::core::LLVMConstNSWNeg(self.as_ref().llvm()))?.to_const() } 221 | } 222 | 223 | pub fn nuw_neg(self) -> Result, Error> { 224 | unsafe { Value::from_inner(llvm::core::LLVMConstNUWNeg(self.as_ref().llvm()))?.to_const() } 225 | } 226 | 227 | pub fn fneg(self) -> Result, Error> { 228 | unsafe { Value::from_inner(llvm::core::LLVMConstFNeg(self.as_ref().llvm()))?.to_const() } 229 | } 230 | 231 | pub fn not(self) -> Result, Error> { 232 | unsafe { Value::from_inner(llvm::core::LLVMConstNot(self.as_ref().llvm())) }?.to_const() 233 | } 234 | 235 | pub fn add(self, other: Const<'a>) -> Result, Error> { 236 | unsafe { 237 | Value::from_inner(llvm::core::LLVMConstAdd( 238 | self.as_ref().llvm(), 239 | other.as_ref().llvm(), 240 | ))? 241 | .to_const() 242 | } 243 | } 244 | 245 | pub fn nsw_add(self, other: Const<'a>) -> Result, Error> { 246 | unsafe { 247 | Value::from_inner(llvm::core::LLVMConstNSWAdd( 248 | self.as_ref().llvm(), 249 | other.as_ref().llvm(), 250 | ))? 251 | .to_const() 252 | } 253 | } 254 | 255 | pub fn nuw_add(self, other: Const<'a>) -> Result, Error> { 256 | unsafe { 257 | Value::from_inner(llvm::core::LLVMConstNUWAdd( 258 | self.as_ref().llvm(), 259 | other.as_ref().llvm(), 260 | ))? 261 | .to_const() 262 | } 263 | } 264 | 265 | pub fn fadd(self, other: Const<'a>) -> Result, Error> { 266 | unsafe { 267 | Value::from_inner(llvm::core::LLVMConstFAdd( 268 | self.as_ref().llvm(), 269 | other.as_ref().llvm(), 270 | ))? 271 | .to_const() 272 | } 273 | } 274 | 275 | pub fn sub(self, other: Const<'a>) -> Result, Error> { 276 | unsafe { 277 | Value::from_inner(llvm::core::LLVMConstSub( 278 | self.as_ref().llvm(), 279 | other.as_ref().llvm(), 280 | ))? 281 | .to_const() 282 | } 283 | } 284 | 285 | pub fn nsw_sub(self, other: Const<'a>) -> Result, Error> { 286 | unsafe { 287 | Value::from_inner(llvm::core::LLVMConstNSWSub( 288 | self.as_ref().llvm(), 289 | other.as_ref().llvm(), 290 | ))? 291 | .to_const() 292 | } 293 | } 294 | 295 | pub fn nuw_sub(self, other: Const<'a>) -> Result, Error> { 296 | unsafe { 297 | Value::from_inner(llvm::core::LLVMConstNUWSub( 298 | self.as_ref().llvm(), 299 | other.as_ref().llvm(), 300 | ))? 301 | .to_const() 302 | } 303 | } 304 | 305 | pub fn fsub(self, other: Const<'a>) -> Result, Error> { 306 | unsafe { 307 | Value::from_inner(llvm::core::LLVMConstFSub( 308 | self.as_ref().llvm(), 309 | other.as_ref().llvm(), 310 | ))? 311 | .to_const() 312 | } 313 | } 314 | 315 | pub fn mul(self, other: Const<'a>) -> Result, Error> { 316 | unsafe { 317 | Value::from_inner(llvm::core::LLVMConstMul( 318 | self.as_ref().llvm(), 319 | other.as_ref().llvm(), 320 | ))? 321 | .to_const() 322 | } 323 | } 324 | 325 | pub fn nsw_mul(self, other: Const<'a>) -> Result, Error> { 326 | unsafe { 327 | Value::from_inner(llvm::core::LLVMConstNSWMul( 328 | self.as_ref().llvm(), 329 | other.as_ref().llvm(), 330 | ))? 331 | .to_const() 332 | } 333 | } 334 | 335 | pub fn nuw_mul(self, other: Const<'a>) -> Result, Error> { 336 | unsafe { 337 | Value::from_inner(llvm::core::LLVMConstNUWMul( 338 | self.as_ref().llvm(), 339 | other.as_ref().llvm(), 340 | ))? 341 | .to_const() 342 | } 343 | } 344 | 345 | pub fn fmul(self, other: Const<'a>) -> Result, Error> { 346 | unsafe { 347 | Value::from_inner(llvm::core::LLVMConstFMul( 348 | self.as_ref().llvm(), 349 | other.as_ref().llvm(), 350 | ))? 351 | .to_const() 352 | } 353 | } 354 | 355 | pub fn udiv(self, other: Const<'a>) -> Result, Error> { 356 | unsafe { 357 | Value::from_inner(llvm::core::LLVMConstUDiv( 358 | self.as_ref().llvm(), 359 | other.as_ref().llvm(), 360 | ))? 361 | .to_const() 362 | } 363 | } 364 | 365 | pub fn exact_udiv(self, other: Const<'a>) -> Result, Error> { 366 | unsafe { 367 | Value::from_inner(llvm::core::LLVMConstExactUDiv( 368 | self.as_ref().llvm(), 369 | other.as_ref().llvm(), 370 | ))? 371 | .to_const() 372 | } 373 | } 374 | 375 | pub fn sdiv(self, other: Const<'a>) -> Result, Error> { 376 | unsafe { 377 | Value::from_inner(llvm::core::LLVMConstSDiv( 378 | self.as_ref().llvm(), 379 | other.as_ref().llvm(), 380 | ))? 381 | .to_const() 382 | } 383 | } 384 | 385 | pub fn exact_sdiv(self, other: Const<'a>) -> Result, Error> { 386 | unsafe { 387 | Value::from_inner(llvm::core::LLVMConstExactSDiv( 388 | self.as_ref().llvm(), 389 | other.as_ref().llvm(), 390 | ))? 391 | .to_const() 392 | } 393 | } 394 | 395 | pub fn fdiv(self, other: Const<'a>) -> Result, Error> { 396 | unsafe { 397 | Value::from_inner(llvm::core::LLVMConstFDiv( 398 | self.as_ref().llvm(), 399 | other.as_ref().llvm(), 400 | ))? 401 | .to_const() 402 | } 403 | } 404 | 405 | pub fn urem(self, other: Const<'a>) -> Result, Error> { 406 | unsafe { 407 | Value::from_inner(llvm::core::LLVMConstURem( 408 | self.as_ref().llvm(), 409 | other.as_ref().llvm(), 410 | ))? 411 | .to_const() 412 | } 413 | } 414 | 415 | pub fn srem(self, other: Const<'a>) -> Result, Error> { 416 | unsafe { 417 | Value::from_inner(llvm::core::LLVMConstSRem( 418 | self.as_ref().llvm(), 419 | other.as_ref().llvm(), 420 | ))? 421 | .to_const() 422 | } 423 | } 424 | 425 | pub fn frem(self, other: Const<'a>) -> Result, Error> { 426 | unsafe { 427 | Value::from_inner(llvm::core::LLVMConstFRem( 428 | self.as_ref().llvm(), 429 | other.as_ref().llvm(), 430 | ))? 431 | .to_const() 432 | } 433 | } 434 | 435 | pub fn and(self, other: Const<'a>) -> Result, Error> { 436 | unsafe { 437 | Value::from_inner(llvm::core::LLVMConstAnd( 438 | self.as_ref().llvm(), 439 | other.as_ref().llvm(), 440 | ))? 441 | .to_const() 442 | } 443 | } 444 | 445 | pub fn or(self, other: Const<'a>) -> Result, Error> { 446 | unsafe { 447 | Value::from_inner(llvm::core::LLVMConstOr( 448 | self.as_ref().llvm(), 449 | other.as_ref().llvm(), 450 | ))? 451 | .to_const() 452 | } 453 | } 454 | 455 | pub fn xor(self, other: Const<'a>) -> Result, Error> { 456 | unsafe { 457 | Value::from_inner(llvm::core::LLVMConstXor( 458 | self.as_ref().llvm(), 459 | other.as_ref().llvm(), 460 | ))? 461 | .to_const() 462 | } 463 | } 464 | 465 | pub fn icmp(self, pred: Icmp, other: Const<'a>) -> Result, Error> { 466 | unsafe { 467 | Value::from_inner(llvm::core::LLVMConstICmp( 468 | pred, 469 | self.as_ref().llvm(), 470 | other.as_ref().llvm(), 471 | ))? 472 | .to_const() 473 | } 474 | } 475 | 476 | pub fn fcmp(self, pred: Fcmp, other: Const<'a>) -> Result, Error> { 477 | unsafe { 478 | Value::from_inner(llvm::core::LLVMConstFCmp( 479 | pred, 480 | self.as_ref().llvm(), 481 | other.as_ref().llvm(), 482 | ))? 483 | .to_const() 484 | } 485 | } 486 | 487 | pub fn shl(self, other: Const<'a>) -> Result, Error> { 488 | unsafe { 489 | Value::from_inner(llvm::core::LLVMConstShl( 490 | self.as_ref().llvm(), 491 | other.as_ref().llvm(), 492 | ))? 493 | .to_const() 494 | } 495 | } 496 | 497 | pub fn lshr(self, other: Const<'a>) -> Result, Error> { 498 | unsafe { 499 | Value::from_inner(llvm::core::LLVMConstLShr( 500 | self.as_ref().llvm(), 501 | other.as_ref().llvm(), 502 | ))? 503 | .to_const() 504 | } 505 | } 506 | 507 | pub fn ashr(self, other: Const<'a>) -> Result, Error> { 508 | unsafe { 509 | Value::from_inner(llvm::core::LLVMConstAShr( 510 | self.as_ref().llvm(), 511 | other.as_ref().llvm(), 512 | ))? 513 | .to_const() 514 | } 515 | } 516 | 517 | pub fn gep( 518 | self, 519 | t: impl AsRef>, 520 | i: impl AsRef<[Value<'a>]>, 521 | ) -> Result, Error> { 522 | let len = i.as_ref().len(); 523 | let mut i: Vec<*mut llvm::LLVMValue> = i.as_ref().iter().map(|x| x.llvm()).collect(); 524 | unsafe { 525 | Value::from_inner(llvm::core::LLVMConstGEP2( 526 | t.as_ref().llvm(), 527 | self.as_ref().llvm(), 528 | i.as_mut_ptr(), 529 | len as c_uint, 530 | ))? 531 | .to_const() 532 | } 533 | } 534 | 535 | pub fn in_bounds_gep( 536 | self, 537 | t: impl AsRef>, 538 | i: impl AsRef<[Value<'a>]>, 539 | ) -> Result, Error> { 540 | let len = i.as_ref().len(); 541 | let mut i: Vec<*mut llvm::LLVMValue> = i.as_ref().iter().map(|x| x.llvm()).collect(); 542 | unsafe { 543 | Value::from_inner(llvm::core::LLVMConstInBoundsGEP2( 544 | t.as_ref().llvm(), 545 | self.as_ref().llvm(), 546 | i.as_mut_ptr(), 547 | len as c_uint, 548 | ))? 549 | .to_const() 550 | } 551 | } 552 | 553 | pub fn trunc(self, t: impl AsRef>) -> Result, Error> { 554 | unsafe { 555 | Value::from_inner(llvm::core::LLVMConstTrunc( 556 | self.as_ref().llvm(), 557 | t.as_ref().llvm(), 558 | ))? 559 | .to_const() 560 | } 561 | } 562 | 563 | pub fn sext(self, t: impl AsRef>) -> Result, Error> { 564 | unsafe { 565 | Value::from_inner(llvm::core::LLVMConstSExt( 566 | self.as_ref().llvm(), 567 | t.as_ref().llvm(), 568 | ))? 569 | .to_const() 570 | } 571 | } 572 | 573 | pub fn zext(self, t: impl AsRef>) -> Result, Error> { 574 | unsafe { 575 | Value::from_inner(llvm::core::LLVMConstZExt( 576 | self.as_ref().llvm(), 577 | t.as_ref().llvm(), 578 | ))? 579 | .to_const() 580 | } 581 | } 582 | 583 | pub fn fp_trunc(self, t: impl AsRef>) -> Result, Error> { 584 | unsafe { 585 | Value::from_inner(llvm::core::LLVMConstFPTrunc( 586 | self.as_ref().llvm(), 587 | t.as_ref().llvm(), 588 | ))? 589 | .to_const() 590 | } 591 | } 592 | 593 | pub fn fp_ext(self, t: impl AsRef>) -> Result, Error> { 594 | unsafe { 595 | Value::from_inner(llvm::core::LLVMConstFPExt( 596 | self.as_ref().llvm(), 597 | t.as_ref().llvm(), 598 | ))? 599 | .to_const() 600 | } 601 | } 602 | 603 | pub fn ui_to_fp(self, t: impl AsRef>) -> Result, Error> { 604 | unsafe { 605 | Value::from_inner(llvm::core::LLVMConstUIToFP( 606 | self.as_ref().llvm(), 607 | t.as_ref().llvm(), 608 | ))? 609 | .to_const() 610 | } 611 | } 612 | 613 | pub fn si_to_fp(self, t: impl AsRef>) -> Result, Error> { 614 | unsafe { 615 | Value::from_inner(llvm::core::LLVMConstSIToFP( 616 | self.as_ref().llvm(), 617 | t.as_ref().llvm(), 618 | ))? 619 | .to_const() 620 | } 621 | } 622 | 623 | pub fn fp_to_ui(self, t: impl AsRef>) -> Result, Error> { 624 | unsafe { 625 | Value::from_inner(llvm::core::LLVMConstFPToUI( 626 | self.as_ref().llvm(), 627 | t.as_ref().llvm(), 628 | ))? 629 | .to_const() 630 | } 631 | } 632 | 633 | pub fn fp_to_si(self, t: impl AsRef>) -> Result, Error> { 634 | unsafe { 635 | Value::from_inner(llvm::core::LLVMConstFPToSI( 636 | self.as_ref().llvm(), 637 | t.as_ref().llvm(), 638 | ))? 639 | .to_const() 640 | } 641 | } 642 | 643 | pub fn ptr_to_int(self, t: impl AsRef>) -> Result, Error> { 644 | unsafe { 645 | Value::from_inner(llvm::core::LLVMConstPtrToInt( 646 | self.as_ref().llvm(), 647 | t.as_ref().llvm(), 648 | ))? 649 | .to_const() 650 | } 651 | } 652 | 653 | pub fn int_to_ptr(self, t: impl AsRef>) -> Result, Error> { 654 | unsafe { 655 | Value::from_inner(llvm::core::LLVMConstIntToPtr( 656 | self.as_ref().llvm(), 657 | t.as_ref().llvm(), 658 | ))? 659 | .to_const() 660 | } 661 | } 662 | 663 | pub fn bit_cast(self, t: impl AsRef>) -> Result, Error> { 664 | unsafe { 665 | Value::from_inner(llvm::core::LLVMConstBitCast( 666 | self.as_ref().llvm(), 667 | t.as_ref().llvm(), 668 | ))? 669 | .to_const() 670 | } 671 | } 672 | 673 | pub fn addr_space_cast(self, t: impl AsRef>) -> Result, Error> { 674 | unsafe { 675 | Value::from_inner(llvm::core::LLVMConstAddrSpaceCast( 676 | self.as_ref().llvm(), 677 | t.as_ref().llvm(), 678 | ))? 679 | .to_const() 680 | } 681 | } 682 | 683 | pub fn zext_or_bit_cast(self, t: impl AsRef>) -> Result, Error> { 684 | unsafe { 685 | Value::from_inner(llvm::core::LLVMConstZExtOrBitCast( 686 | self.as_ref().llvm(), 687 | t.as_ref().llvm(), 688 | ))? 689 | .to_const() 690 | } 691 | } 692 | 693 | pub fn sext_or_bit_cast(self, t: impl AsRef>) -> Result, Error> { 694 | unsafe { 695 | Value::from_inner(llvm::core::LLVMConstSExtOrBitCast( 696 | self.as_ref().llvm(), 697 | t.as_ref().llvm(), 698 | ))? 699 | .to_const() 700 | } 701 | } 702 | 703 | pub fn trunc_or_bit_cast(self, t: impl AsRef>) -> Result, Error> { 704 | unsafe { 705 | Value::from_inner(llvm::core::LLVMConstTruncOrBitCast( 706 | self.as_ref().llvm(), 707 | t.as_ref().llvm(), 708 | ))? 709 | .to_const() 710 | } 711 | } 712 | 713 | const_func!(pointer_cast(&self, t: impl AsRef>) { 714 | llvm::core::LLVMConstPointerCast(self.as_ref().llvm(), t.as_ref().llvm()) 715 | }); 716 | 717 | const_func!(int_cast(&self, t: impl AsRef>, signed: bool) { 718 | llvm::core::LLVMConstIntCast(self.as_ref().llvm(), t.as_ref().llvm(), if signed { 1 } else { 0 }) 719 | }); 720 | 721 | const_func!(fp_cast(&self, t: impl AsRef>) { 722 | llvm::core::LLVMConstFPCast(self.as_ref().llvm(), t.as_ref().llvm()) 723 | }); 724 | 725 | const_func!(select(&self, a: Const<'a>, b: Const<'a>) { 726 | llvm::core::LLVMConstSelect(self.as_ref().llvm(), a.as_ref().llvm(), b.as_ref().llvm()) 727 | }); 728 | 729 | const_func!(extract_element(&self, index: Const<'a>) { 730 | llvm::core::LLVMConstExtractElement(self.as_ref().llvm(), index.as_ref().llvm()) 731 | }); 732 | 733 | const_func!(insert_element(&self, a: Const<'a>, b: Const<'a>) { 734 | llvm::core::LLVMConstInsertElement(self.as_ref().llvm(), a.as_ref().llvm(), b.as_ref().llvm()) 735 | }); 736 | 737 | const_func!(shuffle_vector(&self, a: Const<'a>, b: Const<'a>) { 738 | llvm::core::LLVMConstShuffleVector(self.as_ref().llvm(), a.as_ref().llvm(), b.as_ref().llvm()) 739 | }); 740 | 741 | const_func!(extract_value(&self, idx: impl AsRef<[usize]>) { 742 | let num = idx.as_ref().len(); 743 | let mut idx: Vec = idx.as_ref().iter().map(|x| *x as c_uint).collect(); 744 | llvm::core::LLVMConstExtractValue(self.as_ref().llvm(), idx.as_mut_ptr(), num as u32) 745 | }); 746 | 747 | const_func!(insert_value(&self, idx: impl AsRef<[usize]>, x: Const<'a>) { 748 | let num = idx.as_ref().len(); 749 | let mut idx: Vec = idx.as_ref().iter().map(|x| *x as c_uint).collect(); 750 | llvm::core::LLVMConstInsertValue(self.as_ref().llvm(), x.as_ref().llvm(), idx.as_mut_ptr(), num as u32) 751 | }); 752 | } 753 | -------------------------------------------------------------------------------- /src/builder.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | use crate::*; 4 | 5 | /// A `Builder` is used to create `Instruction`s 6 | pub struct Builder<'a>(NonNull, Context<'a>); 7 | 8 | llvm_inner_impl!(Builder<'a>, llvm::LLVMBuilder); 9 | 10 | impl<'a> Drop for Builder<'a> { 11 | fn drop(&mut self) { 12 | unsafe { llvm::core::LLVMDisposeBuilder(self.llvm()) } 13 | } 14 | } 15 | 16 | macro_rules! op { 17 | (3 : $name:ident, $f:ident) => { 18 | instr!($name(&self, a: impl AsRef>, b: impl AsRef>, c: impl AsRef>, name: impl AsRef) { 19 | let name = cstr!(name.as_ref()); 20 | llvm::core::$f(self.llvm(), a.as_ref().llvm(), b.as_ref().llvm(), c.as_ref().llvm(), name.as_ptr()) 21 | }); 22 | }; 23 | (2 : $name:ident, $f:ident) => { 24 | instr!($name(&self, a: impl AsRef>, b: impl AsRef>, name: impl AsRef) { 25 | let name = cstr!(name.as_ref()); 26 | llvm::core::$f(self.llvm(), a.as_ref().llvm(), b.as_ref().llvm(), name.as_ptr()) 27 | }); 28 | }; 29 | (1 : $name:ident, $f:ident) => { 30 | instr!($name(&self, a: impl AsRef>, name: impl AsRef) { 31 | let name = cstr!(name.as_ref()); 32 | llvm::core::$f(self.llvm(), a.as_ref().llvm(), name.as_ptr()) 33 | }); 34 | }; 35 | (0 : $name:ident, $f:ident) => { 36 | instr!($name(&self, a: impl AsRef>, name: impl AsRef) { 37 | let name = cstr!(name.as_ref()); 38 | llvm::core::$f(self.llvm(), name.as_ptr()) 39 | }); 40 | } 41 | 42 | } 43 | 44 | impl<'a> Builder<'a> { 45 | /// Create a new builder 46 | pub fn new(ctx: &Context<'a>) -> Result, Error> { 47 | let b = unsafe { wrap_inner(llvm::core::LLVMCreateBuilderInContext(ctx.llvm()))? }; 48 | Ok(Builder(b, ctx.clone().clone())) 49 | } 50 | 51 | /// Get the builder's context 52 | pub fn context(&self) -> &Context<'a> { 53 | &self.1 54 | } 55 | 56 | /// Position builder at end of block 57 | pub fn position_at_end(&self, block: BasicBlock<'a>) { 58 | unsafe { llvm::core::LLVMPositionBuilderAtEnd(self.llvm(), block.llvm()) } 59 | } 60 | 61 | /// Position builder before instruction 62 | pub fn position_before(&self, value: Instr<'a>) { 63 | unsafe { llvm::core::LLVMPositionBuilderBefore(self.llvm(), value.as_ref().llvm()) } 64 | } 65 | 66 | /// Clear insertion position 67 | pub fn clear_insertion_position(&self) { 68 | unsafe { llvm::core::LLVMClearInsertionPosition(self.llvm()) } 69 | } 70 | 71 | /// Get the insertion block 72 | pub fn insertion_block(&self) -> Result, Error> { 73 | unsafe { BasicBlock::from_inner(llvm::core::LLVMGetInsertBlock(self.llvm())) } 74 | } 75 | 76 | /// Declare the body of a function 77 | pub fn function_body< 78 | T: Into>, 79 | F: FnOnce(&Self, BasicBlock<'a>) -> Result, 80 | >( 81 | &self, 82 | f: Func<'a>, 83 | def: F, 84 | ) -> Result, Error> { 85 | let entry = BasicBlock::append(self.context(), f.as_ref(), "entry")?; 86 | self.position_at_end(entry); 87 | let v = def(self, entry)?; 88 | Ok(Instr(v.into())) 89 | } 90 | 91 | /// If-statement 92 | pub fn if_then_else< 93 | T: Into>, 94 | E: Into>, 95 | Then: FnOnce(&Builder<'a>) -> Result, 96 | Else: FnOnce(&Builder<'a>) -> Result, 97 | >( 98 | &self, 99 | cond: impl AsRef>, 100 | then_: Then, 101 | else_: Else, 102 | ) -> Result, Error> { 103 | let ctx = self.context(); 104 | let start_bb = self.insertion_block()?; 105 | let function = start_bb.parent()?; 106 | let then_bb = BasicBlock::append(ctx, &function, "then")?; 107 | self.position_at_end(then_bb); 108 | let then_ = then_(self)?.into(); 109 | let new_then_bb = self.insertion_block()?; 110 | let else_bb = BasicBlock::append(ctx, &function, "else")?; 111 | self.position_at_end(else_bb); 112 | let else_ = else_(self)?.into(); 113 | let new_else_bb = self.insertion_block()?; 114 | let merge_bb = BasicBlock::append(ctx, &function, "ifcont")?; 115 | self.position_at_end(merge_bb); 116 | 117 | self.position_at_end(start_bb); 118 | self.cond_br(cond, then_bb, else_bb)?; 119 | 120 | self.position_at_end(new_then_bb); 121 | self.br(merge_bb)?; 122 | 123 | self.position_at_end(new_else_bb); 124 | self.br(merge_bb)?; 125 | 126 | self.position_at_end(merge_bb); 127 | 128 | let mut phi = self.phi(then_.type_of()?, "ite")?; 129 | phi.add_incoming(&[(then_, new_then_bb), (else_, new_else_bb)]); 130 | Ok(phi) 131 | } 132 | 133 | /// For-loop 134 | pub fn for_loop< 135 | S: Into>, 136 | C: Into>, 137 | X: Into>, 138 | Step: FnOnce(&Value<'a>) -> Result, 139 | Cond: FnOnce(&Value<'a>) -> Result, 140 | F: FnOnce(&Value<'a>) -> Result, 141 | >( 142 | &self, 143 | start: impl AsRef>, 144 | cond: Cond, 145 | step: Step, 146 | f: F, 147 | ) -> Result, Error> { 148 | let ctx = self.context(); 149 | 150 | let start = start.as_ref(); 151 | 152 | let preheader_bb = self.insertion_block()?; 153 | let function = preheader_bb.parent()?; 154 | let loop_bb = BasicBlock::append(ctx, &function, "loop")?; 155 | 156 | self.br(loop_bb)?; 157 | self.position_at_end(loop_bb); 158 | 159 | let mut var = self.phi(start.type_of()?, "x")?; 160 | var.add_incoming(&[(*start, preheader_bb)]); 161 | 162 | let _body = f(var.as_ref())?; 163 | 164 | let next_var = step(var.as_ref())?.into(); 165 | 166 | let cond = cond(next_var.as_ref())?.into(); 167 | 168 | let loop_end_bb = self.insertion_block()?; 169 | let after_bb = BasicBlock::append(ctx, &function, "after")?; 170 | self.cond_br(cond, loop_bb, after_bb)?; 171 | self.position_at_end(after_bb); 172 | 173 | var.add_incoming(&[(next_var, loop_end_bb)]); 174 | Ok(_body.into()) 175 | } 176 | 177 | instr!(ret_void(&self) { 178 | llvm::core::LLVMBuildRetVoid( 179 | self.llvm(), 180 | ) 181 | }); 182 | 183 | instr!(ret(&self, a: impl AsRef>) { 184 | llvm::core::LLVMBuildRet( 185 | self.llvm(), 186 | a.as_ref().llvm() 187 | ) 188 | }); 189 | 190 | instr!(aggregate_ret(&self, vals: impl AsRef<[Value<'a>]>) { 191 | let values = vals.as_ref(); 192 | let mut values: Vec<*mut llvm::LLVMValue> = values.iter().map(|x| x.llvm()).collect(); 193 | let ptr = values.as_mut_ptr(); 194 | let len = values.len(); 195 | llvm::core::LLVMBuildAggregateRet(self.llvm(), ptr, len as u32) 196 | }); 197 | 198 | instr!(br(&self, bb: BasicBlock<'a>) { 199 | llvm::core::LLVMBuildBr(self.llvm(), bb.llvm()) 200 | }); 201 | 202 | instr!(cond_br(&self, if_: impl AsRef>, then_: BasicBlock<'a>, else_: BasicBlock<'a>) { 203 | llvm::core::LLVMBuildCondBr(self.llvm(), if_.as_ref().llvm(), then_.llvm(), else_.llvm()) 204 | }); 205 | 206 | instr!(InstrSwitch: switch(&self, v: impl AsRef>, bb: BasicBlock<'a>, num_cases: usize) { 207 | llvm::core::LLVMBuildSwitch(self.llvm(), v.as_ref().llvm(), bb.llvm(), num_cases as c_uint) 208 | }); 209 | 210 | instr!(InstrIndirectBr: indirect_br(&self, addr: impl AsRef>, num_dests: usize) { 211 | llvm::core::LLVMBuildIndirectBr(self.llvm(), addr.as_ref().llvm(), num_dests as c_uint) 212 | }); 213 | 214 | instr!(InstrCall: invoke(&self, t: impl AsRef>, f: impl AsRef>, args: impl AsRef<[Value<'a>]>, then: BasicBlock<'a>, catch: BasicBlock<'a>, name: impl AsRef) { 215 | let name = cstr!(name.as_ref()); 216 | let mut args: Vec<*mut llvm::LLVMValue> = args.as_ref().iter().map(|x| x.llvm()).collect(); 217 | llvm::core::LLVMBuildInvoke2(self.llvm(), t.as_ref().llvm(), f.as_ref().llvm(), args.as_mut_ptr(), args.len() as c_uint, then.llvm(), catch.llvm(), name.as_ptr()) 218 | }); 219 | 220 | instr!(unreachable(&self) { 221 | llvm::core::LLVMBuildUnreachable(self.llvm()) 222 | }); 223 | 224 | instr!(resume(&self, exn: impl AsRef>) { 225 | llvm::core::LLVMBuildResume(self.llvm(), exn.as_ref().llvm()) 226 | }); 227 | 228 | op!(2: add, LLVMBuildAdd); 229 | op!(2: nsw_add, LLVMBuildNSWAdd); 230 | op!(2: nuw_add, LLVMBuildNUWAdd); 231 | op!(2: fadd, LLVMBuildFAdd); 232 | op!(2: sub, LLVMBuildSub); 233 | op!(2: nsw_sub, LLVMBuildNSWSub); 234 | op!(2: nuw_sub, LLVMBuildNUWSub); 235 | op!(2: fsub, LLVMBuildFSub); 236 | op!(2: mul, LLVMBuildMul); 237 | op!(2: nsw_mul, LLVMBuildNSWMul); 238 | op!(2: nuw_mul, LLVMBuildNUWMul); 239 | op!(2: fmul, LLVMBuildFMul); 240 | op!(2: udiv, LLVMBuildUDiv); 241 | op!(2: exact_udiv, LLVMBuildExactUDiv); 242 | op!(2: sdiv, LLVMBuildSDiv); 243 | op!(2: exact_sdiv, LLVMBuildExactSDiv); 244 | op!(2: fdiv, LLVMBuildFDiv); 245 | op!(2: urem, LLVMBuildURem); 246 | op!(2: srem, LLVMBuildSRem); 247 | op!(2: frem, LLVMBuildFRem); 248 | op!(2: shl, LLVMBuildShl); 249 | op!(2: lshr, LLVMBuildLShr); 250 | op!(2: ashr, LLVMBuildAShr); 251 | op!(2: and, LLVMBuildAnd); 252 | op!(2: or, LLVMBuildOr); 253 | op!(2: xor, LLVMBuildXor); 254 | 255 | pub fn bin_op( 256 | &self, 257 | op: OpCode, 258 | lhs: impl AsRef>, 259 | rhs: impl AsRef>, 260 | name: impl AsRef, 261 | ) -> Result, Error> { 262 | let name = cstr!(name.as_ref()); 263 | unsafe { 264 | Ok(Instr(Value::from_inner(llvm::core::LLVMBuildBinOp( 265 | self.llvm(), 266 | op, 267 | lhs.as_ref().llvm(), 268 | rhs.as_ref().llvm(), 269 | name.as_ptr(), 270 | ))?)) 271 | } 272 | } 273 | 274 | op!(1: neg, LLVMBuildNeg); 275 | op!(1: nsw_neg, LLVMBuildNSWNeg); 276 | op!(1: nuw_neg, LLVMBuildNUWNeg); 277 | op!(1: fneg, LLVMBuildFNeg); 278 | op!(1: not, LLVMBuildNot); 279 | 280 | instr!(malloc( 281 | &self, 282 | t: impl AsRef>, 283 | name: impl AsRef, 284 | ) { 285 | let name = cstr!(name.as_ref()); 286 | llvm::core::LLVMBuildMalloc( 287 | self.llvm(), 288 | t.as_ref().llvm(), 289 | name.as_ptr(), 290 | ) 291 | }); 292 | 293 | instr!(array_malloc( 294 | &self, 295 | t: impl AsRef>, 296 | v: impl AsRef>, 297 | name: impl AsRef, 298 | ){ 299 | let name = cstr!(name.as_ref()); 300 | llvm::core::LLVMBuildArrayMalloc( 301 | self.llvm(), 302 | t.as_ref().llvm(), 303 | v.as_ref().llvm(), 304 | name.as_ptr(), 305 | ) 306 | }); 307 | 308 | instr!(memset( 309 | &self, 310 | ptr: impl AsRef>, 311 | val: impl AsRef>, 312 | len: impl AsRef>, 313 | align: usize, 314 | ) { 315 | llvm::core::LLVMBuildMemSet( 316 | self.llvm(), 317 | ptr.as_ref().llvm(), 318 | val.as_ref().llvm(), 319 | len.as_ref().llvm(), 320 | align as c_uint, 321 | ) 322 | }); 323 | 324 | instr!(memcpy( 325 | &self, 326 | dst: impl AsRef>, 327 | dst_align: usize, 328 | src: impl AsRef>, 329 | src_align: usize, 330 | len: impl AsRef>, 331 | ) { 332 | llvm::core::LLVMBuildMemCpy( 333 | self.llvm(), 334 | dst.as_ref().llvm(), 335 | dst_align as c_uint, 336 | src.as_ref().llvm(), 337 | src_align as c_uint, 338 | len.as_ref().llvm(), 339 | ) 340 | }); 341 | 342 | instr!(memmove( 343 | &self, 344 | dst: impl AsRef>, 345 | dst_align: usize, 346 | src: impl AsRef>, 347 | src_align: usize, 348 | len: impl AsRef>, 349 | ) { 350 | llvm::core::LLVMBuildMemMove( 351 | self.llvm(), 352 | dst.as_ref().llvm(), 353 | dst_align as c_uint, 354 | src.as_ref().llvm(), 355 | src_align as c_uint, 356 | len.as_ref().llvm(), 357 | ) 358 | }); 359 | 360 | instr!(InstrAlloca: alloca(&self, t: impl AsRef>, name: impl AsRef) { 361 | let name = cstr!(name.as_ref()); 362 | llvm::core::LLVMBuildAlloca( 363 | self.llvm(), 364 | t.as_ref().llvm(), 365 | name.as_ptr(), 366 | ) 367 | }); 368 | 369 | instr!(array_alloca( 370 | &self, 371 | t: impl AsRef>, 372 | v: impl AsRef>, 373 | name: impl AsRef, 374 | ) { 375 | let name = cstr!(name.as_ref()); 376 | llvm::core::LLVMBuildArrayAlloca( 377 | self.llvm(), 378 | t.as_ref().llvm(), 379 | v.as_ref().llvm(), 380 | name.as_ptr(), 381 | ) 382 | }); 383 | 384 | instr!(free(&self, val: impl AsRef>) { 385 | llvm::core::LLVMBuildFree( 386 | self.llvm(), 387 | val.as_ref().llvm(), 388 | ) 389 | }); 390 | 391 | instr!(load(&self, t: impl AsRef>, v: impl AsRef>, name: impl AsRef) { 392 | let name = cstr!(name.as_ref()); 393 | llvm::core::LLVMBuildLoad2( 394 | self.llvm(), 395 | t.as_ref().llvm(), 396 | v.as_ref().llvm(), 397 | name.as_ptr(), 398 | ) 399 | }); 400 | 401 | instr!(store(&self, val: impl AsRef>, ptr: impl AsRef>) { 402 | llvm::core::LLVMBuildStore( 403 | self.llvm(), 404 | val.as_ref().llvm(), 405 | ptr.as_ref().llvm(), 406 | ) 407 | }); 408 | 409 | instr!(InstrGep: struct_gep(&self, ty: impl AsRef>, ptr: impl AsRef>, index: usize, name: impl AsRef) { 410 | let name = cstr!(name.as_ref()); 411 | llvm::core::LLVMBuildStructGEP2( 412 | self.llvm(), 413 | ty.as_ref().llvm(), 414 | ptr.as_ref().llvm(), 415 | index as c_uint, 416 | name.as_ptr(), 417 | ) 418 | }); 419 | 420 | instr!(InstrGep: gep( 421 | &self, 422 | ty: impl AsRef>, 423 | ptr: impl AsRef>, 424 | indices: impl AsRef<[Value<'a>]>, 425 | name: impl AsRef, 426 | ) { 427 | let mut v: Vec<*mut llvm::LLVMValue> = 428 | indices.as_ref().iter().map(|x| x.llvm()).collect(); 429 | let len = indices.as_ref().len(); 430 | let name = cstr!(name.as_ref()); 431 | llvm::core::LLVMBuildGEP2( 432 | self.llvm(), 433 | ty.as_ref().llvm(), 434 | ptr.as_ref().llvm(), 435 | v.as_mut_ptr(), 436 | len as c_uint, 437 | name.as_ptr(), 438 | ) 439 | }); 440 | 441 | instr!(InstrGep: in_bounds_gep( 442 | &self, 443 | ty: impl AsRef>, 444 | ptr: impl AsRef>, 445 | indices: impl AsRef<[Value<'a>]>, 446 | name: impl AsRef, 447 | ) { 448 | let mut v: Vec<*mut llvm::LLVMValue> = 449 | indices.as_ref().iter().map(|x| x.llvm()).collect(); 450 | let len = indices.as_ref().len(); 451 | let name = cstr!(name.as_ref()); 452 | llvm::core::LLVMBuildInBoundsGEP2( 453 | self.llvm(), 454 | ty.as_ref().llvm(), 455 | ptr.as_ref().llvm(), 456 | v.as_mut_ptr(), 457 | len as c_uint, 458 | name.as_ptr(), 459 | ) 460 | }); 461 | 462 | instr!(InstrGep: struct_gep2( 463 | &self, 464 | ty: impl AsRef>, 465 | ptr: impl AsRef>, 466 | index: usize, 467 | name: impl AsRef, 468 | ) { 469 | let name = cstr!(name.as_ref()); 470 | llvm::core::LLVMBuildStructGEP2( 471 | self.llvm(), 472 | ty.as_ref().llvm(), 473 | ptr.as_ref().llvm(), 474 | index as c_uint, 475 | name.as_ptr(), 476 | ) 477 | }); 478 | 479 | instr!(global_string(&self, s: impl AsRef, name: impl AsRef) { 480 | let s = cstr!(s.as_ref()); 481 | let name = cstr!(name.as_ref()); 482 | llvm::core::LLVMBuildGlobalString( 483 | self.llvm(), 484 | s.as_ptr(), 485 | name.as_ptr(), 486 | ) 487 | }); 488 | 489 | instr!(global_string_ptr(&self, s: impl AsRef, name: impl AsRef) { 490 | let s = cstr!(s.as_ref()); 491 | let name = cstr!(name.as_ref()); 492 | llvm::core::LLVMBuildGlobalStringPtr( 493 | self.llvm(), 494 | s.as_ptr(), 495 | name.as_ptr(), 496 | ) 497 | }); 498 | 499 | instr!(trunc( 500 | &self, 501 | val: impl AsRef>, 502 | ty: impl AsRef>, 503 | name: impl AsRef, 504 | ) { 505 | let name = cstr!(name.as_ref()); 506 | llvm::core::LLVMBuildTrunc( 507 | self.llvm(), 508 | val.as_ref().llvm(), 509 | ty.as_ref().llvm(), 510 | name.as_ptr(), 511 | ) 512 | }); 513 | 514 | instr!(zext( 515 | &self, 516 | val: impl AsRef>, 517 | ty: impl AsRef>, 518 | name: impl AsRef, 519 | ) { 520 | let name = cstr!(name.as_ref()); 521 | llvm::core::LLVMBuildZExt( 522 | self.llvm(), 523 | val.as_ref().llvm(), 524 | ty.as_ref().llvm(), 525 | name.as_ptr(), 526 | ) 527 | }); 528 | 529 | instr!(sext( 530 | &self, 531 | val: impl AsRef>, 532 | ty: impl AsRef>, 533 | name: impl AsRef, 534 | ) { 535 | let name = cstr!(name.as_ref()); 536 | llvm::core::LLVMBuildSExt( 537 | self.llvm(), 538 | val.as_ref().llvm(), 539 | ty.as_ref().llvm(), 540 | name.as_ptr(), 541 | ) 542 | }); 543 | 544 | instr!(fp_to_ui( 545 | &self, 546 | val: impl AsRef>, 547 | ty: impl AsRef>, 548 | name: impl AsRef, 549 | ) { 550 | let name = cstr!(name.as_ref()); 551 | llvm::core::LLVMBuildFPToUI( 552 | self.llvm(), 553 | val.as_ref().llvm(), 554 | ty.as_ref().llvm(), 555 | name.as_ptr(), 556 | ) 557 | }); 558 | 559 | instr!(fp_to_si( 560 | &self, 561 | val: impl AsRef>, 562 | ty: impl AsRef>, 563 | name: impl AsRef, 564 | ) { 565 | let name = cstr!(name.as_ref()); 566 | llvm::core::LLVMBuildFPToSI( 567 | self.llvm(), 568 | val.as_ref().llvm(), 569 | ty.as_ref().llvm(), 570 | name.as_ptr(), 571 | ) 572 | }); 573 | 574 | instr!(ui_to_fp( 575 | &self, 576 | val: impl AsRef>, 577 | ty: impl AsRef>, 578 | name: impl AsRef, 579 | ) { 580 | let name = cstr!(name.as_ref()); 581 | llvm::core::LLVMBuildUIToFP( 582 | self.llvm(), 583 | val.as_ref().llvm(), 584 | ty.as_ref().llvm(), 585 | name.as_ptr(), 586 | ) 587 | }); 588 | 589 | instr!(si_to_fp( 590 | &self, 591 | val: impl AsRef>, 592 | ty: impl AsRef>, 593 | name: impl AsRef, 594 | ) { 595 | let name = cstr!(name.as_ref()); 596 | llvm::core::LLVMBuildSIToFP( 597 | self.llvm(), 598 | val.as_ref().llvm(), 599 | ty.as_ref().llvm(), 600 | name.as_ptr(), 601 | ) 602 | }); 603 | 604 | instr!(fp_trunc( 605 | &self, 606 | val: impl AsRef>, 607 | ty: impl AsRef>, 608 | name: impl AsRef, 609 | ) { 610 | let name = cstr!(name.as_ref()); 611 | llvm::core::LLVMBuildFPTrunc( 612 | self.llvm(), 613 | val.as_ref().llvm(), 614 | ty.as_ref().llvm(), 615 | name.as_ptr(), 616 | ) 617 | }); 618 | 619 | instr!(fp_ext( 620 | &self, 621 | val: impl AsRef>, 622 | ty: impl AsRef>, 623 | name: impl AsRef, 624 | ) { 625 | let name = cstr!(name.as_ref()); 626 | llvm::core::LLVMBuildFPExt( 627 | self.llvm(), 628 | val.as_ref().llvm(), 629 | ty.as_ref().llvm(), 630 | name.as_ptr(), 631 | ) 632 | }); 633 | 634 | instr!(ptr_to_int( 635 | &self, 636 | val: impl AsRef>, 637 | ty: impl AsRef>, 638 | name: impl AsRef, 639 | ) { 640 | let name = cstr!(name.as_ref()); 641 | llvm::core::LLVMBuildPtrToInt( 642 | self.llvm(), 643 | val.as_ref().llvm(), 644 | ty.as_ref().llvm(), 645 | name.as_ptr(), 646 | ) 647 | }); 648 | 649 | instr!(int_to_ptr( 650 | &self, 651 | val: impl AsRef>, 652 | ty: impl AsRef>, 653 | name: impl AsRef, 654 | ) { 655 | let name = cstr!(name.as_ref()); 656 | llvm::core::LLVMBuildIntToPtr( 657 | self.llvm(), 658 | val.as_ref().llvm(), 659 | ty.as_ref().llvm(), 660 | name.as_ptr(), 661 | ) 662 | }); 663 | 664 | instr!(bit_cast( 665 | &self, 666 | val: impl AsRef>, 667 | ty: impl AsRef>, 668 | name: impl AsRef, 669 | ) { 670 | let name = cstr!(name.as_ref()); 671 | llvm::core::LLVMBuildBitCast( 672 | self.llvm(), 673 | val.as_ref().llvm(), 674 | ty.as_ref().llvm(), 675 | name.as_ptr(), 676 | ) 677 | }); 678 | 679 | instr!(addr_space_cast( 680 | &self, 681 | val: impl AsRef>, 682 | ty: impl AsRef>, 683 | name: impl AsRef, 684 | ) { 685 | let name = cstr!(name.as_ref()); 686 | llvm::core::LLVMBuildAddrSpaceCast( 687 | self.llvm(), 688 | val.as_ref().llvm(), 689 | ty.as_ref().llvm(), 690 | name.as_ptr(), 691 | ) 692 | }); 693 | 694 | instr!(zext_or_bit_cast( 695 | &self, 696 | val: impl AsRef>, 697 | ty: impl AsRef>, 698 | name: impl AsRef, 699 | ) { 700 | let name = cstr!(name.as_ref()); 701 | llvm::core::LLVMBuildZExtOrBitCast( 702 | self.llvm(), 703 | val.as_ref().llvm(), 704 | ty.as_ref().llvm(), 705 | name.as_ptr(), 706 | ) 707 | }); 708 | 709 | instr!(sext_or_bit_cast( 710 | &self, 711 | val: impl AsRef>, 712 | ty: impl AsRef>, 713 | name: impl AsRef, 714 | ) { 715 | let name = cstr!(name.as_ref()); 716 | llvm::core::LLVMBuildSExtOrBitCast( 717 | self.llvm(), 718 | val.as_ref().llvm(), 719 | ty.as_ref().llvm(), 720 | name.as_ptr(), 721 | ) 722 | }); 723 | 724 | instr!(trunc_or_bit_cast( 725 | &self, 726 | val: impl AsRef>, 727 | ty: impl AsRef>, 728 | name: impl AsRef, 729 | ) { 730 | let name = cstr!(name.as_ref()); 731 | llvm::core::LLVMBuildTruncOrBitCast( 732 | self.llvm(), 733 | val.as_ref().llvm(), 734 | ty.as_ref().llvm(), 735 | name.as_ptr(), 736 | ) 737 | }); 738 | 739 | instr!(pointer_cast( 740 | &self, 741 | val: impl AsRef>, 742 | ty: impl AsRef>, 743 | name: impl AsRef, 744 | ) { 745 | let name = cstr!(name.as_ref()); 746 | llvm::core::LLVMBuildPointerCast( 747 | self.llvm(), 748 | val.as_ref().llvm(), 749 | ty.as_ref().llvm(), 750 | name.as_ptr(), 751 | ) 752 | }); 753 | 754 | instr!(int_cast( 755 | &self, 756 | val: impl AsRef>, 757 | ty: impl AsRef>, 758 | signed: bool, 759 | name: impl AsRef, 760 | ) { 761 | let name = cstr!(name.as_ref()); 762 | llvm::core::LLVMBuildIntCast2( 763 | self.llvm(), 764 | val.as_ref().llvm(), 765 | ty.as_ref().llvm(), 766 | if signed { 1 } else { 0 }, 767 | name.as_ptr(), 768 | ) 769 | }); 770 | 771 | instr!(fp_cast( 772 | &self, 773 | val: impl AsRef>, 774 | ty: impl AsRef>, 775 | name: impl AsRef, 776 | ) { 777 | let name = cstr!(name.as_ref()); 778 | llvm::core::LLVMBuildFPCast( 779 | self.llvm(), 780 | val.as_ref().llvm(), 781 | ty.as_ref().llvm(), 782 | name.as_ptr(), 783 | ) 784 | }); 785 | 786 | instr!(InstrIcmp: icmp( 787 | &self, 788 | op: Icmp, 789 | lhs: impl AsRef>, 790 | rhs: impl AsRef>, 791 | name: impl AsRef, 792 | ) { 793 | let name = cstr!(name.as_ref()); 794 | llvm::core::LLVMBuildICmp( 795 | self.llvm(), 796 | op, 797 | lhs.as_ref().llvm(), 798 | rhs.as_ref().llvm(), 799 | name.as_ptr(), 800 | ) 801 | }); 802 | 803 | instr!(InstrFcmp: fcmp( 804 | &self, 805 | op: Fcmp, 806 | lhs: impl AsRef>, 807 | rhs: impl AsRef>, 808 | name: impl AsRef, 809 | ) { 810 | let name = cstr!(name.as_ref()); 811 | llvm::core::LLVMBuildFCmp( 812 | self.llvm(), 813 | op, 814 | lhs.as_ref().llvm(), 815 | rhs.as_ref().llvm(), 816 | name.as_ptr(), 817 | ) 818 | }); 819 | 820 | instr!(InstrPhi: phi(&self, ty: impl AsRef>, name: impl AsRef) { 821 | let name = cstr!(name.as_ref()); 822 | llvm::core::LLVMBuildPhi( 823 | self.llvm(), 824 | ty.as_ref().llvm(), 825 | name.as_ptr(), 826 | ) 827 | }); 828 | 829 | instr!(InstrCall: call(&self, f: Func<'a>, args: impl AsRef<[Value<'a>]>, name: impl AsRef) { 830 | let name = cstr!(name.as_ref()); 831 | let mut values: Vec<*mut llvm::LLVMValue> = args.as_ref().iter().map(|x| x.llvm()).collect(); 832 | let ptr = values.as_mut_ptr(); 833 | let len = values.len(); 834 | let t = f.func_type()?; 835 | 836 | llvm::core::LLVMBuildCall2(self.llvm(), t.as_ref().llvm(), f.as_ref().llvm(), ptr, len as c_uint, name.as_ptr()) 837 | }); 838 | 839 | op!(3: select, LLVMBuildSelect); 840 | 841 | instr!(va_arg(&self, list: impl AsRef>, ty: impl AsRef>, name: impl AsRef) { 842 | let name = cstr!(name.as_ref()); 843 | llvm::core::LLVMBuildVAArg(self.llvm(), list.as_ref().llvm(), ty.as_ref().llvm(), name.as_ptr()) 844 | }); 845 | 846 | op!(2: extract_element, LLVMBuildExtractElement); 847 | op!(3: insert_element, LLVMBuildInsertElement); 848 | op!(3: shuffle_vector, LLVMBuildShuffleVector); 849 | 850 | instr!(extract_value(&self, vec: impl AsRef>, index: usize, name: impl AsRef) { 851 | let name = cstr!(name.as_ref()); 852 | llvm::core::LLVMBuildExtractValue(self.llvm(), vec.as_ref().llvm(), index as c_uint, name.as_ptr()) 853 | }); 854 | 855 | instr!(insert_value(&self, vec: impl AsRef>, val: impl AsRef>, index: usize, name: impl AsRef) { 856 | let name = cstr!(name.as_ref()); 857 | llvm::core::LLVMBuildInsertValue(self.llvm(), vec.as_ref().llvm(), val.as_ref().llvm(), index as c_uint, name.as_ptr()) 858 | }); 859 | 860 | op!(1: is_null, LLVMBuildIsNull); 861 | op!(1: is_not_null, LLVMBuildIsNotNull); 862 | 863 | instr!(ptr_diff(&self, t: impl AsRef>, a: impl AsRef>, b: impl AsRef>, name: impl AsRef) { 864 | let name = cstr!(name.as_ref()); 865 | llvm::core::LLVMBuildPtrDiff2(self.llvm(), t.as_ref().llvm(), a.as_ref().llvm(), b.as_ref().llvm(), name.as_ptr()) 866 | }); 867 | 868 | instr!(fence(&self, ordering: AtomicOrdering, single_thread: bool, name: impl AsRef) { 869 | let name = cstr!(name.as_ref()); 870 | let single_thread = if single_thread { 1 } else { 0 }; 871 | llvm::core::LLVMBuildFence(self.llvm(), ordering, single_thread, name.as_ptr()) 872 | }); 873 | 874 | instr!(atomic_rmw(&self, op: AtomicRMWBinOp, ptr: impl AsRef>, val: impl AsRef>, ordering: AtomicOrdering, single_thread: bool) { 875 | let single_thread = if single_thread { 1 } else { 0 }; 876 | llvm::core::LLVMBuildAtomicRMW(self.llvm(), op, ptr.as_ref().llvm(), val.as_ref().llvm(), ordering, single_thread) 877 | }); 878 | 879 | instr!(atomic_cmp_xchg(&self, ptr: impl AsRef>, cmp: impl AsRef>, new_: impl AsRef>, success_ordering: AtomicOrdering, failure_ordering: AtomicOrdering, single_thread: bool) { 880 | let single_thread = if single_thread { 1 } else { 0 }; 881 | llvm::core::LLVMBuildAtomicCmpXchg(self.llvm(), ptr.as_ref().llvm(), cmp.as_ref().llvm(), new_.as_ref().llvm(), success_ordering, failure_ordering, single_thread) 882 | }); 883 | 884 | op!(1: freeze, LLVMBuildFreeze); 885 | } 886 | --------------------------------------------------------------------------------