remir_llvm 1.0.0

The LLVM binding for the Remir library
use std::hint::unreachable_unchecked;

use inkwell::types::BasicType;
use remir::{block::BlockInstruction, insts::Instruction, module::Module, values::ValueType};

use crate::{LLVMBridge, llvm_to_base, llvm_to_base_returnless, utils::LLVMBasicValue};

pub fn bridge_llvm_mem_instruction(
    instruction: BlockInstruction,
    bridge: &mut LLVMBridge,
    module: &mut Module,
) -> Result<Option<LLVMBasicValue>, ()> {
    let res = match &instruction.instruction {
        Instruction::Alloc { size: _, val_type } => {
            let res = llvm_to_base!(
                bridge
                    .builder
                    .build_malloc(bridge.type_storage.convert(val_type.clone()).inner, "")
            );

            Some(res.into())
        }

        Instruction::Alloca { size: _, val_type } => {
            let res = llvm_to_base!(
                bridge
                    .builder
                    .build_alloca(bridge.type_storage.convert(val_type.clone()).inner, "")
            );

            Some(res.into())
        }

        Instruction::AllocUntyped { size } => {
            let size = bridge.values[&size.base.inst_ind].into_int_value();

            let malloc_ty = bridge
                .type_storage
                .convert(ValueType::Pointer(Box::new(ValueType::Unknown)))
                .fn_type(
                    &[bridge
                        .type_storage
                        .convert(ValueType::Int(false, 64))
                        .inner
                        .into()],
                    false,
                );

            let malloc = bridge.modules[&module.name]
                .get_function("malloc")
                .unwrap_or_else(|| {
                    bridge.modules[&module.name].add_function("malloc", malloc_ty, None)
                });

            let ptr = llvm_to_base!(bridge.builder.build_call(malloc, &[size.into()], ""));

            ptr.try_as_basic_value().basic()
        }

        Instruction::AllocaUntyped { size } => {
            let size = bridge.values[&size.base.inst_ind].into_int_value();

            let alloca_ty = bridge
                .type_storage
                .convert(ValueType::Pointer(Box::new(ValueType::Unknown)))
                .fn_type(
                    &[bridge
                        .type_storage
                        .convert(ValueType::Int(false, 64))
                        .inner
                        .into()],
                    false,
                );

            let alloca = bridge.modules[&module.name]
                .get_function("alloca")
                .unwrap_or_else(|| {
                    bridge.modules[&module.name].add_function("alloca", alloca_ty, None)
                });

            let ptr = llvm_to_base!(bridge.builder.build_call(alloca, &[size.into()], ""));

            ptr.try_as_basic_value().basic()
        }

        Instruction::Free { ptr } => {
            let ptr = bridge.values[&ptr.base.inst_ind].into_pointer_value();

            llvm_to_base_returnless!(bridge.builder.build_free(ptr));

            None
        }

        Instruction::Gep { base, offset } => {
            let ty = bridge.type_storage.convert(ValueType::Int(false, 8));

            let base = bridge.values[&base.base.inst_ind].into_pointer_value();
            let offset = bridge.values[&offset.base.inst_ind].into_int_value();

            let val =
                unsafe { llvm_to_base!(bridge.builder.build_gep(ty.inner, base, &[offset], "")) };

            Some(val.into())
        }

        Instruction::LoadIndexed { base, index } => {
            let ty = bridge.type_storage.convert(base.inner_type.clone());

            let base = bridge.values[&base.base.inst_ind].into_pointer_value();
            let offset = bridge.values[&index.base.inst_ind].into_int_value();

            let ptr = unsafe {
                llvm_to_base!(
                    bridge
                        .builder
                        .build_gep(ty.inner.clone(), base, &[offset], "")
                )
            };

            let val = llvm_to_base!(bridge.builder.build_load(ty.inner.clone(), ptr, ""));

            Some(val)
        }

        Instruction::StoreIndexed { base, index, val } => {
            let ty = bridge.type_storage.convert(base.inner_type.clone());
            let val = bridge.values[&val.inst_ind].inner.clone();

            let base = bridge.values[&base.base.inst_ind].into_pointer_value();
            let offset = bridge.values[&index.base.inst_ind].into_int_value();

            let ptr = unsafe {
                llvm_to_base!(
                    bridge
                        .builder
                        .build_gep(ty.inner.clone(), base, &[offset], "")
                )
            };

            llvm_to_base_returnless!(bridge.builder.build_store(ptr, val));

            None
        }

        _ => unsafe { unreachable_unchecked() },
    };

    if res.is_some() {
        return Ok(Some(LLVMBasicValue::new(res.unwrap(), &bridge.ctx)));
    }

    return Ok(None);
}