pub struct Builder<'ctx> { /* private fields */ }
Expand description
All build_*
methods return a Result<_, BuilderError>
type containing either the returned value or some error.
Those methods all may return BuilderError::UnsetPosition
if a position_*
method has not yet been called, in addition
to any other possibility.
Implementations§
Source§impl<'ctx> Builder<'ctx>
impl<'ctx> Builder<'ctx>
pub unsafe fn new(builder: LLVMBuilderRef) -> Self
Sourcepub fn as_mut_ptr(&self) -> LLVMBuilderRef
pub fn as_mut_ptr(&self) -> LLVMBuilderRef
Acquires the underlying raw pointer belonging to this Builder
type.
Sourcepub fn build_return(
&self,
value: Option<&dyn BasicValue<'ctx>>,
) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_return( &self, value: Option<&dyn BasicValue<'ctx>>, ) -> Result<InstructionValue<'ctx>, BuilderError>
Builds a function return instruction. It should be provided with None
if the return type
is void otherwise Some(&value)
should be provided.
§Example
use inkwell::context::Context;
// A simple function which returns its argument:
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let i32_type = context.i32_type();
let arg_types = [i32_type.into()];
let fn_type = i32_type.fn_type(&arg_types, false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_arg = fn_value.get_first_param().unwrap();
builder.position_at_end(entry);
builder.build_return(Some(&i32_arg)).unwrap();
Sourcepub fn build_aggregate_return(
&self,
values: &[BasicValueEnum<'ctx>],
) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_aggregate_return( &self, values: &[BasicValueEnum<'ctx>], ) -> Result<InstructionValue<'ctx>, BuilderError>
Builds a function return instruction for a return type which is an aggregate type (ie structs and arrays).
It is not necessary to use this over build_return
but may be more convenient to use.
§Example
use inkwell::context::Context;
// This builds a simple function which returns a struct (tuple) of two ints.
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let i32_type = context.i32_type();
let i32_three = i32_type.const_int(3, false);
let i32_seven = i32_type.const_int(7, false);
let struct_type = context.struct_type(&[i32_type.into(), i32_type.into()], false);
let fn_type = struct_type.fn_type(&[], false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
builder.position_at_end(entry);
builder.build_aggregate_return(&[i32_three.into(), i32_seven.into()]).unwrap();
Sourcepub fn build_call(
&self,
function: FunctionValue<'ctx>,
args: &[BasicMetadataValueEnum<'ctx>],
name: &str,
) -> Result<CallSiteValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_call( &self, function: FunctionValue<'ctx>, args: &[BasicMetadataValueEnum<'ctx>], name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Builds a function call instruction. Alias for Builder::build_direct_call.
Sourcepub fn build_direct_call(
&self,
function: FunctionValue<'ctx>,
args: &[BasicMetadataValueEnum<'ctx>],
name: &str,
) -> Result<CallSiteValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_direct_call( &self, function: FunctionValue<'ctx>, args: &[BasicMetadataValueEnum<'ctx>], name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Builds a function call instruction. The function being called is known at compile time. If you want to call a function pointer, see Builder::build_indirect_call.
§Example
use inkwell::context::Context;
// A simple function which calls itself:
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let i32_type = context.i32_type();
let fn_type = i32_type.fn_type(&[i32_type.into()], false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_arg = fn_value.get_first_param().unwrap();
let md_string = context.metadata_string("a metadata");
builder.position_at_end(entry);
let ret_val = builder.build_call(fn_value, &[i32_arg.into(), md_string.into()], "call").unwrap()
.try_as_basic_value()
.left()
.unwrap();
builder.build_return(Some(&ret_val)).unwrap();
Sourcepub fn build_direct_call_with_operand_bundles(
&self,
function: FunctionValue<'ctx>,
args: &[BasicMetadataValueEnum<'ctx>],
operand_bundles: &[OperandBundle<'ctx>],
name: &str,
) -> Result<CallSiteValue<'ctx>, BuilderError>
Available on crate feature llvm18-0
only.
pub fn build_direct_call_with_operand_bundles( &self, function: FunctionValue<'ctx>, args: &[BasicMetadataValueEnum<'ctx>], operand_bundles: &[OperandBundle<'ctx>], name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm18-0
only.Build a function call instruction, with attached operand bundles.
§Example
use inkwell::context::Context;
use inkwell::values::OperandBundle;
let context = Context::create();
let module = context.create_module("call_with_op_bundles");
let builder = context.create_builder();
let i32_type = context.i32_type();
// declare i32 @func(i32)
let fn_type = i32_type.fn_type(&[i32_type.into()], false);
let fn_value = module.add_function("func", fn_type, None);
let basic_block = context.append_basic_block(fn_value, "entry");
builder.position_at_end(basic_block);
// %func_ret = call i32 @func(i32 0) [ "tag"(i32 0) ]
let ret_val = builder.build_direct_call_with_operand_bundles(
fn_value,
&[i32_type.const_zero().into()],
&[OperandBundle::create("tag", &[i32_type.const_zero().into()])],
"func_ret"
)
.unwrap()
.try_as_basic_value()
.unwrap_left();
builder.build_return(Some(&ret_val)).unwrap();
Sourcepub fn build_indirect_call(
&self,
function_type: FunctionType<'ctx>,
function_pointer: PointerValue<'ctx>,
args: &[BasicMetadataValueEnum<'ctx>],
name: &str,
) -> Result<CallSiteValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_indirect_call( &self, function_type: FunctionType<'ctx>, function_pointer: PointerValue<'ctx>, args: &[BasicMetadataValueEnum<'ctx>], name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Call a function pointer. Because a pointer does not carry a type, the type of the function must be specified explicitly.
See Context::create_inline_asm for a practical example. Basic usage looks like this:
use inkwell::context::Context;
// A simple function which calls itself:
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let i32_type = context.i32_type();
let fn_type = i32_type.fn_type(&[i32_type.into()], false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_arg = fn_value.get_first_param().unwrap();
let md_string = context.metadata_string("a metadata");
builder.position_at_end(entry);
let function_pointer = fn_value.as_global_value().as_pointer_value();
let ret_val = builder.build_indirect_call(fn_value.get_type(), function_pointer, &[i32_arg.into(), md_string.into()], "call").unwrap()
.try_as_basic_value()
.left()
.unwrap();
builder.build_return(Some(&ret_val)).unwrap();
Sourcepub fn build_indirect_call_with_operand_bundles(
&self,
function_type: FunctionType<'ctx>,
function_pointer: PointerValue<'ctx>,
args: &[BasicMetadataValueEnum<'ctx>],
operand_bundles: &[OperandBundle<'ctx>],
name: &str,
) -> Result<CallSiteValue<'ctx>, BuilderError>
Available on crate feature llvm18-0
only.
pub fn build_indirect_call_with_operand_bundles( &self, function_type: FunctionType<'ctx>, function_pointer: PointerValue<'ctx>, args: &[BasicMetadataValueEnum<'ctx>], operand_bundles: &[OperandBundle<'ctx>], name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm18-0
only.Build a call instruction to a function pointer, with attached operand bundles.
See Builder::build_direct_call_with_operand_bundles for a usage example with operand bundles.
Sourcepub fn build_invoke(
&self,
function: FunctionValue<'ctx>,
args: &[BasicValueEnum<'ctx>],
then_block: BasicBlock<'ctx>,
catch_block: BasicBlock<'ctx>,
name: &str,
) -> Result<CallSiteValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_invoke( &self, function: FunctionValue<'ctx>, args: &[BasicValueEnum<'ctx>], then_block: BasicBlock<'ctx>, catch_block: BasicBlock<'ctx>, name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.An invoke is similar to a normal function call, but used to call functions that may throw an exception, and then respond to the exception.
When the called function returns normally, the then
block is evaluated next. If instead
the function threw an exception, the catch
block is entered. The first non-phi
instruction of the catch block must be a landingpad
instruction. See also
Builder::build_landing_pad
.
The add_prune_eh_pass
turns an invoke into a call when the called function is
guaranteed to never throw an exception.
This example catches C++ exceptions of type int
, and returns 0
if an exceptions is thrown.
For usage of a cleanup landing pad and the resume
instruction, see Builder::build_resume
use inkwell::context::Context;
use inkwell::AddressSpace;
use inkwell::module::Linkage;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
let f32_type = context.f32_type();
let fn_type = f32_type.fn_type(&[], false);
// we will pretend this function can throw an exception
let function = module.add_function("bomb", fn_type, None);
let basic_block = context.append_basic_block(function, "entry");
builder.position_at_end(basic_block);
let pi = f32_type.const_float(std::f64::consts::PI);
builder.build_return(Some(&pi)).unwrap();
let function2 = module.add_function("wrapper", fn_type, None);
let basic_block2 = context.append_basic_block(function2, "entry");
builder.position_at_end(basic_block2);
let then_block = context.append_basic_block(function2, "then_block");
let catch_block = context.append_basic_block(function2, "catch_block");
let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi").unwrap();
{
builder.position_at_end(then_block);
// in the then_block, the `call_site` value is defined and can be used
let result = call_site.try_as_basic_value().left().unwrap();
builder.build_return(Some(&result)).unwrap();
}
{
builder.position_at_end(catch_block);
// the personality function used by C++
let personality_function = {
let name = "__gxx_personality_v0";
let linkage = Some(Linkage::External);
module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
};
// type of an exception in C++
let ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[ptr_type.into(), i32_type.into()], false);
let null = ptr_type.const_zero();
let res = builder.build_landing_pad(exception_type, personality_function, &[null.into()], false, "res").unwrap();
// we handle the exception by returning a default value
builder.build_return(Some(&f32_type.const_zero())).unwrap();
}
pub fn build_direct_invoke( &self, function: FunctionValue<'ctx>, args: &[BasicValueEnum<'ctx>], then_block: BasicBlock<'ctx>, catch_block: BasicBlock<'ctx>, name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.pub fn build_indirect_invoke( &self, function_type: FunctionType<'ctx>, function_pointer: PointerValue<'ctx>, args: &[BasicValueEnum<'ctx>], then_block: BasicBlock<'ctx>, catch_block: BasicBlock<'ctx>, name: &str, ) -> Result<CallSiteValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Sourcepub fn build_landing_pad<T>(
&self,
exception_type: T,
personality_function: FunctionValue<'ctx>,
clauses: &[BasicValueEnum<'ctx>],
is_cleanup: bool,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>where
T: BasicType<'ctx>,
pub fn build_landing_pad<T>(
&self,
exception_type: T,
personality_function: FunctionValue<'ctx>,
clauses: &[BasicValueEnum<'ctx>],
is_cleanup: bool,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>where
T: BasicType<'ctx>,
Landing pads are places where control flow jumps to if a Builder::build_invoke
triggered an exception.
The landing pad will match the exception against its clauses. Depending on the clause
that is matched, the exception can then be handled, or resumed after some optional cleanup,
causing the exception to bubble up.
Exceptions in LLVM are designed based on the needs of a C++ compiler, but can be used more generally.
Here are some specific examples of landing pads. For a full example of handling an exception, see Builder::build_invoke
.
- cleanup: a cleanup landing pad is always visited when unwinding the stack.
A cleanup is extra code that needs to be run when unwinding a scope. C++ destructors are a typical example.
In a language with reference counting, the cleanup block can decrement the refcount of values in scope.
The
Builder::build_resume
function has a full example using a cleanup lading pad.
use inkwell::context::Context;
use inkwell::AddressSpace;
use inkwell::module::Linkage;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
// type of an exception in C++
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
// the personality function used by C++
let personality_function = {
let name = "__gxx_personality_v0";
let linkage = Some(Linkage::External);
module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
};
// make the cleanup landing pad
let res = builder.build_landing_pad( exception_type, personality_function, &[], true, "res").unwrap();
- catch all: An implementation of the C++
catch(...)
, which catches all exceptions. A catch clause with a NULL pointer value will match anything.
use inkwell::context::Context;
use inkwell::AddressSpace;
use inkwell::module::Linkage;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
// type of an exception in C++
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
// the personality function used by C++
let personality_function = {
let name = "__gxx_personality_v0";
let linkage = Some(Linkage::External);
module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
};
// make a null pointer of type i8
let null = i8_ptr_type.const_zero();
// make the catch all landing pad
let res = builder.build_landing_pad(exception_type, personality_function, &[null.into()], false, "res").unwrap();
- catch a type of exception: Catch a specific type of exception. The example uses C++’s type info.
use inkwell::context::Context;
use inkwell::module::Linkage;
use inkwell::AddressSpace;
use inkwell::values::BasicValue;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
// type of an exception in C++
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
// the personality function used by C++
let personality_function = {
let name = "__gxx_personality_v0";
let linkage = Some(Linkage::External);
module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
};
// link in the C++ type info for the `int` type
let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::default()), "_ZTIi");
type_info_int.set_linkage(Linkage::External);
// make the catch landing pad
let clause = type_info_int.as_basic_value_enum();
let res = builder.build_landing_pad(exception_type, personality_function, &[clause], false, "res").unwrap();
- filter: A filter clause encodes that only some types of exceptions are valid at this point. A filter clause is made by constructing a clause from a constant array.
use inkwell::context::Context;
use inkwell::module::Linkage;
use inkwell::values::AnyValue;
use inkwell::AddressSpace;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
// type of an exception in C++
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
// the personality function used by C++
let personality_function = {
let name = "__gxx_personality_v0";
let linkage = Some(Linkage::External);
module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
};
// link in the C++ type info for the `int` type
let type_info_int = module.add_global(i8_ptr_type, Some(AddressSpace::default()), "_ZTIi");
type_info_int.set_linkage(Linkage::External);
// make the filter landing pad
let filter_pattern = i8_ptr_type.const_array(&[type_info_int.as_any_value_enum().into_pointer_value()]);
let res = builder.build_landing_pad(exception_type, personality_function, &[filter_pattern.into()], false, "res").unwrap();
Sourcepub fn build_resume<V: BasicValue<'ctx>>(
&self,
value: V,
) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_resume<V: BasicValue<'ctx>>( &self, value: V, ) -> Result<InstructionValue<'ctx>, BuilderError>
Resume propagation of an existing (in-flight) exception whose unwinding was interrupted with a landingpad instruction.
This example uses a cleanup landing pad. A cleanup is extra code that needs to be run when unwinding a scope. C++ destructors are a typical example. In a language with reference counting, the cleanup block can decrement the refcount of values in scope.
use inkwell::context::Context;
use inkwell::AddressSpace;
use inkwell::module::Linkage;
let context = Context::create();
let module = context.create_module("sum");
let builder = context.create_builder();
let f32_type = context.f32_type();
let fn_type = f32_type.fn_type(&[], false);
// we will pretend this function can throw an exception
let function = module.add_function("bomb", fn_type, None);
let basic_block = context.append_basic_block(function, "entry");
builder.position_at_end(basic_block);
let pi = f32_type.const_float(std::f64::consts::PI);
builder.build_return(Some(&pi)).unwrap();
let function2 = module.add_function("wrapper", fn_type, None);
let basic_block2 = context.append_basic_block(function2, "entry");
builder.position_at_end(basic_block2);
let then_block = context.append_basic_block(function2, "then_block");
let catch_block = context.append_basic_block(function2, "catch_block");
let call_site = builder.build_invoke(function, &[], then_block, catch_block, "get_pi").unwrap();
{
builder.position_at_end(then_block);
// in the then_block, the `call_site` value is defined and can be used
let result = call_site.try_as_basic_value().left().unwrap();
builder.build_return(Some(&result)).unwrap();
}
{
builder.position_at_end(catch_block);
// the personality function used by C++
let personality_function = {
let name = "__gxx_personality_v0";
let linkage = Some(Linkage::External);
module.add_function(name, context.i64_type().fn_type(&[], false), linkage)
};
// type of an exception in C++
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i8_ptr_type = context.ptr_type(AddressSpace::default());
let i32_type = context.i32_type();
let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);
// make the landing pad; must give a concrete type to the slice
let res = builder.build_landing_pad( exception_type, personality_function, &[], true, "res").unwrap();
// do cleanup ...
builder.build_resume(res).unwrap();
}
Sourcepub unsafe fn build_gep<T: BasicType<'ctx>>(
&self,
pointee_ty: T,
ptr: PointerValue<'ctx>,
ordered_indexes: &[IntValue<'ctx>],
name: &str,
) -> Result<PointerValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub unsafe fn build_gep<T: BasicType<'ctx>>( &self, pointee_ty: T, ptr: PointerValue<'ctx>, ordered_indexes: &[IntValue<'ctx>], name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
Sourcepub unsafe fn build_in_bounds_gep<T: BasicType<'ctx>>(
&self,
pointee_ty: T,
ptr: PointerValue<'ctx>,
ordered_indexes: &[IntValue<'ctx>],
name: &str,
) -> Result<PointerValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub unsafe fn build_in_bounds_gep<T: BasicType<'ctx>>( &self, pointee_ty: T, ptr: PointerValue<'ctx>, ordered_indexes: &[IntValue<'ctx>], name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.GEP is very likely to segfault if indexes are used incorrectly, and is therefore an unsafe function. Maybe we can change this in the future.
Sourcepub fn build_struct_gep<T: BasicType<'ctx>>(
&self,
pointee_ty: T,
ptr: PointerValue<'ctx>,
index: u32,
name: &str,
) -> Result<PointerValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_struct_gep<T: BasicType<'ctx>>( &self, pointee_ty: T, ptr: PointerValue<'ctx>, index: u32, name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Builds a GEP instruction on a struct pointer. Returns Err
BuilderError::GEPPointee
or BuilderError::GEPIndex
if input PointerValue
doesn’t
point to a struct or if index is out of bounds.
§Example
use inkwell::AddressSpace;
use inkwell::context::Context;
let context = Context::create();
let builder = context.create_builder();
let module = context.create_module("struct_gep");
let void_type = context.void_type();
let i32_ty = context.i32_type();
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i32_ptr_ty = context.ptr_type(AddressSpace::default());
let field_types = &[i32_ty.into(), i32_ty.into()];
let struct_ty = context.struct_type(field_types, false);
let struct_ptr_ty = struct_ty.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_ty.into(), struct_ptr_ty.into()], false);
let fn_value = module.add_function("", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
builder.position_at_end(entry);
let i32_ptr = fn_value.get_first_param().unwrap().into_pointer_value();
let struct_ptr = fn_value.get_last_param().unwrap().into_pointer_value();
assert!(builder.build_struct_gep(i32_ty, i32_ptr, 0, "struct_gep").is_err());
assert!(builder.build_struct_gep(i32_ty, i32_ptr, 10, "struct_gep").is_err());
assert!(builder.build_struct_gep(struct_ty, struct_ptr, 0, "struct_gep").is_ok());
assert!(builder.build_struct_gep(struct_ty, struct_ptr, 1, "struct_gep").is_ok());
assert!(builder.build_struct_gep(struct_ty, struct_ptr, 2, "struct_gep").is_err());
Sourcepub fn build_ptr_diff<T: BasicType<'ctx>>(
&self,
pointee_ty: T,
lhs_ptr: PointerValue<'ctx>,
rhs_ptr: PointerValue<'ctx>,
name: &str,
) -> Result<IntValue<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_ptr_diff<T: BasicType<'ctx>>( &self, pointee_ty: T, lhs_ptr: PointerValue<'ctx>, rhs_ptr: PointerValue<'ctx>, name: &str, ) -> Result<IntValue<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Builds an instruction which calculates the difference of two pointers.
§Example
use inkwell::context::Context;
use inkwell::AddressSpace;
// Builds a function which diffs two pointers
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let void_type = context.void_type();
let i32_type = context.i32_type();
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_type.into(), i32_ptr_type.into()], false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_ptr_param1 = fn_value.get_first_param().unwrap().into_pointer_value();
let i32_ptr_param2 = fn_value.get_nth_param(1).unwrap().into_pointer_value();
builder.position_at_end(entry);
builder.build_ptr_diff(i32_ptr_type, i32_ptr_param1, i32_ptr_param2, "diff").unwrap();
builder.build_return(None).unwrap();
pub fn build_phi<T: BasicType<'ctx>>( &self, type_: T, name: &str, ) -> Result<PhiValue<'ctx>, BuilderError>
Sourcepub fn build_store<V: BasicValue<'ctx>>(
&self,
ptr: PointerValue<'ctx>,
value: V,
) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_store<V: BasicValue<'ctx>>( &self, ptr: PointerValue<'ctx>, value: V, ) -> Result<InstructionValue<'ctx>, BuilderError>
Builds a store instruction. It allows you to store a value of type T
in a pointer to a type T
.
§Example
use inkwell::context::Context;
use inkwell::AddressSpace;
// Builds a function which takes an i32 pointer and stores a 7 in it.
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let void_type = context.void_type();
let i32_type = context.i32_type();
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let i32_seven = i32_type.const_int(7, false);
let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value();
builder.position_at_end(entry);
builder.build_store(i32_ptr_param, i32_seven).unwrap();
builder.build_return(None).unwrap();
Sourcepub fn build_load<T: BasicType<'ctx>>(
&self,
pointee_ty: T,
ptr: PointerValue<'ctx>,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>
Available on crate features llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_load<T: BasicType<'ctx>>( &self, pointee_ty: T, ptr: PointerValue<'ctx>, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Builds a load2 instruction. It allows you to retrieve a value of type T
from a pointer to a type T
.
§Example
use inkwell::context::Context;
use inkwell::AddressSpace;
// Builds a function which takes an i32 pointer and returns the pointed at i32.
let context = Context::create();
let module = context.create_module("ret");
let builder = context.create_builder();
let i32_type = context.i32_type();
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = i32_type.fn_type(&[i32_ptr_type.into()], false);
let fn_value = module.add_function("ret", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value();
builder.position_at_end(entry);
let pointee = builder.build_load(i32_type, i32_ptr_param, "load2").unwrap();
builder.build_return(Some(&pointee)).unwrap();
pub fn build_alloca<T: BasicType<'ctx>>( &self, ty: T, name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
pub fn build_array_alloca<T: BasicType<'ctx>>( &self, ty: T, size: IntValue<'ctx>, name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
Sourcepub fn build_memcpy(
&self,
dest: PointerValue<'ctx>,
dest_align_bytes: u32,
src: PointerValue<'ctx>,
src_align_bytes: u32,
size: IntValue<'ctx>,
) -> Result<PointerValue<'ctx>, BuilderError>
Available on crate features llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_memcpy( &self, dest: PointerValue<'ctx>, dest_align_bytes: u32, src: PointerValue<'ctx>, src_align_bytes: u32, size: IntValue<'ctx>, ) -> Result<PointerValue<'ctx>, BuilderError>
llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Build a memcpy instruction.
Alignment arguments are specified in bytes, and should always be both a power of 2 and under 2^64.
The final argument should be a pointer-sized integer.
Returns an Err(BuilderError::AlignmentError)
if the source or destination alignments are not a power of 2.
TargetData::ptr_sized_int_type_in_context
will get you one of those.
Sourcepub fn build_memmove(
&self,
dest: PointerValue<'ctx>,
dest_align_bytes: u32,
src: PointerValue<'ctx>,
src_align_bytes: u32,
size: IntValue<'ctx>,
) -> Result<PointerValue<'ctx>, BuilderError>
Available on crate features llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_memmove( &self, dest: PointerValue<'ctx>, dest_align_bytes: u32, src: PointerValue<'ctx>, src_align_bytes: u32, size: IntValue<'ctx>, ) -> Result<PointerValue<'ctx>, BuilderError>
llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Build a memmove instruction.
Alignment arguments are specified in bytes, and should always be both a power of 2 and under 2^64.
The final argument should be a pointer-sized integer.
Returns an Err(BuilderError::AlignmentError)
if the source or destination alignments are not a power of 2 under 2^64.
TargetData::ptr_sized_int_type_in_context
will get you one of those.
Sourcepub fn build_memset(
&self,
dest: PointerValue<'ctx>,
dest_align_bytes: u32,
val: IntValue<'ctx>,
size: IntValue<'ctx>,
) -> Result<PointerValue<'ctx>, BuilderError>
Available on crate features llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_memset( &self, dest: PointerValue<'ctx>, dest_align_bytes: u32, val: IntValue<'ctx>, size: IntValue<'ctx>, ) -> Result<PointerValue<'ctx>, BuilderError>
llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Build a memset instruction.
Alignment arguments are specified in bytes, and should always be both a power of 2 and under 2^64.
The final argument should be a pointer-sized integer.
Returns an Err(BuilderError::AlignmentError)
if the source alignment is not a power of 2 under 2^64.
TargetData::ptr_sized_int_type_in_context
will get you one of those.
Sourcepub fn build_malloc<T: BasicType<'ctx>>(
&self,
ty: T,
name: &str,
) -> Result<PointerValue<'ctx>, BuilderError>
pub fn build_malloc<T: BasicType<'ctx>>( &self, ty: T, name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
Returns Err(BuilderError::AlignmentError)
if the type is unsized.
Sourcepub fn build_array_malloc<T: BasicType<'ctx>>(
&self,
ty: T,
size: IntValue<'ctx>,
name: &str,
) -> Result<PointerValue<'ctx>, BuilderError>
pub fn build_array_malloc<T: BasicType<'ctx>>( &self, ty: T, size: IntValue<'ctx>, name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
Returns Err(BuilderError::AlignmentError)
if the type is unsized.
pub fn build_free( &self, ptr: PointerValue<'ctx>, ) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn insert_instruction( &self, instruction: &InstructionValue<'ctx>, name: Option<&str>, )
pub fn get_insert_block(&self) -> Option<BasicBlock<'ctx>>
pub fn build_int_unsigned_div<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_signed_div<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_exact_signed_div<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_unsigned_rem<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_signed_rem<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_s_extend<T: IntMathValue<'ctx>>( &self, int_value: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_address_space_cast( &self, ptr_val: PointerValue<'ctx>, ptr_type: PointerType<'ctx>, name: &str, ) -> Result<PointerValue<'ctx>, BuilderError>
Sourcepub fn build_bit_cast<T, V>(
&self,
val: V,
ty: T,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>where
T: BasicType<'ctx>,
V: BasicValue<'ctx>,
pub fn build_bit_cast<T, V>(
&self,
val: V,
ty: T,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>where
T: BasicType<'ctx>,
V: BasicValue<'ctx>,
Builds a bitcast instruction. A bitcast reinterprets the bits of one value into a value of another type which has the same bit width.
§Example
use inkwell::AddressSpace;
use inkwell::context::Context;
let context = Context::create();
let module = context.create_module("bc");
let void_type = context.void_type();
let f32_type = context.f32_type();
let i32_type = context.i32_type();
let arg_types = [i32_type.into()];
let fn_type = void_type.fn_type(&arg_types, false);
let fn_value = module.add_function("bc", fn_type, None);
let builder = context.create_builder();
let entry = context.append_basic_block(fn_value, "entry");
let i32_arg = fn_value.get_first_param().unwrap();
builder.position_at_end(entry);
builder.build_bit_cast(i32_arg, f32_type, "i32tof32").unwrap();
builder.build_return(None).unwrap();
assert!(module.verify().is_ok());
pub fn build_int_s_extend_or_bit_cast<T: IntMathValue<'ctx>>( &self, int_value: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_z_extend<T: IntMathValue<'ctx>>( &self, int_value: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_z_extend_or_bit_cast<T: IntMathValue<'ctx>>( &self, int_value: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_truncate<T: IntMathValue<'ctx>>( &self, int_value: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_truncate_or_bit_cast<T: IntMathValue<'ctx>>( &self, int_value: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_rem<T: FloatMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_to_unsigned_int<T: FloatMathValue<'ctx>>( &self, float: T, int_type: <T::BaseType as FloatMathType<'ctx>>::MathConvType, name: &str, ) -> Result<<<T::BaseType as FloatMathType<'ctx>>::MathConvType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn build_float_to_signed_int<T: FloatMathValue<'ctx>>( &self, float: T, int_type: <T::BaseType as FloatMathType<'ctx>>::MathConvType, name: &str, ) -> Result<<<T::BaseType as FloatMathType<'ctx>>::MathConvType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn build_unsigned_int_to_float<T: IntMathValue<'ctx>>( &self, int: T, float_type: <T::BaseType as IntMathType<'ctx>>::MathConvType, name: &str, ) -> Result<<<T::BaseType as IntMathType<'ctx>>::MathConvType as FloatMathType<'ctx>>::ValueType, BuilderError>
pub fn build_signed_int_to_float<T: IntMathValue<'ctx>>( &self, int: T, float_type: <T::BaseType as IntMathType<'ctx>>::MathConvType, name: &str, ) -> Result<<<T::BaseType as IntMathType<'ctx>>::MathConvType as FloatMathType<'ctx>>::ValueType, BuilderError>
pub fn build_float_trunc<T: FloatMathValue<'ctx>>( &self, float: T, float_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_ext<T: FloatMathValue<'ctx>>( &self, float: T, float_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_cast<T: FloatMathValue<'ctx>>( &self, float: T, float_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_cast<T: IntMathValue<'ctx>>( &self, int: T, int_type: T::BaseType, name: &str, ) -> Result<T, BuilderError>
Sourcepub fn build_int_cast_sign_flag<T: IntMathValue<'ctx>>(
&self,
int: T,
int_type: T::BaseType,
is_signed: bool,
name: &str,
) -> Result<T, BuilderError>
Available on crate features llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn build_int_cast_sign_flag<T: IntMathValue<'ctx>>( &self, int: T, int_type: T::BaseType, is_signed: bool, name: &str, ) -> Result<T, BuilderError>
llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Like build_int_cast
, but respects the signedness of the type being cast to.
pub fn build_float_div<T: FloatMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_add<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nsw_add<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nuw_add<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_add<T: FloatMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_xor<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_and<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_or<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
Sourcepub fn build_left_shift<T: IntMathValue<'ctx>>(
&self,
lhs: T,
rhs: T,
name: &str,
) -> Result<T, BuilderError>
pub fn build_left_shift<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
Builds an IntValue
containing the result of a logical left shift instruction.
§Example
A logical left shift is an operation in which an integer value’s bits are shifted left by N number of positions.
assert_eq!(0b0000_0001 << 0, 0b0000_0001);
assert_eq!(0b0000_0001 << 1, 0b0000_0010);
assert_eq!(0b0000_0011 << 2, 0b0000_1100);
In Rust, a function that could do this for 8bit values looks like:
fn left_shift(value: u8, n: u8) -> u8 {
value << n
}
And in Inkwell, the corresponding function would look roughly like:
use inkwell::context::Context;
// Setup
let context = Context::create();
let module = context.create_module("my_module");
let builder = context.create_builder();
let i8_type = context.i8_type();
let fn_type = i8_type.fn_type(&[i8_type.into(), i8_type.into()], false);
// Function Definition
let function = module.add_function("left_shift", fn_type, None);
let value = function.get_first_param().unwrap().into_int_value();
let n = function.get_nth_param(1).unwrap().into_int_value();
let entry_block = context.append_basic_block(function, "entry");
builder.position_at_end(entry_block);
let shift = builder.build_left_shift(value, n, "left_shift").unwrap(); // value << n
builder.build_return(Some(&shift)).unwrap();
Sourcepub fn build_right_shift<T: IntMathValue<'ctx>>(
&self,
lhs: T,
rhs: T,
sign_extend: bool,
name: &str,
) -> Result<T, BuilderError>
pub fn build_right_shift<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, sign_extend: bool, name: &str, ) -> Result<T, BuilderError>
Builds an IntValue
containing the result of a right shift instruction.
§Example
A right shift is an operation in which an integer value’s bits are shifted right by N number of positions. It may either be logical and have its leftmost N bit(s) filled with zeros or sign extended and filled with ones if the leftmost bit was one.
//fix doc error about overflowing_literals
//rendered rfc: https://github.com/rust-lang/rfcs/blob/master/text/2438-deny-integer-literal-overflow-lint.md
//tracking issue: https://github.com/rust-lang/rust/issues/54502
#![allow(overflowing_literals)]
// Logical Right Shift
assert_eq!(0b1100_0000u8 >> 2, 0b0011_0000);
assert_eq!(0b0000_0010u8 >> 1, 0b0000_0001);
assert_eq!(0b0000_1100u8 >> 2, 0b0000_0011);
// Sign Extended Right Shift
assert_eq!(0b0100_0000i8 >> 2, 0b0001_0000);
assert_eq!(0b1110_0000u8 as i8 >> 1, 0b1111_0000u8 as i8);
assert_eq!(0b1100_0000u8 as i8 >> 2, 0b1111_0000u8 as i8);
In Rust, functions that could do this for 8bit values look like:
fn logical_right_shift(value: u8, n: u8) -> u8 {
value >> n
}
fn sign_extended_right_shift(value: i8, n: u8) -> i8 {
value >> n
}
Notice that, in Rust (and most other languages), whether or not a value is sign extended depends wholly on whether or not the type is signed (ie an i8 is a signed 8 bit value). LLVM does not make this distinction for you.
In Inkwell, the corresponding functions would look roughly like:
use inkwell::context::Context;
// Setup
let context = Context::create();
let module = context.create_module("my_module");
let builder = context.create_builder();
let i8_type = context.i8_type();
let fn_type = i8_type.fn_type(&[i8_type.into(), i8_type.into()], false);
// Function Definition
let function = module.add_function("right_shift", fn_type, None);
let value = function.get_first_param().unwrap().into_int_value();
let n = function.get_nth_param(1).unwrap().into_int_value();
let entry_block = context.append_basic_block(function, "entry");
builder.position_at_end(entry_block);
// Whether or not your right shift is sign extended (true) or logical (false) depends
// on the boolean input parameter:
let shift = builder.build_right_shift(value, n, false, "right_shift").unwrap(); // value >> n
builder.build_return(Some(&shift)).unwrap();
pub fn build_int_sub<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nsw_sub<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nuw_sub<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_sub<T: FloatMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_mul<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nsw_mul<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nuw_mul<T: IntMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_mul<T: FloatMathValue<'ctx>>( &self, lhs: T, rhs: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_binop<T: BasicValue<'ctx>>( &self, op: InstructionOpcode, lhs: T, rhs: T, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
pub fn build_cast<T: BasicType<'ctx>, V: BasicValue<'ctx>>( &self, op: InstructionOpcode, from_value: V, to_type: T, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
pub fn build_pointer_cast<T: PointerMathValue<'ctx>>( &self, from: T, to: T::BaseType, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_compare<T: IntMathValue<'ctx>>( &self, op: IntPredicate, lhs: T, rhs: T, name: &str, ) -> Result<<T::BaseType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn build_float_compare<T: FloatMathValue<'ctx>>( &self, op: FloatPredicate, lhs: T, rhs: T, name: &str, ) -> Result<<<T::BaseType as FloatMathType<'ctx>>::MathConvType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn build_unconditional_branch( &self, destination_block: BasicBlock<'ctx>, ) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_conditional_branch( &self, comparison: IntValue<'ctx>, then_block: BasicBlock<'ctx>, else_block: BasicBlock<'ctx>, ) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_indirect_branch<BV: BasicValue<'ctx>>( &self, address: BV, destinations: &[BasicBlock<'ctx>], ) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_int_neg<T: IntMathValue<'ctx>>( &self, value: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nsw_neg<T: IntMathValue<'ctx>>( &self, value: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_int_nuw_neg<T: IntMathValue<'ctx>>( &self, value: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_float_neg<T: FloatMathValue<'ctx>>( &self, value: T, name: &str, ) -> Result<T, BuilderError>
pub fn build_not<T: IntMathValue<'ctx>>( &self, value: T, name: &str, ) -> Result<T, BuilderError>
Sourcepub fn position_at(
&self,
basic_block: BasicBlock<'ctx>,
instruction: &InstructionValue<'ctx>,
)
pub fn position_at( &self, basic_block: BasicBlock<'ctx>, instruction: &InstructionValue<'ctx>, )
Set the position of the builder to after an instruction.
Be sure to call one of the position_*
methods or all build_*
methods will return Err(BuilderError::UnsetPosition)
.
Sourcepub fn position_before(&self, instruction: &InstructionValue<'ctx>)
pub fn position_before(&self, instruction: &InstructionValue<'ctx>)
Set the position of the builder to before an instruction.
Be sure to call one of the position_*
methods or all build_*
methods will return Err(BuilderError::UnsetPosition)
.
Sourcepub fn position_at_end(&self, basic_block: BasicBlock<'ctx>)
pub fn position_at_end(&self, basic_block: BasicBlock<'ctx>)
Set the position of the builder to the end of a basic block.
Be sure to call one of the position_*
methods or all build_*
methods will return Err(BuilderError::UnsetPosition)
.
Sourcepub fn build_extract_value<AV: AggregateValue<'ctx>>(
&self,
agg: AV,
index: u32,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>
pub fn build_extract_value<AV: AggregateValue<'ctx>>( &self, agg: AV, index: u32, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
Builds an extract value instruction which extracts a BasicValueEnum
from a struct or array.
Returns Err(BuilderError::ExtractOutOfRange)
if the provided index is out of bounds of the aggregate value length.
§Example
use inkwell::context::Context;
use inkwell::builder::BuilderError;
let context = Context::create();
let module = context.create_module("av");
let void_type = context.void_type();
let f32_type = context.f32_type();
let i32_type = context.i32_type();
let struct_type = context.struct_type(&[i32_type.into(), f32_type.into()], false);
let array_type = i32_type.array_type(3);
let fn_type = void_type.fn_type(&[], false);
let fn_value = module.add_function("av_fn", fn_type, None);
let builder = context.create_builder();
let entry = context.append_basic_block(fn_value, "entry");
builder.position_at_end(entry);
let array_alloca = builder.build_alloca(array_type, "array_alloca").unwrap();
#[cfg(any(
feature = "llvm4-0",
feature = "llvm5-0",
feature = "llvm6-0",
feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
feature = "llvm11-0",
feature = "llvm12-0",
feature = "llvm13-0",
feature = "llvm14-0"
))]
let array = builder.build_load(array_alloca, "array_load").unwrap().into_array_value();
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let array = builder.build_load(i32_type, array_alloca, "array_load").unwrap().into_array_value();
let const_int1 = i32_type.const_int(2, false);
let const_int2 = i32_type.const_int(5, false);
let const_int3 = i32_type.const_int(6, false);
assert!(builder.build_insert_value(array, const_int1, 0, "insert").is_ok());
assert!(builder.build_insert_value(array, const_int2, 1, "insert").is_ok());
assert!(builder.build_insert_value(array, const_int3, 2, "insert").is_ok());
assert!(builder.build_insert_value(array, const_int3, 3, "insert").is_err_and(|e| e == BuilderError::ExtractOutOfRange));
assert!(builder.build_extract_value(array, 0, "extract").unwrap().is_int_value());
assert!(builder.build_extract_value(array, 1, "extract").unwrap().is_int_value());
assert!(builder.build_extract_value(array, 2, "extract").unwrap().is_int_value());
assert!(builder.build_extract_value(array, 3, "extract").is_err_and(|e| e == BuilderError::ExtractOutOfRange));
Sourcepub fn build_insert_value<AV, BV>(
&self,
agg: AV,
value: BV,
index: u32,
name: &str,
) -> Result<AggregateValueEnum<'ctx>, BuilderError>where
AV: AggregateValue<'ctx>,
BV: BasicValue<'ctx>,
pub fn build_insert_value<AV, BV>(
&self,
agg: AV,
value: BV,
index: u32,
name: &str,
) -> Result<AggregateValueEnum<'ctx>, BuilderError>where
AV: AggregateValue<'ctx>,
BV: BasicValue<'ctx>,
Builds an insert value instruction which inserts a BasicValue
into a struct
or array and returns the resulting aggregate value.
Returns Err(BuilderError::ExtractOutOfRange)
if the provided index is out of bounds of the aggregate value length.
§Example
use inkwell::context::Context;
use inkwell::builder::BuilderError;
let context = Context::create();
let module = context.create_module("av");
let void_type = context.void_type();
let f32_type = context.f32_type();
let i32_type = context.i32_type();
let struct_type = context.struct_type(&[i32_type.into(), f32_type.into()], false);
let array_type = i32_type.array_type(3);
let fn_type = void_type.fn_type(&[], false);
let fn_value = module.add_function("av_fn", fn_type, None);
let builder = context.create_builder();
let entry = context.append_basic_block(fn_value, "entry");
builder.position_at_end(entry);
let array_alloca = builder.build_alloca(array_type, "array_alloca").unwrap();
#[cfg(any(
feature = "llvm4-0",
feature = "llvm5-0",
feature = "llvm6-0",
feature = "llvm7-0",
feature = "llvm8-0",
feature = "llvm9-0",
feature = "llvm10-0",
feature = "llvm11-0",
feature = "llvm12-0",
feature = "llvm13-0",
feature = "llvm14-0"
))]
let array = builder.build_load(array_alloca, "array_load").unwrap().into_array_value();
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let array = builder.build_load(i32_type, array_alloca, "array_load").unwrap().into_array_value();
let const_int1 = i32_type.const_int(2, false);
let const_int2 = i32_type.const_int(5, false);
let const_int3 = i32_type.const_int(6, false);
assert!(builder.build_insert_value(array, const_int1, 0, "insert").is_ok());
assert!(builder.build_insert_value(array, const_int2, 1, "insert").is_ok());
assert!(builder.build_insert_value(array, const_int3, 2, "insert").is_ok());
assert!(builder.build_insert_value(array, const_int3, 3, "insert").is_err_and(|e| e == BuilderError::ExtractOutOfRange));
Sourcepub fn build_extract_element<V: VectorBaseValue<'ctx>>(
&self,
vector: V,
index: IntValue<'ctx>,
name: &str,
) -> Result<BasicValueEnum<'ctx>, BuilderError>
pub fn build_extract_element<V: VectorBaseValue<'ctx>>( &self, vector: V, index: IntValue<'ctx>, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
Builds an extract element instruction which extracts a BasicValueEnum
from a vector.
§Example
use inkwell::context::Context;
let context = Context::create();
let module = context.create_module("av");
let i32_type = context.i32_type();
let i32_zero = i32_type.const_int(0, false);
let vec_type = i32_type.vec_type(2);
let fn_type = i32_type.fn_type(&[vec_type.into()], false);
let fn_value = module.add_function("vec_fn", fn_type, None);
let builder = context.create_builder();
let entry = context.append_basic_block(fn_value, "entry");
let vector_param = fn_value.get_first_param().unwrap().into_vector_value();
builder.position_at_end(entry);
let extracted = builder.build_extract_element(vector_param, i32_zero, "insert").unwrap();
builder.build_return(Some(&extracted)).unwrap();
Sourcepub fn build_insert_element<V: BasicValue<'ctx>, W: VectorBaseValue<'ctx>>(
&self,
vector: W,
element: V,
index: IntValue<'ctx>,
name: &str,
) -> Result<W, BuilderError>
pub fn build_insert_element<V: BasicValue<'ctx>, W: VectorBaseValue<'ctx>>( &self, vector: W, element: V, index: IntValue<'ctx>, name: &str, ) -> Result<W, BuilderError>
Builds an insert element instruction which inserts a BasicValue
into a vector
and returns the resulting vector.
§Example
use inkwell::context::Context;
let context = Context::create();
let module = context.create_module("av");
let void_type = context.void_type();
let i32_type = context.i32_type();
let i32_zero = i32_type.const_int(0, false);
let i32_seven = i32_type.const_int(7, false);
let vec_type = i32_type.vec_type(2);
let fn_type = void_type.fn_type(&[vec_type.into()], false);
let fn_value = module.add_function("vec_fn", fn_type, None);
let builder = context.create_builder();
let entry = context.append_basic_block(fn_value, "entry");
let vector_param = fn_value.get_first_param().unwrap().into_vector_value();
builder.position_at_end(entry);
builder.build_insert_element(vector_param, i32_seven, i32_zero, "insert").unwrap();
builder.build_return(None).unwrap();
pub fn build_unreachable(&self) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_fence( &self, atomic_ordering: AtomicOrdering, num: i32, name: &str, ) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_is_null<T: PointerMathValue<'ctx>>( &self, ptr: T, name: &str, ) -> Result<<<T::BaseType as PointerMathType<'ctx>>::PtrConvType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn build_is_not_null<T: PointerMathValue<'ctx>>( &self, ptr: T, name: &str, ) -> Result<<<T::BaseType as PointerMathType<'ctx>>::PtrConvType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn build_int_to_ptr<T: IntMathValue<'ctx>>( &self, int: T, ptr_type: <T::BaseType as IntMathType<'ctx>>::PtrConvType, name: &str, ) -> Result<<<T::BaseType as IntMathType<'ctx>>::PtrConvType as PointerMathType<'ctx>>::ValueType, BuilderError>
pub fn build_ptr_to_int<T: PointerMathValue<'ctx>>( &self, ptr: T, int_type: <T::BaseType as PointerMathType<'ctx>>::PtrConvType, name: &str, ) -> Result<<<T::BaseType as PointerMathType<'ctx>>::PtrConvType as IntMathType<'ctx>>::ValueType, BuilderError>
pub fn clear_insertion_position(&self)
pub fn build_switch( &self, value: IntValue<'ctx>, else_block: BasicBlock<'ctx>, cases: &[(IntValue<'ctx>, BasicBlock<'ctx>)], ) -> Result<InstructionValue<'ctx>, BuilderError>
pub fn build_select<BV: BasicValue<'ctx>, IMV: IntMathValue<'ctx>>( &self, condition: IMV, then: BV, else_: BV, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
pub unsafe fn build_global_string( &self, value: &str, name: &str, ) -> Result<GlobalValue<'ctx>, BuilderError>
pub fn build_global_string_ptr( &self, value: &str, name: &str, ) -> Result<GlobalValue<'ctx>, BuilderError>
pub fn build_shuffle_vector<V: VectorBaseValue<'ctx>>( &self, left: V, right: V, mask: V, name: &str, ) -> Result<V, BuilderError>
pub fn build_va_arg<BT: BasicType<'ctx>>( &self, list: PointerValue<'ctx>, type_: BT, name: &str, ) -> Result<BasicValueEnum<'ctx>, BuilderError>
Sourcepub fn build_atomicrmw(
&self,
op: AtomicRMWBinOp,
ptr: PointerValue<'ctx>,
value: IntValue<'ctx>,
ordering: AtomicOrdering,
) -> Result<IntValue<'ctx>, BuilderError>
pub fn build_atomicrmw( &self, op: AtomicRMWBinOp, ptr: PointerValue<'ctx>, value: IntValue<'ctx>, ordering: AtomicOrdering, ) -> Result<IntValue<'ctx>, BuilderError>
Builds an atomicrmw instruction. It allows you to atomically modify memory.
May return of the following errors:
Err(BuilderError::BitwidthError)
if the bitwidth of the value is not a power of 2 and less than 8Err(BuilderError:PointeeTypeMismatch)
if the pointee type does not match the value’s type
§Example
use inkwell::context::Context;
use inkwell::{AddressSpace, AtomicOrdering, AtomicRMWBinOp};
let context = Context::create();
let module = context.create_module("rmw");
let void_type = context.void_type();
let i32_type = context.i32_type();
let i32_seven = i32_type.const_int(7, false);
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
let fn_value = module.add_function("rmw", fn_type, None);
let entry = context.append_basic_block(fn_value, "entry");
let i32_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value();
let builder = context.create_builder();
builder.position_at_end(entry);
builder.build_atomicrmw(AtomicRMWBinOp::Add, i32_ptr_param, i32_seven, AtomicOrdering::Unordered).unwrap();
builder.build_return(None).unwrap();
Sourcepub fn build_cmpxchg<V: BasicValue<'ctx>>(
&self,
ptr: PointerValue<'ctx>,
cmp: V,
new: V,
success: AtomicOrdering,
failure: AtomicOrdering,
) -> Result<StructValue<'ctx>, BuilderError>
pub fn build_cmpxchg<V: BasicValue<'ctx>>( &self, ptr: PointerValue<'ctx>, cmp: V, new: V, success: AtomicOrdering, failure: AtomicOrdering, ) -> Result<StructValue<'ctx>, BuilderError>
Builds a cmpxchg instruction. It allows you to atomically compare and replace memory.
May return one of the following errors:
Err(BuilderError::PointeeTypeMismatch)
if the pointer does not point to an element of the value typeErr(BuilderError::ValueTypeMismatch)
if the value to compare and the new values are not of the same type, or if the value does not have a pointer or integer typeErr(BuilderError::OrderingError)
if the following conditions are not satisfied:- Both success and failure orderings are not Monotonic or stronger
- The failure ordering is stronger than the success ordering
- The failure ordering is release or acquire release
§Example
use inkwell::context::Context;
use inkwell::{AddressSpace, AtomicOrdering};
let context = Context::create();
let module = context.create_module("cmpxchg");
let void_type = context.void_type();
let i32_type = context.i32_type();
#[cfg(not(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0")))]
let i32_ptr_type = i32_type.ptr_type(AddressSpace::default());
#[cfg(any(feature = "llvm15-0", feature = "llvm16-0", feature = "llvm17-0", feature = "llvm18-0"))]
let i32_ptr_type = context.ptr_type(AddressSpace::default());
let fn_type = void_type.fn_type(&[i32_ptr_type.into()], false);
let fn_value = module.add_function("", fn_type, None);
let i32_ptr_param = fn_value.get_first_param().unwrap().into_pointer_value();
let i32_seven = i32_type.const_int(7, false);
let i32_eight = i32_type.const_int(8, false);
let entry = context.append_basic_block(fn_value, "entry");
let builder = context.create_builder();
builder.position_at_end(entry);
builder.build_cmpxchg(i32_ptr_param, i32_seven, i32_eight, AtomicOrdering::AcquireRelease, AtomicOrdering::Monotonic).unwrap();
builder.build_return(None).unwrap();
Sourcepub fn set_current_debug_location(&self, location: DILocation<'ctx>)
Available on crate features llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn set_current_debug_location(&self, location: DILocation<'ctx>)
llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Set the debug info source location of the instruction currently pointed at by the builder
Sourcepub fn get_current_debug_location(&self) -> Option<DILocation<'ctx>>
Available on crate features llvm7-0
or llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn get_current_debug_location(&self) -> Option<DILocation<'ctx>>
llvm7-0
or llvm8-0
or llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Get the debug info source location of the instruction currently pointed at by the builder, if available.
Sourcepub fn unset_current_debug_location(&self)
Available on crate features llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.
pub fn unset_current_debug_location(&self)
llvm9-0
or llvm10-0
or llvm11-0
or llvm12-0
or llvm13-0
or llvm14-0
or llvm15-0
or llvm16-0
or llvm17-0
or llvm18-0
only.Unset the debug info source location of the instruction currently pointed at by the builder. If there isn’t any debug info, this is a no-op.
Trait Implementations§
Auto Trait Implementations§
impl<'ctx> !Freeze for Builder<'ctx>
impl<'ctx> !RefUnwindSafe for Builder<'ctx>
impl<'ctx> !Send for Builder<'ctx>
impl<'ctx> !Sync for Builder<'ctx>
impl<'ctx> Unpin for Builder<'ctx>
impl<'ctx> UnwindSafe for Builder<'ctx>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more