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
dialects: riscv-func add initial function call lowering #929
dialects: riscv-func add initial function call lowering #929
Conversation
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.
Thank you! There are a few changes from my branch that I was hoping to clean up before merging, could you please address the comments?
07524c3
to
876f15a
Compare
26f3cc4
to
51b2390
Compare
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.
Thank you, code mostly looks good to me, could you please remove the remaining TODOs?
GitHub automatically deleted the target branch of this PR, and clsoed the PR instead of retargeting it to main. Sorry about that. |
2ae064f
to
7185a6f
Compare
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.
Could you please rebase again?
7185a6f
to
b8ba98e
Compare
…gue register constraints compliant to conventions
… from JalOp def to Func CallOp
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.
Looks really nice, thanks! Left just one question in review.
xdsl/transforms/lower_riscv_func.py
Outdated
if func_op is not None: | ||
assert isinstance(func_op, riscv_func.FuncOp) | ||
if func_op.func_name.data == "main": | ||
# Main does not return, call exit syscall instead |
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.
Probably I'm missing something here but why main
doesn't return?
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.
Where would it return to? My understanding is that main
is kind of just the entry point to the .text
section, and not a "real" function
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.
main
always returns as a regular function, what happens later depends on the platform. On bare metal it's usually a super simple wrapper (crt0
) that takes care of the return value but since we already have syscalls in the mix we are assuming a full fledged OS (e.g.: on linux-gnu
is _libc_start_main
that also does some flavor of exit
syscall). I would say that the compiler has zero knowledge of who's going to invoke main
(not really sure it's always true tho...).
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.
...it's a much bigger topic tho, maybe this PR is not the right place to figure it out :) Approving as it is because it's really nice overall.
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.
Ah no I'd love your input, we don't need to merge it as-is. It seems that we could simplify this PR by removing the syscall special case, if I understand you correctly. At the least, some lever higher than riscv-func could be made to deal with this, maybe the llvm to riscv lowering.
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.
I think the truth is somewhere in the middle and that seems to be acknowledged in the C standard at least:
A return
statement with a integer compatible value implies a call to exit
.
If there is a plain return
the termination status to the host environment is undefined which is the same as declaring void main()
.
More frustrating details here: https://en.cppreference.com/w/c/language/main_function.
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.
That seems to be at a slightly higher level of abstraction to me, I think that's something that should be handled at the llvm level, unless I'm missing something
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.
No objection there.
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.
Thank you for the discussion, removed special handling of main
function
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.
Thanks for the changes, looks super neat!
LGTM, @AntonLydike, WDYT? |
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.
It's very nice to see work continue in this direction! Although I want to re-iterate, that I feel that we are "just winging" API/ABI here. I don't think that's a very good direction to take.
Furthermore, I think we need some unit tests on the verifiers here!
xdsl/dialects/riscv_func.py
Outdated
name = "riscv_func.call" | ||
args: Annotated[VarOperand, riscv.RegisterType] | ||
func_name: OpAttr[StringAttr] | ||
result: Annotated[OptOpResult, riscv.RegisterType] |
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.
I'm pretty sure that we want to have VarResult
here instead. It's common to return values in multiple registers to prevent values spilling to the stack (e.g. when returning a 64 bit value, or a struct)
xdsl/dialects/riscv_func.py
Outdated
"""RISC-V function return operation""" | ||
|
||
name = "riscv_func.return" | ||
value: Annotated[OptOperand, riscv.RegisterType] |
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 also be VarOperand
xdsl/dialects/riscv_func.py
Outdated
"""RISC-V function definition operation""" | ||
|
||
name = "riscv_func.func" | ||
args: Annotated[VarOperand, riscv.RegisterType] |
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.
Why does the function definition take arguments here?
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.
Ah that's a good point, they should not be here indeed
args: Annotated[VarOperand, riscv.RegisterType] | ||
func_name: OpAttr[StringAttr] | ||
func_body: SingleBlockRegion | ||
|
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.
I feel this is missing a function_type
style annotation? @superlopuh what's your opinion on that?
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.
I'm still not exactly sure when we need it and when we don't. I guess it doesn't hurt, and should help with printing/parsing more cleanly
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.
Thank you @eymay ! This looks really cool!
But maybe we should make issues for the cases that are not covered yet:
- (register spilling)
- non-main functions
Would be nice to have this soon, I'm happy to address remaining comments and merge in the next couple of days |
@AntonLydike I addressed your comments |
The current register allocator for the RISC-V dialect exclusively utilizes j-registers for unallocated values. However, @compor and I propose an improvement over the existing allocator by introducing a naive strategy that leverages the available real RISC-V registers for each block. In case the real registers are exhausted, the allocator gracefully falls back to j-registers. This enhancement brings forth several important questions that need to be addressed at this stage: - Determining the Set of Available Registers: The choice of available registers depends on the ABI and the adopted calling convention. So, we probably want to determine a target for now and see how it involves other topics (like function handling see #929). - Efficiency Requirements for Future Work: We might need to establish the desired level of efficiency for the register allocator (linear scan, ...) and the relevant use cases. Moreover, this improvement is contingent on the merging of the LabelOp into the main branch. For further details regarding the LabelOp merge, please refer to the following pull request #994. --------- Co-authored-by: Chris Vasiladiotis <cvassiladiotis@gmail.com>
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.
LGTM
@@ -58,18 +58,18 @@ class CallOp(IRDLOperation): | |||
name = "riscv_func.call" | |||
args: Annotated[VarOperand, riscv.RegisterType] | |||
func_name: OpAttr[StringAttr] | |||
result: Annotated[OptOpResult, riscv.RegisterType] | |||
ress: Annotated[VarOpResult, riscv.RegisterType] |
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.
nit: should this be results
or res
? ress
looks a bit weird?
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.
results is reserved, res to me implies singular, and ress is weird, alternative suggestions welcome
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.
To be honest results already works, I expect people will use that, we can always rename it later
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.
sure!
together with prologue and epilogue register constraints compliant to conventions.
Integrated this branch with reference to the sasha/workshop-all branch.