-
Notifications
You must be signed in to change notification settings - Fork 711
Jump-and-link instruction #630
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
Conversation
|
cc @vaivaswatha can you comment on the impact of this change? Ie. any concerns regarding register allocation for nested sub-routines? |
|
Today this is how we compile the following fn main() -> u64 {
1337
}
This is the function ASM (not super optimized to avoid inlining): This is the ASM calling the With this new instruction, we could call and the Which means we can save 3 instructions when calling We could save extra 4 instructions per function definition, by using |
There shouldn't be any problem. When we enter a function, we save all (used) registers and pop them all back at the end. So register allocation shouldn't be affected. I don't see any downsides, and the upside is as elaborated by @xunilrj . |
I'm not sure how that would work? The immediate part here is at most 12 bits long, and the VM has 48 user-writable registers. Unless we special-case some of these registers, of course, but that seems unwise. I'm noticing that the function calls could be optimized a lot further with smarter register allocation. For instance...
|
|
I was imagining one bit per push/pop. So from the 12bits not being used, 4 would allow jump and push, or jump and pop all registers. |
I don't think push/pop all registers are sensible operations. At least you'd like to keep the return value and address as-is. |
|
Some benchmarks with a sway compiler modified to use this instruction: build command
|
|
Should we align the naming more closely with RISCV instructions? ie. JAL -> jmp and link with only an immediate value operand |
|
|
||
| - `$rA` is a reserved register other than `$zero` | ||
| - `$rB + imm * 4 >= VM_MAX_RAM` | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we panic if $rB == $pc && imm == 0 to avoid jumping into the exact same spot?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likely not. It's not like you couldn't otherwise make an infinite loop if you want, and then you'll just run out of gas anyway.
## Description This PR contains an initial implementtion of subroutine calls using the in-progress [jump-and-link instruction `JAL`](FuelLabs/fuel-specs#630). It substantially reduces the function call overhead: the old code used 4 instructions per call, while the new version uses 1-3 depending on the distance to the called function. ### Future optimizations * Reorder functions, so those that call each other are adjacent * Use absolute or IS-relative jumps where it makes sense, see #7267 ## Checklist - [x] I have linked to any relevant issues. - [x] I have commented my code, particularly in hard-to-understand areas. - [ ] I have updated the documentation where relevant (API docs, the reference, and the Sway book). - [x] If my change requires substantial documentation changes, I have [requested support from the DevRel team](https://github.com/FuelLabs/devrel-requests/issues/new/choose) - [x] I have added tests that prove my fix is effective or that my feature works. - [x] I have added (or requested a maintainer to add) the necessary `Breaking*` or `New Feature` labels where relevant. - [x] I have done my best to ensure that my PR adheres to [the Fuel Labs Code Review Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md). - [x] I have requested a review from the relevant team or maintainers.
Closes #627. VM issue: FuelLabs/fuel-vm#857. VM PR: FuelLabs/fuel-vm#925.
The design is quite similar of the RISC-V of the same name.
JAL $ra $rb immstores the address of the next instruction to$ra, so that register can be used as a return address from the subroutine. Ifrais$zero, the value is discarded instead, so this can be used as a jump without having to trash a register. After storing the return address, it jumps to instruction at memory address$rb + imm * 4.The main purpose of this instruction is efficient subroutine-calling and returning.
JAL $ret_addr $subroutine_addr 0is used to perform the call, andJAL $zero $ret_addr 0returns from it. For nexted function calls, the callee is responsible for storing the$ret_addr.The following snippet shows a minimal program using the functionality:
Fibonacci example
To show off how compact code this makes, I wrote a small fibonacci function using it. The function here uses the following register-based ABI:
$fnargin0x10$return_addrin0x11Also the code uses the following locals:
$local1: 0x12, $local2: 0x13, $local3: 0x14(named forpshl/popl)Before requesting review