dworkin / lpc-ext

Extension modules for Hydra and DGD
The Unlicense
9 stars 5 forks source link

JIT fails to compile LPC #9

Closed nyankers closed 3 years ago

nyankers commented 3 years ago

The JIT extension seems to fail to compile x = y[0] = z[0] when x/y/z are int or float types, respectively showing error messages like:

int error

cache/b8/b88ec35eebcbedf1df275572df197e79.ll:92:19: error: use of undefined value '%t15'
        %l1r30 = xor i32 %t15, 0
                         ^
1 error generated.

float error

cache/cf/cf3f625685caef596c6b995f7dec9a5c.ll:92:28: error: use of undefined value '%t15'
        %l1r35 = fadd fast double %t15, 0x0000000000000000
                                  ^
1 error generated.

Example code to reproduce this:

mixed test()
{
    mixed x;
    mixed *a, *b;

    a = allocate(11);
    b = allocate(21);

    x = a[0] = b[0];

    return ({ x, a, b });
}
nyankers commented 3 years ago

At initial glance, it looks like this is happening because STORE_LOCAL is attempting to copy from a tmpRef generated from the current stack pointer, but the STORE_LOCAL_INDEX instructions that happen before that increment the stack pointer.

I'm not sure I fully understand it, but from debugging things, it looks like the stack mainly just grows.

dworkin commented 3 years ago

It seems like I completely overlooked the case where an indexed assignment produces a value that can be stored in a register...

dworkin commented 3 years ago

Should be fixed by 16b60e41cc403f183faba7658cef36b302d207b8.

dworkin commented 3 years ago

I'm not sure I fully understand it, but from debugging things, it looks like the stack mainly just grows.

The Stack class records not just the current stack as you go through the code, but all possible stacks of all instructions in a function. The next element on the stack after stack[sp] is not stack[sp - 1] but stack[stack[sp].next]. That is why the "stack" keeps growing as the decompiler processes a function.

nyankers commented 3 years ago

It looks like it's fixed to me! It happened pretty much because my fancy text column code needed a special "what if there's only one element" branch where it says the width of all columns equals the width of the first column equals the length of the only element. :)

I'm afraid I don't really understand the JIT code yet. I assume everything up until genclang.cpp is just breaking down the LPC instructions into its component pieces, and it's solely genclang.cpp that does the conversion. If that's true, maybe I'll try to write an alternative genclang.cpp to try and understand it better, though it's not a high priority for me yet. n.n

dworkin commented 3 years ago

genclang is the most complex part, but also the easiest to make small changes to. If you really want to try your hand at it, take a look at this issue.