open-goal / jak-project

Reviving the language that brought us the Jak & Daxter Series
https://opengoal.dev
ISC License
2.84k stars 174 forks source link

[Decompiler] Support dynamically populated bitfields. #353

Closed water111 closed 3 years ago

water111 commented 3 years ago

It seems like GOAL could support creating a bitfield where some field are known at compile time, and others are evaluated at runtime. The decompiler current doesn't handle this neatly.

The function dma-buffer-add-vu-function has three examples of this that should make a good test case.

Here's one example:

    ;; get address to store in
    lwu t2, 4(t1)
    ;; create value
    lui t3, 12288
    dsll32 t4, t0, 16
    dsrl32 t4, t4, 16
    or t3, t3, t4
    dsll32 t4, v1, 1
    dsrl t4, t4, 1
    or t3, t3, t4
    ;; store value
    sd t3, 0(t2)              ;; (s.d! buf-ptr t3-2)[16] [t2: dma-packet t3: int ] -> []

The decompiler does produce correct code, but it's hard to understand:

      (set!
       (-> buf-ptr dma)
       (the-as
        dma-tag
        (logior
         (logior #x30000000 (shr (shl qwc-now 48) 48))
         (the-as int (shr (shl (the-as int func-ptr) 33) 1))
         )
        )
       )

The pattern seems pretty simple: nested logiors, like this:

(logior (logior .... (logior <constant> (shr (shl <expr1> <lshift>) <rshift>)) ...))

The <constant> is left out if it's zero. Note that sar shouldn't be used, even for signed bitfields.
This appears to be the same logic as setting a normal bitfield, but the initial "and with mask" is omitted. So I would expect shr and shls to be omitted if the shift amount is zero.

water111 commented 3 years ago

The OpenGOAL compiler also needs to add support for this.