vnmakarov / mir

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

Assertion failed: (0), function out_op, file mir2c.c, line 65 #369

Open elix22 opened 1 year ago

elix22 commented 1 year ago

I have compiled mir2c.c as a standalone executable (m2c , defined(MIR2C) )

trying to convert a simple Fibonacci (mir <-> c),

Getting an error

Assertion failed: (0), function out_op, file mir2c.c, line 65. Abort trap: 6

fib.c


int printf ( const char * format, ... );

int fibR(int n)
{
    if (n < 2) return n;
    return (fibR(n-2) + fibR(n-1));
}

int main()
{
    int N;
    N = 42;
    printf("fib: %d\n", fibR(N));
    return 0;
}

fib.mir

M0: module
proto0: proto   i32, i32:i0_n
proto1: proto   i32, u64:U0_format, ...
    import  printf
fibR:   func    i32, i32:i0_n
    local   i64:i_0, i64:i_1, i64:i_2, i64:i_3, i64:i_4, i64:i_5
# 1 arg, 6 locals
    bges    L2, i0_n, 2
L1:
    ret i0_n
    jmp L3
L2:
L3:
    subs    i_2, i0_n, 2
    call    proto0, fibR, i_1, i_2
    subs    i_4, i0_n, 1
    call    proto0, fibR, i_3, i_4
    adds    i_5, i_1, i_3
    ret i_5
    endfunc
    export  fibR
main:   func    i32
    local   i64:i0_N, i64:i_0, i64:i_1
# 0 args, 3 locals
    mov i0_N, 42
    call    proto0, fibR, i_1, i0_N
    call    proto1, printf, i_0, "fib: %d\n\000", i_1
    ret 0
    endfunc
    export  main
    endmodule

fib_mir_genereated.c

#include <stdint.h>
typedef int32_t (*proto0) (int32_t i0_n);
typedef int32_t (*proto1) (uint64_t U0_format);
extern char printf[];
int32_t fibR (int32_t _i0_n) {
  int64_t i0_n = _i0_n;
  int64_t i_0;
  int64_t i_1;
  int64_t i_2;
  int64_t i_3;
  int64_t i_4;
  int64_t i_5;
  if ((int32_t) i0_n >= (int32_t) 2) goto l1;
l2:
  return i0_n;
  goto l3;
l1:
l3:
  i_2 = (int32_t) i0_n - (int32_t) 2;
  i_1 = ((proto0) fibR) (i_2);
  i_4 = (int32_t) i0_n - (int32_t) 1;
  i_3 = ((proto0) fibR) (i_4);
  i_5 = (int32_t) i_1 + (int32_t) i_3;
  return i_5;
}
int32_t main (void) {
  int64_t i0_N;
  int64_t i_0;
  int64_t i_1;
  i0_N = 42;
  i_1 = ((proto0) fibR) (i0_N);
  i_0 = ((proto1) printf) (
vnmakarov commented 1 year ago

Thank you for reporting this. m2c is not a part of the last binary release installation but it should have worked. I'll fix it on this week.

vnmakarov commented 1 year ago

I've just fixed it.

elix22 commented 1 year ago

Great , thanks . I think MIR is a great piece of software and has a lot of potential I noticed that the generated c (from MIR) contains extern char printf[];

I am removing it in order to pass compilation Commented // fprintf (f, "extern char %s[];\n", item->u.import_id);

I also modified below to pass compilation fprintf (f, "#include <stdio.h>\n");

void MIR_module2c (MIR_context_t ctx, FILE *f, MIR_module_t m) {
  fprintf (f, "#include <stdint.h>\n");
  fprintf (f, "#include <stdio.h>\n");
  for (MIR_item_t item = DLIST_HEAD (MIR_item_t, m->items); item != NULL;
       item = DLIST_NEXT (MIR_item_t, item))
    out_item (ctx, f, item);
}
vnmakarov commented 1 year ago

Great , thanks . I think MIR is a great piece of software and has a lot of potential I noticed that the generated c (from MIR) contains extern char printf[];

Thank you for the kind words.

MIR has no information about external symbols (is it function or global variable?). It has only an import symbol (import printf in this case). So I use this trick. It should work at least with GCC although a warning might be generated.

elix22 commented 1 year ago

On my Mac it is considered an error , but personally I am ok with my workaround.

gcc fib_mir_genereated.c -o fib_mir_genereated

fib_mir_genereated.c:5:13: error: redefinition of 'printf' as different kind of symbol
extern char printf[];
elix22 commented 1 year ago

I tried the same procedure on c-benchmarks/sieve.c

Getting an error

./m2c sieve.mir > sieve_mir_genereated.c wrong length for MIR_var_tAssertion failed: (0), function mir_varr_assert_fail, file mir-varr.h, line 26. Abort trap: 6

vnmakarov commented 1 year ago

I fixed this. Unfortunately mir-2-c compiler is in a bad shape. A lot of new MIR constructions is not implemented and some features are not easy to implement, including multiple results funcs and BLK types used to pass args according some target specific ABIs. For example, on x86-64 struct of int and double is passed in regs and for this a MIR BLK type is used.

So translation to MIR should be target specific. I should think what to do with m2c. I am inclining to remove this because I don't see where it could be useful.

elix22 commented 1 year ago

Thanks for your fixes . I am not an expert in JIT/AOT compilers but was always fascinated by this subject My Idea was to use it for a small .NET runtime DotNetAnywhere I have played with it in the past and also did some P.O.C running it on top of SDL , working on mobiles SDL-DNA The idea is to implement the following : Translate CIL -> MIR -> JIT (PC) Translate CIL -> MIR -> C (on Mobile devices)

Basically to follow the same functionality that is done for HAXE , with the Hashlink runtime On PC it is a JIT compiler For Mobiles it is compiled to C (HL/C) Also Played with it in the past made some working P.O.C , using it in a Game engine

These are all side pet projects , I like to play and experiment with this stuff. I didn't dig too deep into MIR , so I don't know if MIR is suitable for that task So I might be wrong in my assumptions . You thoughts would be appreciated

Thanks