Skip to content

edg-l/irvm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Mar 17, 2025
e392e9d · Mar 17, 2025

History

55 Commits
Mar 12, 2025
Mar 17, 2025
Mar 17, 2025
Mar 17, 2025
Mar 17, 2025
Mar 17, 2025
Feb 23, 2025
Mar 13, 2025
Mar 14, 2025
Mar 17, 2025
Mar 14, 2025

Repository files navigation

IRVM

CI Crate Crates.io irvm Total Downloads Crate Crates.io irvm-lower Total Downloads Crates.io License

A IR compiler target with a native Rust friendly API that lowers to LLVM IR (or other targets).

How it works

Basically mimic a IR that closely resembles LLVM IR in Rust structures and only interface with LLVM at the time of lowering to LLVM IR / compilation.

Ideally when lowering to LLVM IR the IR in IRVM should be valid due to checks on our side.

Why?

There are some nice crates to use LLVM from Rust, like inkwell, but due to the need to model the C++ ownership (ffi) in Rust, the API tends to not be so user friendly, even if they try hard, also some functions like GEP are unsafe if used incorrectly, this library strives to provide a Rust friendly API thats fully safe.

use std::error::Error;

use irvm::{
    block::IcmpCond,
    common::Location,
    function::Parameter,
    module::Module,
    types::{Type, TypeStorage},
    value::Operand,
};

use irvm_lower::llvm::{lower_module_to_llvmir, OutputCompilation};

fn main() -> Result<(), Box<dyn Error>> {
    let mut module = Module::new("example", Location::unknown());
    let mut storage = TypeStorage::new();
    let _bool_ty = storage.add_type(Type::Int(1), Some("bool"));
    let i32_ty = storage.add_type(Type::Int(32), Some("i32"));
    let _i64_ty = storage.add_type(Type::Int(64), Some("i64"));
    let _ptr_ty = storage.add_type(
        Type::Ptr {
            pointee: i32_ty,
            address_space: None,
        },
        Some("*i32"),
    );

    let main_func = module
        .add_function(
            "main",
            &[Parameter::new(i32_ty, Location::Unknown)],
            i32_ty,
            Location::Unknown,
        )
        .get_id();
    let test_func = module
        .add_function(
            "test",
            &[Parameter::new(i32_ty, Location::Unknown)],
            i32_ty,
            Location::Unknown,
        )
        .get_id();

    let test_func_ret_ty = module.get_function(test_func).result_type;

    // main function
    {
        let func = module.get_function_mut(main_func);
        let param = func.param(0)?;
        let entry_block = func.entry_block;

        let value = func.blocks[entry_block].instr_add(
            &param,
            &Operand::const_int(4, i32_ty),
            Location::Unknown,
        )?;

        let then_block = func.add_block(&[]);
        let else_block = func.add_block(&[]);
        let final_block = func.add_block(&[i32_ty]);

        let cond = func.blocks[entry_block].instr_icmp(
            IcmpCond::Eq,
            value.clone(),
            Operand::const_int(6, i32_ty),
            Location::Unknown,
            &storage,
        )?;

        func.blocks[entry_block].instr_cond_jmp(
            then_block,
            else_block,
            &cond,
            &[],
            &[],
            Location::Unknown,
        );

        // then block
        {
            let value = func.blocks[then_block].instr_add(
                &value,
                &Operand::const_int(2, i32_ty),
                Location::Unknown,
            )?;
            func.blocks[then_block].instr_jmp(final_block, &[value], Location::Unknown);
        }

        // else block
        {
            let value = func.blocks[else_block].instr_add(
                &value,
                &Operand::const_int(6, i32_ty),
                Location::Unknown,
            )?;
            func.blocks[else_block].instr_jmp(final_block, &[value], Location::Unknown);
        }

        // final block
        {
            let param = func.blocks[final_block].arg(0)?;
            let value = func.blocks[final_block].instr_call(
                test_func,
                &[param],
                test_func_ret_ty,
                Location::Unknown,
            )?;
            func.blocks[final_block].instr_ret(Some(&value), Location::Unknown);
        }
    }

    // test function
    {
        let func = module.get_function_mut(test_func);
        let value = func.param(0)?;
        func.entry_block()
            .instr_ret(Some(&value), Location::Unknown);
    }

    let compile_result = lower_module_to_llvmir(&module, &storage)?;
    compile_result.dump();
    Ok(())
}

About

A IR compiler target with a native Rust friendly API that lowers to LLVM IR.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages