vnmakarov / mir

A lightweight JIT compiler based on MIR (Medium Internal Representation) and C11 JIT compiler and interpreter based on MIR
MIT License
2.24k stars 145 forks source link

Allow MIR text to be mixed in with C API #385

Open iacore opened 7 months ago

iacore commented 7 months ago

Currently, MIR_scan_string and MIR_read can only read complete modules, not a function or standalone MIR instructions.

Since MIR has both text and in-memory representation, I thought the C API should allow me to do this:

(sorry about the code being Zig)

const std = @import("std");
const m = @import("mir.zig");

const use_text = true;

pub fn main() !void {
    const ctx = m.MIR_init() orelse return error.MIRError;

    const mod = m.MIR_new_module(ctx, "name");

    var f: m.MIR_item_t = undefined;
    if (use_text) {
        m.MIR_scan_string(ctx,
            \\hello:  
            \\  func i64, i64:a, i64:b
            \\  local      i64:$ret
            \\  add        $ret, a, b
            \\  ret        $ret
            \\  endfunc
        );
        f = m.MIR_get_global_item(ctx, "hello");
    } else {
        var f_vars = [_]m.MIR_var_t{
            .{ .type = m.MIR_T_I64, .name = "a" },
            .{ .type = m.MIR_T_I64, .name = "b" },
        };
        f = ctx.new_func("add", 1, &.{m.MIR_T_I64}, 2, &f_vars);
        const fid = m.MIR_get_item_func(f);

        const ret = ctx.new_func_reg(fid, m.MIR_T_I64, "ret");
        const a = ctx.reg(f_vars[0].name, fid);
        const b = ctx.reg(f_vars[1].name, fid);

        ctx.append(f, ctx.insn(m.MIR_ADD, 3, &.{ ctx.op_reg(ret), ctx.op_reg(a), ctx.op_reg(b) }));

        ctx.append(f, ctx.insn(m.MIR_RET, 1, &.{ctx.op_reg(ret)}));
        m.MIR_finish_func(ctx);
    }

    m.MIR_finish_module(ctx);

    m.MIR_load_module(ctx, mod);

    m.MIR_output(ctx, m.stderr);

    m.MIR_gen_init(ctx, 1);
    m.MIR_link(ctx, m.MIR_set_gen_interface, null);
    const f_call = @as(*fn (i64, i64) callconv(.C) i64, @ptrCast(m.MIR_gen(ctx, 0, f)));
    m.MIR_gen_finish(ctx);

    const ans = f_call(2, 3);
    std.log.info("{}", .{ans});
}