aboutsummaryrefslogblamecommitdiffhomepage
path: root/src/llvm/value.rs
blob: 219c85587e1c47f08912a0d801a2b23069d8c9f6 (plain) (tree)
1
2
3
4
5
6


                                                              


                                                                                                








                                
                      















































































































































                                                                                                 






                                                                        









                                                                  
use llvm_sys::{
    analysis::{LLVMVerifierFailureAction, LLVMVerifyFunction},
    core::{
        LLVMAppendExistingBasicBlock, LLVMCountBasicBlocks, LLVMCountParams, LLVMDumpValue,
        LLVMGetParam, LLVMGetReturnType, LLVMGetValueKind, LLVMGetValueName2, LLVMSetValueName2,
        LLVMTypeOf,
    },
    prelude::LLVMValueRef,
    LLVMTypeKind, LLVMValueKind,
};

use std::ffi::CStr;
use std::marker::PhantomData;
use std::ops::Deref;

use super::BasicBlock;
use super::Type;

/// Wrapper for a LLVM Value Reference.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Value<'llvm>(LLVMValueRef, PhantomData<&'llvm ()>);

impl<'llvm> Value<'llvm> {
    /// Create a new Value instance.
    ///
    /// # Panics
    ///
    /// Panics if `value_ref` is a null pointer.
    pub(super) fn new(value_ref: LLVMValueRef) -> Self {
        assert!(!value_ref.is_null());
        Value(value_ref, PhantomData)
    }

    /// Get the raw LLVM value reference.
    #[inline]
    pub(super) fn value_ref(&self) -> LLVMValueRef {
        self.0
    }

    /// Get the LLVM value kind for the given value reference.
    pub(super) fn kind(&self) -> LLVMValueKind {
        unsafe { LLVMGetValueKind(self.value_ref()) }
    }

    /// Dump the LLVM Value to stdout.
    pub fn dump(&self) {
        unsafe { LLVMDumpValue(self.value_ref()) };
    }

    /// Get a type reference representing for the given value reference.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn type_of(&self) -> Type<'llvm> {
        let type_ref = unsafe { LLVMTypeOf(self.value_ref()) };
        Type::new(type_ref)
    }

    /// Set the name for the given value reference.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn set_name(&self, name: &str) {
        unsafe { LLVMSetValueName2(self.value_ref(), name.as_ptr().cast(), name.len()) };
    }

    /// Get the name for the given value reference.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn get_name(&self) -> &'llvm str {
        let name = unsafe {
            let mut len: libc::size_t = 0;
            let name = LLVMGetValueName2(self.0, &mut len as _);
            assert!(!name.is_null());

            CStr::from_ptr(name)
        };

        // TODO: Does this string live for the time of the LLVM context?!
        name.to_str()
            .expect("Expected valid UTF8 string from LLVM API")
    }

    /// Check if value is of `f64` type.
    pub fn is_f64(&self) -> bool {
        self.type_of().kind() == LLVMTypeKind::LLVMDoubleTypeKind
    }

    /// Check if value is of integer type.
    pub fn is_int(&self) -> bool {
        self.type_of().kind() == LLVMTypeKind::LLVMIntegerTypeKind
    }
}

/// Wrapper for a LLVM Value Reference specialized for contexts where function values are needed.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct FnValue<'llvm>(Value<'llvm>);

impl<'llvm> Deref for FnValue<'llvm> {
    type Target = Value<'llvm>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'llvm> FnValue<'llvm> {
    /// Create a new FnValue instance.
    ///
    /// # Panics
    ///
    /// Panics if `value_ref` is a null pointer.
    pub(super) fn new(value_ref: LLVMValueRef) -> Self {
        let value = Value::new(value_ref);
        debug_assert_eq!(
            value.kind(),
            LLVMValueKind::LLVMFunctionValueKind,
            "Expected a fn value when constructing FnValue!"
        );

        FnValue(value)
    }

    /// Get a type reference representing the return value of the given function value.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer.
    pub fn ret_type(&self) -> Type<'llvm> {
        let type_ref = unsafe { LLVMGetReturnType(LLVMTypeOf(self.value_ref())) };
        Type::new(type_ref)
    }

    /// Get the number of function arguments for the given function value.
    pub fn args(&self) -> usize {
        unsafe { LLVMCountParams(self.value_ref()) as usize }
    }

    /// Get a value reference for the function argument at index `idx`.
    ///
    /// # Panics
    ///
    /// Panics if LLVM API returns a `null` pointer or indexed out of bounds.
    pub fn arg(&self, idx: usize) -> Value<'llvm> {
        assert!(idx < self.args());

        let value_ref = unsafe { LLVMGetParam(self.value_ref(), idx as libc::c_uint) };
        Value::new(value_ref)
    }

    /// Get the number of Basic Blocks for the given function value.
    pub fn basic_blocks(&self) -> usize {
        unsafe { LLVMCountBasicBlocks(self.value_ref()) as usize }
    }

    /// Append a Basic Block to the end of the function value.
    pub fn append_basic_block(&self, bb: BasicBlock<'llvm>) {
        unsafe {
            LLVMAppendExistingBasicBlock(self.value_ref(), bb.bb_ref());
        }
    }

    /// Verify that the given function is valid.
    pub fn verify(&self) -> bool {
        unsafe {
            LLVMVerifyFunction(
                self.value_ref(),
                LLVMVerifierFailureAction::LLVMPrintMessageAction,
            ) == 0
        }
    }
}