Alamvic / druid

Meta-compiler to generate an optimised JIT compiler frontend based on an Interpreter definition
8 stars 6 forks source link

Improve booleans on generated code #117

Closed PalumboN closed 5 months ago

PalumboN commented 6 months ago

Now when Druid interprets a complex condition (using and:/or:) like

isFixedSizePointerFormat: format
    <api>
    ^format <= self nonIndexablePointerFormat
      or: [format = self ephemeronFormat]

It's generates an IR like

# Block1
-------------------------------
t1 := GetConditionCode(cond1)
JumpIf(cond1 = true)
-------------------------------

# BlockTrue
-------------------------------
t2 := GetConditionCode(cond2)
Jump(Merge)
-------------------------------

# BlockMerge
-------------------------------
t3 := Phi(t1, t2)
JumpIf(t3 = true)
-------------------------------

And it generates, after not optimal register allocations because of the phi, Cogit's code that move constants to the compare

DruidJIT >> gen_PrimitiveNew
        "..."
        self CmpCq: 5 R: Extra1Reg.
        jumpTrue := self JumpZero: 0.
        self MoveCq: 0 R: Extra1Reg.
        jumpNext := self Jump: 0.
        jumpTrue jmpTarget: self Label.
        self MoveCq: 1 R: Extra1Reg.
        jumpNext jmpTarget: self Label.
        currentBlock := self Label.
        jump2 jmpTarget: currentBlock.
        self CmpCq: 1 R: Extra1Reg.
        jump2 := self JumpNonZero: 0.
        "..."

What to do?

Well, we can avoid these unnecesary copies, compares and jumps by solving the phi in the IR.


I make a POC doing the tail duplication by hand in the IR, this is the result:

image