aboutsummaryrefslogblamecommitdiffhomepage
path: root/src/llvm/builder.rs
blob: 3d43b685ae0f92b83fdcb08ae0710bdc4f1499ca (plain) (tree)




























































































































































































                                                                                                  
use llvm_sys::{
    core::{
        LLVMBuildFAdd, LLVMBuildFCmp, LLVMBuildFMul, LLVMBuildFSub, LLVMBuildRet, LLVMBuildUIToFP,
        LLVMCreateBuilderInContext, LLVMDisposeBuilder, LLVMPositionBuilderAtEnd,
    },
    prelude::{LLVMBuilderRef, LLVMValueRef},
    LLVMRealPredicate,
};

use std::marker::PhantomData;

use super::{BasicBlock, FnValue, Module, Type, Value};

// Definition of LLVM C API functions using our `repr(transparent)` types.
extern "C" {
    fn LLVMBuildCall2(
        arg1: LLVMBuilderRef,
        arg2: Type<'_>,
        Fn: FnValue<'_>,
        Args: *mut Value<'_>,
        NumArgs: ::libc::c_uint,
        Name: *const ::libc::c_char,
    ) -> LLVMValueRef;
}

/// Wrapper for a LLVM IR Builder.
pub struct IRBuilder<'llvm> {
    builder: LLVMBuilderRef,
    _ctx: PhantomData<&'llvm ()>,
}

impl<'llvm> IRBuilder<'llvm> {
    /// Create a new LLVM IR Builder with the `module`s context.
    ///
    /// # Panics
    ///
    /// Panics if creating the IR Builder fails.
    pub fn with_ctx(module: &'llvm Module) -> IRBuilder<'llvm> {
        let builder = unsafe { LLVMCreateBuilderInContext(module.ctx()) };
        assert!(!builder.is_null());

        IRBuilder {
            builder,
            _ctx: PhantomData,
        }
    }

    /// Position the IR Builder at the end of the given Basic Block.
    pub fn pos_at_end(&self, bb: BasicBlock<'llvm>) {
        unsafe {
            LLVMPositionBuilderAtEnd(self.builder, bb.0);
        }
    }

    /// Emit a [fadd](https://llvm.org/docs/LangRef.html#fadd-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn fadd(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
        debug_assert!(lhs.is_f64(), "fadd: Expected f64 as lhs operand!");
        debug_assert!(rhs.is_f64(), "fadd: Expected f64 as rhs operand!");

        let value_ref = unsafe {
            LLVMBuildFAdd(
                self.builder,
                lhs.value_ref(),
                rhs.value_ref(),
                b"fadd\0".as_ptr().cast(),
            )
        };
        Value::new(value_ref)
    }

    /// Emit a [fsub](https://llvm.org/docs/LangRef.html#fsub-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn fsub(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
        debug_assert!(lhs.is_f64(), "fsub: Expected f64 as lhs operand!");
        debug_assert!(rhs.is_f64(), "fsub: Expected f64 as rhs operand!");

        let value_ref = unsafe {
            LLVMBuildFSub(
                self.builder,
                lhs.value_ref(),
                rhs.value_ref(),
                b"fsub\0".as_ptr().cast(),
            )
        };
        Value::new(value_ref)
    }

    /// Emit a [fmul](https://llvm.org/docs/LangRef.html#fmul-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn fmul(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
        debug_assert!(lhs.is_f64(), "fmul: Expected f64 as lhs operand!");
        debug_assert!(rhs.is_f64(), "fmul: Expected f64 as rhs operand!");

        let value_ref = unsafe {
            LLVMBuildFMul(
                self.builder,
                lhs.value_ref(),
                rhs.value_ref(),
                b"fmul\0".as_ptr().cast(),
            )
        };
        Value::new(value_ref)
    }

    /// Emit a [fcmult](https://llvm.org/docs/LangRef.html#fcmp-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn fcmpult(&self, lhs: Value<'llvm>, rhs: Value<'llvm>) -> Value<'llvm> {
        debug_assert!(lhs.is_f64(), "fcmplt: Expected f64 as lhs operand!");
        debug_assert!(rhs.is_f64(), "fcmplt: Expected f64 as rhs operand!");

        let value_ref = unsafe {
            LLVMBuildFCmp(
                self.builder,
                LLVMRealPredicate::LLVMRealULT,
                lhs.value_ref(),
                rhs.value_ref(),
                b"fcmplt\0".as_ptr().cast(),
            )
        };
        Value::new(value_ref)
    }

    /// Emit a [uitofp](https://llvm.org/docs/LangRef.html#uitofp-to-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn uitofp(&self, val: Value<'llvm>, dest_type: Type<'llvm>) -> Value<'llvm> {
        debug_assert!(val.is_int(), "uitofp: Expected integer operand!");

        let value_ref = unsafe {
            LLVMBuildUIToFP(
                self.builder,
                val.value_ref(),
                dest_type.type_ref(),
                b"uitofp\0".as_ptr().cast(),
            )
        };
        Value::new(value_ref)
    }

    /// Emit a [call](https://llvm.org/docs/LangRef.html#call-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn call(&self, fn_value: FnValue<'llvm>, args: &mut [Value<'llvm>]) -> Value<'llvm> {
        let value_ref = unsafe {
            LLVMBuildCall2(
                self.builder,
                fn_value.ret_type(),
                fn_value,
                args.as_mut_ptr(),
                args.len() as libc::c_uint,
                b"call\0".as_ptr().cast(),
            )
        };
        Value::new(value_ref)
    }

    /// Emit a [ret](https://llvm.org/docs/LangRef.html#ret-instruction) instruction.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn ret(&self, ret: Value<'llvm>) {
        let ret = unsafe { LLVMBuildRet(self.builder, ret.value_ref()) };
        assert!(!ret.is_null());
    }
}

impl Drop for IRBuilder<'_> {
    fn drop(&mut self) {
        unsafe { LLVMDisposeBuilder(self.builder) }
    }
}