Struct inkwell::builder::Builder[][src]

pub struct Builder<'ctx> { /* fields omitted */ }

Implementations

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));

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()]);

Builds a function call instruction. FunctionValues can be implicitly converted into a CallableValue. See CallableValue for details on calling a PointerValue that points to a function.

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();

builder.position_at_end(entry);

let ret_val = builder.build_call(fn_value, &[i32_arg], "call")
    .try_as_basic_value()
    .left()
    .unwrap();

builder.build_return(Some(&ret_val));

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));

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");

{
    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));
}

{
    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 i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic);
    let i32_type = context.i32_type();
    let exception_type = context.struct_type(&[i8_ptr_type.into(), i32_type.into()], false);

    let null = i8_ptr_type.const_zero();
    let res = builder.build_landing_pad(exception_type, personality_function, &[null.into()], false, "res");

    // we handle the exception by returning a default value
    builder.build_return(Some(&f32_type.const_zero()));
}

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++
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
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");
  • 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++
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
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");
  • 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++
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
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::Generic), "_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");
  • 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++
let i8_ptr_type = context.i8_type().ptr_type(AddressSpace::Generic);
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::Generic), "_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");

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));

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");

{
    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));
}

{
    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 i8_ptr_type = context.i32_type().ptr_type(AddressSpace::Generic);
    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");

    // do cleanup ...

    builder.build_resume(res);
}

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.

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.

Builds a GEP instruction on a struct pointer. Returns Err(()) 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();
let i32_ptr_ty = i32_ty.ptr_type(AddressSpace::Generic);
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::Generic);
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_ptr, 0, "struct_gep").is_err());
assert!(builder.build_struct_gep(i32_ptr, 10, "struct_gep").is_err());
assert!(builder.build_struct_gep(struct_ptr, 0, "struct_gep").is_ok());
assert!(builder.build_struct_gep(struct_ptr, 1, "struct_gep").is_ok());
assert!(builder.build_struct_gep(struct_ptr, 2, "struct_gep").is_err());

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();
let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic);
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_param1, i32_ptr_param2, "diff");
builder.build_return(None);

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();
let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic);
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);
builder.build_return(None);

Builds a load 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();
let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic);
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_ptr_param, "load");

builder.build_return(Some(&pointee));
This is supported on crate features llvm8-0 or llvm9-0 or llvm10-0 or llvm11-0 or llvm12-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.

TargetData::ptr_sized_int_type_in_context will get you one of those.

This is supported on crate features llvm8-0 or llvm9-0 or llvm10-0 or llvm11-0 or llvm12-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.

TargetData::ptr_sized_int_type_in_context will get you one of those.

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::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_bitcast(i32_arg, f32_type, "i32tof32");
builder.build_return(None);

assert!(module.verify().is_ok());

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"); // value << n

builder.build_return(Some(&shift));

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"); // value >> n

builder.build_return(Some(&shift));

Builds an extract value instruction which extracts a BasicValueEnum from a struct or array.

Example

use inkwell::context::Context;

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");
let array = builder.build_load(array_alloca, "array_load").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_some());
assert!(builder.build_insert_value(array, const_int2, 1, "insert").is_some());
assert!(builder.build_insert_value(array, const_int3, 2, "insert").is_some());
assert!(builder.build_insert_value(array, const_int3, 3, "insert").is_none());

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_none());

Builds an insert value instruction which inserts a BasicValue into a struct or array and returns the resulting aggregate value.

Example

use inkwell::context::Context;

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");
let array = builder.build_load(array_alloca, "array_load").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_some());
assert!(builder.build_insert_value(array, const_int2, 1, "insert").is_some());
assert!(builder.build_insert_value(array, const_int3, 2, "insert").is_some());
assert!(builder.build_insert_value(array, const_int3, 3, "insert").is_none());

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");

builder.build_return(Some(&extracted));

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");
builder.build_return(None);

Builds an atomicrmw instruction. It allows you to atomically modify memory.

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);
let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic);
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);
builder.build_return(None);
This is supported on crate features llvm3-9 or llvm4-0 or llvm5-0 or llvm6-0 or llvm7-0 or llvm8-0 or llvm9-0 or llvm10-0 or llvm11-0 or llvm12-0 only.

Builds a cmpxchg instruction. It allows you to atomically compare and replace memory.

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();
let i32_ptr_type = i32_type.ptr_type(AddressSpace::Generic);
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);
builder.build_return(None);
This is supported on crate features llvm7-0 or llvm8-0 or llvm9-0 or llvm10-0 or llvm11-0 or llvm12-0 only.

Set the debug info source location of the instruction currently pointed at by the builder

This is supported on crate features llvm7-0 or llvm8-0 or llvm9-0 or llvm10-0 or llvm11-0 or llvm12-0 only.

Get the debug info source location of the instruction currently pointed at by the builder, if available.

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

Formats the value using the given formatter. Read more

Executes the destructor for this type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.