bac 0.1.0

Rust bindings for the BAC compiler backend
#[cfg(all(
    target_os = "linux",
    any(target_arch = "x86_64", target_arch = "aarch64")
))]
fn main() {
    use bac::{Arena, CodegenEmitCtx, Datatype, Proc};
    use core::{ffi::c_void, ptr};

    unsafe extern "C" {
        fn mmap(
            addr: *mut c_void,
            len: usize,
            prot: i32,
            flags: i32,
            fd: i32,
            offset: isize,
        ) -> *mut c_void;
        fn mprotect(addr: *mut c_void, len: usize, prot: i32) -> i32;
        fn munmap(addr: *mut c_void, len: usize) -> i32;
    }

    let mut temps = [Arena::new(4096 * 128), Arena::new(4096 * 128)];
    let mut memory = Arena::new(4096 * 8);
    let mut proc = Proc::new(&mut memory, &mut temps);
    let mut nodes = Vec::new();
    {
        let mut builder = proc.builder(&mut nodes);
        let value = builder.add_c_int("mcnst", Datatype::I64, 69);
        builder.merge_returns(&[builder.entry(), builder.initial_memory(), value]);
    }
    let mut code = Arena::new(4096);
    let mut ctx = CodegenEmitCtx::new(&mut proc, &mut code);
    let output = ctx.compile();
    assert!(!output.code.is_empty() && output.code.len() <= 4096);

    let page = unsafe { mmap(ptr::null_mut(), 4096, 1 | 2, 2 | 0x20, -1, 0) };
    assert_ne!(page as isize, -1);
    unsafe { ptr::copy_nonoverlapping(output.code.as_ptr(), page.cast(), output.code.len()) };
    assert_eq!(unsafe { mprotect(page, 4096, 1 | 4) }, 0);

    #[cfg(target_arch = "aarch64")]
    unsafe {
        unsafe extern "C" {
            fn __clear_cache(begin: *mut c_void, end: *mut c_void);
        }
        __clear_cache(page, page.add(output.code.len()));
    }

    let function: unsafe extern "C" fn() -> i64 = unsafe { core::mem::transmute(page) };
    let result = unsafe { function() };
    assert_eq!(unsafe { munmap(page, 4096) }, 0);
    assert_eq!(result, 69);
    std::process::exit(result as i32);
}

#[cfg(not(all(
    target_os = "linux",
    any(target_arch = "x86_64", target_arch = "aarch64")
)))]
fn main() {
    panic!("the executable-memory example supports Linux x86-64 and AArch64");
}