3 releases
Uses new Rust 2024
new 0.1.0-alpha.4 | Mar 17, 2025 |
---|---|
0.1.0-alpha.3 | Mar 14, 2025 |
#1169 in Programming languages
304 downloads per month
175KB
4K
SLoC
IRVM
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(
¶m,
&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(())
}
lib.rs
:
irmv-lower
Lower irvm IR to other IRs.
This crates currently only allows you to lower irmv IR to LLVM IR.
See the llvm
submodule for more information.
cargo add irvm-lower
Dependencies
~2.3–3.5MB
~74K SLoC