Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature request] Link-time conditionals for identically sized branches #822

Open
Rangi42 opened this issue Apr 2, 2021 · 8 comments
Open
Labels
enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM

Comments

@Rangi42
Copy link
Contributor

Rangi42 commented Apr 2, 2021

Generating code with macros, like pokecrystal16, can require different optimizations depending on where labels end up being placed. (Note the various dbs in that file.) However, if needs to be evaluated at assembly time, and an eventual ternary operator would only work within dbs, requiring people to encode instructions as raw bytes. (For instance, db (HIGH(\1EntriesEnd) & 1) ? $28 : $20, .search_loop - (@ + 1), would eventually work, but (HIGH(\1EntriesEnd) & 1) ? <jr nz, .search_loop> : <jr z, .search_loop>, or jr <(HIGH(\1EntriesEnd) & 1) ? nz : z>, .search_loop, cannot.)

A solution could be link-time conditionals. These would fail to assemble if all their branches are not already the same size, or if one branch defines a label but another does not. (Two branches defining a label in different relative locations should be okay, I think, but if it isn't that would be fine as a limitation too.)

Example syntax (chosen in contrast with static_assert):

dynamic_if HIGH(\1EntriesEnd) & 1
    jr nz, .search_loop
else
    jr z, .search_loop
endc
@Rangi42 Rangi42 added enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM labels Apr 2, 2021
@aaaaaa123456789
Copy link
Member

I like it. I wonder how complex RPN-based relocations would get, though.

@ISSOtm
Copy link
Member

ISSOtm commented Apr 3, 2021

Sadly, this precondition isn't sufficient:

dynamic_if Test & 1
    def trap EQUS ""
else
    def trap EQUS "ld a, 1"
endc

    trap

Both branches produce exactly 0 bytes, so they fulfill the precondition, but then trap breaks everything. Its computation can also be made arbitrarily complex, as long as neither branch outputs any bytes.

@Rangi42
Copy link
Contributor Author

Rangi42 commented Apr 3, 2021

That's not a problem; the second definition would fail since trap is already defined.

dynamic_if (or some better name; maybe when) would act more like a "ROM union" than an asm-time if: every branch is evaluated, top to bottom as usual, but nothing is output right away; it's stored in RPN buffers along with the RPN conditions. (The assembler fails right away if they're different sizes.) Then the linker outputs only the first one with a true condition.

@Rangi42 Rangi42 added this to the v0.9.0 milestone Nov 3, 2023
@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 20, 2023

ISSOtm suggested "UNION IF" for this, which avoids a new keyword and I think nicely indicates how it works. One concern: would we be able to use ELSE and ENDC, or need to do UNION ELSE and UNION ENDC?

Alternatively, maybe UNION IF cond / ... / NEXTU / ... / ENDU would be fine, since this feature is ROM-only, and regular UNIONs are RAM-only. Or add a new ELSEU keyword (and ELIFU). Or have UNION IF cond / ... / NEXTU IF cond2 / ... / NEXTU / ... / ENDU.

@ISSOtm
Copy link
Member

ISSOtm commented Dec 20, 2023

That last syntax is what I had in mind, yep. The last branch is mandatory, obviously!

@aaaaaa123456789
Copy link
Member

I was hoping for regular elif and else for other branches, since the union part is already declared, but I wouldn't mind writing it some other equally clear way.

@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 20, 2023

That last syntax is what I had in mind, yep. The last branch is mandatory, obviously!

Like this?

UNION IF x == -1
    jr c, .foo
NEXTU IF x == 0 ; "elif"
    jr z, .foo
NEXTU IF x == 1 ; "elif"
    jr nc, .foo
NEXTU ; "else"
    jr .foo
ENDU ; "endc"

@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 20, 2023

I was hoping for regular elif and else for other branches, since the union part is already declared, but I wouldn't mind writing it some other equally clear way.

I believe that would be problematic given how IF sets a lexer mode to skip over lines until an ELIF/ELSE/ENDC.

@Rangi42 Rangi42 removed this from the v0.10.0 milestone Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM
Projects
None yet
Development

No branches or pull requests

3 participants