use either::{Either, Left, Right};
use llvm_sys::core::{LLVMBuildAdd, LLVMBuildAlloca, LLVMBuildAnd, LLVMBuildArrayAlloca, LLVMBuildArrayMalloc, LLVMBuildAtomicRMW, LLVMBuildBr, LLVMBuildCall, LLVMBuildCast, LLVMBuildCondBr, LLVMBuildExtractValue, LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFDiv, LLVMBuildFence, LLVMBuildFMul, LLVMBuildFNeg, LLVMBuildFree, LLVMBuildFSub, LLVMBuildGEP, LLVMBuildICmp, LLVMBuildInsertValue, LLVMBuildIsNotNull, LLVMBuildIsNull, LLVMBuildLoad, LLVMBuildMalloc, LLVMBuildMul, LLVMBuildNeg, LLVMBuildNot, LLVMBuildOr, LLVMBuildPhi, LLVMBuildPointerCast, LLVMBuildRet, LLVMBuildRetVoid, LLVMBuildStore, LLVMBuildSub, LLVMBuildUDiv, LLVMBuildUnreachable, LLVMBuildXor, LLVMDisposeBuilder, LLVMGetElementType, LLVMGetInsertBlock, LLVMGetReturnType, LLVMGetTypeKind, LLVMInsertIntoBuilder, LLVMPositionBuilderAtEnd, LLVMTypeOf, LLVMBuildExtractElement, LLVMBuildInsertElement, LLVMBuildIntToPtr, LLVMBuildPtrToInt, LLVMInsertIntoBuilderWithName, LLVMClearInsertionPosition, LLVMCreateBuilder, LLVMPositionBuilder, LLVMPositionBuilderBefore, LLVMBuildAggregateRet, LLVMBuildStructGEP, LLVMBuildInBoundsGEP, LLVMBuildPtrDiff, LLVMBuildNSWAdd, LLVMBuildNUWAdd, LLVMBuildNSWSub, LLVMBuildNUWSub, LLVMBuildNSWMul, LLVMBuildNUWMul, LLVMBuildSDiv, LLVMBuildSRem, LLVMBuildURem, LLVMBuildFRem, LLVMBuildNSWNeg, LLVMBuildNUWNeg, LLVMBuildFPToUI, LLVMBuildFPToSI, LLVMBuildSIToFP, LLVMBuildUIToFP, LLVMBuildFPTrunc, LLVMBuildFPExt, LLVMBuildIntCast, LLVMBuildFPCast, LLVMBuildSExtOrBitCast, LLVMBuildZExtOrBitCast, LLVMBuildTruncOrBitCast, LLVMBuildSwitch, LLVMAddCase, LLVMBuildShl, LLVMBuildAShr, LLVMBuildLShr, LLVMBuildGlobalString, LLVMBuildGlobalStringPtr, LLVMBuildExactSDiv, LLVMBuildTrunc, LLVMBuildSExt, LLVMBuildZExt, LLVMBuildSelect, LLVMBuildAddrSpaceCast, LLVMBuildBitCast, LLVMBuildShuffleVector, LLVMBuildVAArg, LLVMBuildIndirectBr, LLVMAddDestination};
#[llvm_versions(3.9..=latest)]
use llvm_sys::core::LLVMBuildAtomicCmpXchg;
use llvm_sys::prelude::{LLVMBuilderRef, LLVMValueRef};
use llvm_sys::{LLVMTypeKind};
use crate::{AtomicOrdering, AtomicRMWBinOp, IntPredicate, FloatPredicate};
use crate::basic_block::BasicBlock;
use crate::values::{AggregateValue, AggregateValueEnum, AsValueRef, BasicValue, BasicValueEnum, PhiValue, FunctionValue, IntValue, PointerValue, StructValue, VectorValue, InstructionValue, GlobalValue, IntMathValue, FloatMathValue, PointerMathValue, InstructionOpcode, CallSiteValue};
use crate::types::{AsTypeRef, BasicType, IntMathType, FloatMathType, PointerType, PointerMathType};
use std::ffi::CString;
#[derive(Debug)]
pub struct Builder {
builder: LLVMBuilderRef,
}
impl Builder {
pub(crate) fn new(builder: LLVMBuilderRef) -> Self {
debug_assert!(!builder.is_null());
Builder {
builder: builder
}
}
pub fn create() -> Self {
let builder = unsafe {
LLVMCreateBuilder()
};
Builder::new(builder)
}
pub fn build_return(&self, value: Option<&dyn BasicValue>) -> InstructionValue {
let value = unsafe {
value.map_or_else(|| LLVMBuildRetVoid(self.builder), |value| LLVMBuildRet(self.builder, value.as_value_ref()))
};
InstructionValue::new(value)
}
pub fn build_aggregate_return(&self, values: &[BasicValueEnum]) -> InstructionValue {
let mut args: Vec<LLVMValueRef> = values.iter()
.map(|val| val.as_value_ref())
.collect();
let value = unsafe {
LLVMBuildAggregateRet(self.builder, args.as_mut_ptr(), args.len() as u32)
};
InstructionValue::new(value)
}
pub fn build_call<F>(&self, function: F, args: &[BasicValueEnum], name: &str) -> CallSiteValue
where
F: Into<FunctionOrPointerValue>,
{
let fn_val_ref = match function.into() {
Left(val) => val.as_value_ref(),
Right(val) => {
let value_ref = val.as_value_ref();
let ty_kind = unsafe { LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(value_ref))) };
let is_a_fn_ptr = match ty_kind {
LLVMTypeKind::LLVMFunctionTypeKind => true,
_ => false,
};
assert!(is_a_fn_ptr, "build_call called with a pointer which is not a function pointer");
value_ref
},
};
let name = unsafe {
match LLVMGetTypeKind(LLVMGetReturnType(LLVMGetElementType(LLVMTypeOf(fn_val_ref)))) {
LLVMTypeKind::LLVMVoidTypeKind => "",
_ => name,
}
};
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let mut args: Vec<LLVMValueRef> = args.iter()
.map(|val| val.as_value_ref())
.collect();
let value = unsafe {
LLVMBuildCall(self.builder, fn_val_ref, args.as_mut_ptr(), args.len() as u32, c_string.as_ptr())
};
CallSiteValue::new(value)
}
pub unsafe fn build_gep(&self, ptr: PointerValue, ordered_indexes: &[IntValue], name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let mut index_values: Vec<LLVMValueRef> = ordered_indexes.iter()
.map(|val| val.as_value_ref())
.collect();
let value = LLVMBuildGEP(self.builder, ptr.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, c_string.as_ptr());
PointerValue::new(value)
}
pub unsafe fn build_in_bounds_gep(&self, ptr: PointerValue, ordered_indexes: &[IntValue], name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let mut index_values: Vec<LLVMValueRef> = ordered_indexes.iter()
.map(|val| val.as_value_ref())
.collect();
let value = LLVMBuildInBoundsGEP(self.builder, ptr.as_value_ref(), index_values.as_mut_ptr(), index_values.len() as u32, c_string.as_ptr());
PointerValue::new(value)
}
pub unsafe fn build_struct_gep(&self, ptr: PointerValue, index: u32, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = LLVMBuildStructGEP(self.builder, ptr.as_value_ref(), index, c_string.as_ptr());
PointerValue::new(value)
}
pub fn build_ptr_diff(&self, lhs_ptr: PointerValue, rhs_ptr: PointerValue, name: &str) -> IntValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildPtrDiff(self.builder, lhs_ptr.as_value_ref(), rhs_ptr.as_value_ref(), c_string.as_ptr())
};
IntValue::new(value)
}
pub fn build_phi<T: BasicType>(&self, type_: T, name: &str) -> PhiValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildPhi(self.builder, type_.as_type_ref(), c_string.as_ptr())
};
PhiValue::new(value)
}
pub fn build_store<V: BasicValue>(&self, ptr: PointerValue, value: V) -> InstructionValue {
let value = unsafe {
LLVMBuildStore(self.builder, value.as_value_ref(), ptr.as_value_ref())
};
InstructionValue::new(value)
}
pub fn build_load(&self, ptr: PointerValue, name: &str) -> BasicValueEnum {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildLoad(self.builder, ptr.as_value_ref(), c_string.as_ptr())
};
BasicValueEnum::new(value)
}
pub fn build_alloca<T: BasicType>(&self, ty: T, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildAlloca(self.builder, ty.as_type_ref(), c_string.as_ptr())
};
PointerValue::new(value)
}
pub fn build_array_alloca<T: BasicType>(&self, ty: T, size: IntValue, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildArrayAlloca(self.builder, ty.as_type_ref(), size.as_value_ref(), c_string.as_ptr())
};
PointerValue::new(value)
}
pub fn build_malloc<T: BasicType>(&self, ty: T, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildMalloc(self.builder, ty.as_type_ref(), c_string.as_ptr())
};
PointerValue::new(value)
}
pub fn build_array_malloc<T: BasicType>(&self, ty: T, size: IntValue, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildArrayMalloc(self.builder, ty.as_type_ref(), size.as_value_ref(), c_string.as_ptr())
};
PointerValue::new(value)
}
pub fn build_free(&self, ptr: PointerValue) -> InstructionValue {
let val = unsafe {
LLVMBuildFree(self.builder, ptr.as_value_ref())
};
InstructionValue::new(val)
}
pub fn insert_instruction(&self, instruction: &InstructionValue, name: Option<&str>) {
match name {
Some(name) => {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
unsafe {
LLVMInsertIntoBuilderWithName(self.builder, instruction.as_value_ref(), c_string.as_ptr())
}
},
None => unsafe {
LLVMInsertIntoBuilder(self.builder, instruction.as_value_ref());
},
}
}
pub fn get_insert_block(&self) -> Option<BasicBlock> {
let bb = unsafe {
LLVMGetInsertBlock(self.builder)
};
BasicBlock::new(bb)
}
pub fn build_int_unsigned_div<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildUDiv(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_signed_div<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSDiv(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_exact_signed_div<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildExactSDiv(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_unsigned_rem<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildURem(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_signed_rem<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSRem(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_s_extend<T: IntMathValue>(&self, int_value: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSExt(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_address_space_cast(&self, ptr_val: PointerValue, ptr_type: PointerType, name: &str) -> PointerValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildAddrSpaceCast(self.builder, ptr_val.as_value_ref(), ptr_type.as_type_ref(), c_string.as_ptr())
};
PointerValue::new(value)
}
pub fn build_bitcast<T, V>(&self, val: V, ty: T, name: &str) -> BasicValueEnum
where
T: BasicType,
V: BasicValue,
{
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildBitCast(self.builder, val.as_value_ref(), ty.as_type_ref(), c_string.as_ptr())
};
BasicValueEnum::new(value)
}
pub fn build_int_s_extend_or_bit_cast<T: IntMathValue>(&self, int_value: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSExtOrBitCast(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_z_extend<T: IntMathValue>(&self, int_value: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildZExt(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_z_extend_or_bit_cast<T: IntMathValue>(&self, int_value: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildZExtOrBitCast(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_truncate<T: IntMathValue>(&self, int_value: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildTrunc(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_truncate_or_bit_cast<T: IntMathValue>(&self, int_value: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildTruncOrBitCast(self.builder, int_value.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_rem<T: FloatMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFRem(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_to_unsigned_int<T: FloatMathValue>(&self, float: T, int_type: <T::BaseType as FloatMathType>::MathConvType, name: &str) -> <<T::BaseType as FloatMathType>::MathConvType as IntMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFPToUI(self.builder, float.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
<<T::BaseType as FloatMathType>::MathConvType as IntMathType>::ValueType::new(value)
}
pub fn build_float_to_signed_int<T: FloatMathValue>(&self, float: T, int_type: <T::BaseType as FloatMathType>::MathConvType, name: &str) -> <<T::BaseType as FloatMathType>::MathConvType as IntMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFPToSI(self.builder, float.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
<<T::BaseType as FloatMathType>::MathConvType as IntMathType>::ValueType::new(value)
}
pub fn build_unsigned_int_to_float<T: IntMathValue>(&self, int: T, float_type: <T::BaseType as IntMathType>::MathConvType, name: &str) -> <<T::BaseType as IntMathType>::MathConvType as FloatMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildUIToFP(self.builder, int.as_value_ref(), float_type.as_type_ref(), c_string.as_ptr())
};
<<T::BaseType as IntMathType>::MathConvType as FloatMathType>::ValueType::new(value)
}
pub fn build_signed_int_to_float<T: IntMathValue>(&self, int: T, float_type: <T::BaseType as IntMathType>::MathConvType, name: &str) -> <<T::BaseType as IntMathType>::MathConvType as FloatMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSIToFP(self.builder, int.as_value_ref(), float_type.as_type_ref(), c_string.as_ptr())
};
<<T::BaseType as IntMathType>::MathConvType as FloatMathType>::ValueType::new(value)
}
pub fn build_float_trunc<T: FloatMathValue>(&self, float: T, float_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFPTrunc(self.builder, float.as_value_ref(), float_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_ext<T: FloatMathValue>(&self, float: T, float_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFPExt(self.builder, float.as_value_ref(), float_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_cast<T: FloatMathValue>(&self, float: T, float_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFPCast(self.builder, float.as_value_ref(), float_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_cast<T: IntMathValue>(&self, int: T, int_type: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildIntCast(self.builder, int.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_div<T: FloatMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFDiv(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_add<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildAdd(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nsw_add<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNSWAdd(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nuw_add<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNUWAdd(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_add<T: FloatMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFAdd(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_xor<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildXor(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_and<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildAnd(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_or<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildOr(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_left_shift<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildShl(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_right_shift<T: IntMathValue>(&self, lhs: T, rhs: T, sign_extend: bool, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
if sign_extend {
LLVMBuildAShr(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
} else {
LLVMBuildLShr(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
}
};
T::new(value)
}
pub fn build_int_sub<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSub(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nsw_sub<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNSWSub(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nuw_sub<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNUWSub(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_sub<T: FloatMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFSub(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_mul<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildMul(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nsw_mul<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNSWMul(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nuw_mul<T: IntMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNUWMul(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_mul<T: FloatMathValue>(&self, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFMul(self.builder, lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_cast<T: BasicType, V: BasicValue>(&self, op: InstructionOpcode, from_value: V, to_type: T, name: &str) -> BasicValueEnum {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildCast(self.builder, op.into(), from_value.as_value_ref(), to_type.as_type_ref(), c_string.as_ptr())
};
BasicValueEnum::new(value)
}
pub fn build_pointer_cast<T: PointerMathValue>(&self, from: T, to: T::BaseType, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildPointerCast(self.builder, from.as_value_ref(), to.as_type_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_compare<T: IntMathValue>(&self, op: IntPredicate, lhs: T, rhs: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildICmp(self.builder, op.as_llvm_enum(), lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_compare<T: FloatMathValue>(&self, op: FloatPredicate, lhs: T, rhs: T, name: &str) -> <<T::BaseType as FloatMathType>::MathConvType as IntMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFCmp(self.builder, op.as_llvm_enum(), lhs.as_value_ref(), rhs.as_value_ref(), c_string.as_ptr())
};
<<T::BaseType as FloatMathType>::MathConvType as IntMathType>::ValueType::new(value)
}
pub fn build_unconditional_branch(&self, destination_block: &BasicBlock) -> InstructionValue {
let value = unsafe {
LLVMBuildBr(self.builder, destination_block.basic_block)
};
InstructionValue::new(value)
}
pub fn build_conditional_branch(&self, comparison: IntValue, then_block: &BasicBlock, else_block: &BasicBlock) -> InstructionValue {
let value = unsafe {
LLVMBuildCondBr(self.builder, comparison.as_value_ref(), then_block.basic_block, else_block.basic_block)
};
InstructionValue::new(value)
}
pub fn build_indirect_branch<BV: BasicValue>(&self, address: BV, destinations: &[&BasicBlock]) -> InstructionValue {
let value = unsafe {
LLVMBuildIndirectBr(self.builder, address.as_value_ref(), destinations.len() as u32)
};
for destination in destinations {
unsafe {
LLVMAddDestination(value, destination.basic_block)
}
}
InstructionValue::new(value)
}
pub fn build_int_neg<T: IntMathValue>(&self, value: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNeg(self.builder, value.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nsw_neg<T: IntMathValue>(&self, value: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNSWNeg(self.builder, value.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_int_nuw_neg<T: IntMathValue>(&self, value: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNUWNeg(self.builder, value.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_float_neg<T: FloatMathValue>(&self, value: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildFNeg(self.builder, value.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn build_not<T: IntMathValue>(&self, value: T, name: &str) -> T {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildNot(self.builder, value.as_value_ref(), c_string.as_ptr())
};
T::new(value)
}
pub fn position_at(&self, basic_block: &BasicBlock, instruction: &InstructionValue) {
unsafe {
LLVMPositionBuilder(self.builder, basic_block.basic_block, instruction.as_value_ref())
}
}
pub fn position_before(&self, instruction: &InstructionValue) {
unsafe {
LLVMPositionBuilderBefore(self.builder, instruction.as_value_ref())
}
}
pub fn position_at_end(&self, basic_block: &BasicBlock) {
unsafe {
LLVMPositionBuilderAtEnd(self.builder, basic_block.basic_block);
}
}
pub fn build_extract_value<AV: AggregateValue>(&self, agg: AV, index: u32, name: &str) -> Option<BasicValueEnum> {
let size = match agg.as_aggregate_value_enum() {
AggregateValueEnum::ArrayValue(av) => av.get_type().len(),
AggregateValueEnum::StructValue(sv) => sv.get_type().count_fields(),
};
if index >= size {
return None;
}
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildExtractValue(self.builder, agg.as_value_ref(), index, c_string.as_ptr())
};
Some(BasicValueEnum::new(value))
}
pub fn build_insert_value<AV, BV>(&self, agg: AV, value: BV, index: u32, name: &str) -> Option<AggregateValueEnum>
where
AV: AggregateValue,
BV: BasicValue,
{
let size = match agg.as_aggregate_value_enum() {
AggregateValueEnum::ArrayValue(av) => av.get_type().len(),
AggregateValueEnum::StructValue(sv) => sv.get_type().count_fields(),
};
if index >= size {
return None;
}
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildInsertValue(self.builder, agg.as_value_ref(), value.as_value_ref(), index, c_string.as_ptr())
};
Some(AggregateValueEnum::new(value))
}
pub fn build_extract_element(&self, vector: VectorValue, index: IntValue, name: &str) -> BasicValueEnum {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildExtractElement(self.builder, vector.as_value_ref(), index.as_value_ref(), c_string.as_ptr())
};
BasicValueEnum::new(value)
}
pub fn build_insert_element<V: BasicValue>(&self, vector: VectorValue, element: V, index: IntValue, name: &str) -> VectorValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildInsertElement(self.builder, vector.as_value_ref(), element.as_value_ref(), index.as_value_ref(), c_string.as_ptr())
};
VectorValue::new(value)
}
pub fn build_unreachable(&self) -> InstructionValue {
let val = unsafe {
LLVMBuildUnreachable(self.builder)
};
InstructionValue::new(val)
}
pub fn build_fence(&self, atomic_ordering: AtomicOrdering, num: i32, name: &str) -> InstructionValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let val = unsafe {
LLVMBuildFence(self.builder, atomic_ordering.into(), num, c_string.as_ptr())
};
InstructionValue::new(val)
}
pub fn build_is_null<T: PointerMathValue>(&self, ptr: T, name: &str) -> <<T::BaseType as PointerMathType>::PtrConvType as IntMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let val = unsafe {
LLVMBuildIsNull(self.builder, ptr.as_value_ref(), c_string.as_ptr())
};
<<T::BaseType as PointerMathType>::PtrConvType as IntMathType>::ValueType::new(val)
}
pub fn build_is_not_null<T: PointerMathValue>(&self, ptr: T, name: &str) -> <<T::BaseType as PointerMathType>::PtrConvType as IntMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let val = unsafe {
LLVMBuildIsNotNull(self.builder, ptr.as_value_ref(), c_string.as_ptr())
};
<<T::BaseType as PointerMathType>::PtrConvType as IntMathType>::ValueType::new(val)
}
pub fn build_int_to_ptr<T: IntMathValue>(&self, int: T, ptr_type: <T::BaseType as IntMathType>::PtrConvType, name: &str) -> <<T::BaseType as IntMathType>::PtrConvType as PointerMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildIntToPtr(self.builder, int.as_value_ref(), ptr_type.as_type_ref(), c_string.as_ptr())
};
<<T::BaseType as IntMathType>::PtrConvType as PointerMathType>::ValueType::new(value)
}
pub fn build_ptr_to_int<T: PointerMathValue>(&self, ptr: T, int_type: <T::BaseType as PointerMathType>::PtrConvType, name: &str) -> <<T::BaseType as PointerMathType>::PtrConvType as IntMathType>::ValueType {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildPtrToInt(self.builder, ptr.as_value_ref(), int_type.as_type_ref(), c_string.as_ptr())
};
<<T::BaseType as PointerMathType>::PtrConvType as IntMathType>::ValueType::new(value)
}
pub fn clear_insertion_position(&self) {
unsafe {
LLVMClearInsertionPosition(self.builder)
}
}
pub fn build_switch(&self, value: IntValue, else_block: &BasicBlock, cases: &[(IntValue, &BasicBlock)]) -> InstructionValue {
let switch_value = unsafe {
LLVMBuildSwitch(self.builder, value.as_value_ref(), else_block.basic_block, cases.len() as u32)
};
for &(value, basic_block) in cases {
unsafe {
LLVMAddCase(switch_value, value.as_value_ref(), basic_block.basic_block)
}
}
InstructionValue::new(switch_value)
}
pub fn build_select<BV: BasicValue, IMV: IntMathValue>(&self, condition: IMV, then: BV, else_: BV, name: &str) -> BasicValueEnum {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildSelect(self.builder, condition.as_value_ref(), then.as_value_ref(), else_.as_value_ref(), c_string.as_ptr())
};
BasicValueEnum::new(value)
}
pub unsafe fn build_global_string(&self, value: &str, name: &str) -> GlobalValue {
let c_string_value = CString::new(value).expect("Conversion to CString failed unexpectedly");
let c_string_name = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = LLVMBuildGlobalString(self.builder, c_string_value.as_ptr(), c_string_name.as_ptr());
GlobalValue::new(value)
}
pub fn build_global_string_ptr(&self, value: &str, name: &str) -> GlobalValue {
let c_string_value = CString::new(value).expect("Conversion to CString failed unexpectedly");
let c_string_name = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildGlobalStringPtr(self.builder, c_string_value.as_ptr(), c_string_name.as_ptr())
};
GlobalValue::new(value)
}
pub fn build_shuffle_vector(&self, left: VectorValue, right: VectorValue, mask: VectorValue, name: &str) -> VectorValue {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildShuffleVector(self.builder, left.as_value_ref(), right.as_value_ref(), mask.as_value_ref(), c_string.as_ptr())
};
VectorValue::new(value)
}
pub fn build_va_arg<BT: BasicType>(&self, list: PointerValue, type_: BT, name: &str) -> BasicValueEnum {
let c_string = CString::new(name).expect("Conversion to CString failed unexpectedly");
let value = unsafe {
LLVMBuildVAArg(self.builder, list.as_value_ref(), type_.as_type_ref(), c_string.as_ptr())
};
BasicValueEnum::new(value)
}
pub fn build_atomicrmw(&self, op: AtomicRMWBinOp, ptr: PointerValue, value: IntValue, ordering: AtomicOrdering) -> Result<IntValue, &'static str> {
if value.get_type().get_bit_width() < 8 ||
!value.get_type().get_bit_width().is_power_of_two() {
return Err("The bitwidth of value must be a power of 2 and greater than 8.");
}
if ptr.get_type().get_element_type() != value.get_type().into() {
return Err("Pointer's pointee type must match the value's type.");
}
let val = unsafe {
LLVMBuildAtomicRMW(self.builder, op.into(), ptr.as_value_ref(), value.as_value_ref(), ordering.into(), false as i32)
};
Ok(IntValue::new(val))
}
#[llvm_versions(3.9..=latest)]
pub fn build_cmpxchg<V: BasicValue>(&self, ptr: PointerValue, cmp: V, new: V, success: AtomicOrdering, failure: AtomicOrdering) -> Result<StructValue, &'static str> {
let cmp = cmp.as_basic_value_enum();
let new = new.as_basic_value_enum();
if cmp.get_type() != new.get_type() {
return Err("The value to compare against and the value to replace with must have the same type.");
}
if !cmp.is_int_value() && !cmp.is_pointer_value() {
return Err("The values must have pointer or integer type.");
}
if ptr.get_type().get_element_type().to_basic_type_enum() != cmp.get_type() {
return Err("The pointer does not point to an element of the value type.");
}
if success < AtomicOrdering::Monotonic || failure < AtomicOrdering::Monotonic {
return Err("Both success and failure orderings must be Monotonic or stronger.");
}
if failure > success {
return Err("The failure ordering may not be stronger than the success ordering.");
}
if failure == AtomicOrdering::Release || failure == AtomicOrdering::AcquireRelease {
return Err("The failure ordering may not be release or acquire release.");
}
let val = unsafe {
LLVMBuildAtomicCmpXchg(self.builder, ptr.as_value_ref(), cmp.as_value_ref(), new.as_value_ref(), success.into(), failure.into(), false as i32)
};
Ok(StructValue::new(val).into())
}
}
impl Drop for Builder {
fn drop(&mut self) {
unsafe {
LLVMDisposeBuilder(self.builder);
}
}
}
type FunctionOrPointerValue = Either<FunctionValue, PointerValue>;
impl Into<FunctionOrPointerValue> for FunctionValue {
fn into(self) -> FunctionOrPointerValue {
Left(self)
}
}
impl Into<FunctionOrPointerValue> for PointerValue {
fn into(self) -> FunctionOrPointerValue {
Right(self)
}
}