elliottt opened issue #5401:
Feature
Currently, struct return is enabled in cranelift via the
sret
parameter annotation. This annotation marks the parameter as a required input, and also signals to the abi that this value will be returned and may need special handling. As the value is not explicitly returned, the lowering module is responsible for tracking and returning that parameter in an abi-defined location. Cranelift itself doesn't write data to the memory pointed to by thesret
param, and instead relies on the clif producer to write data out.Since cranelift itself doesn't need to know that an input will ultimately be used as an
sret
location, I'd like to propose that we turnsret
into an annotation on a return type instead. For example, consider this existing function:function %f0(i64 sret) { block0(v0: i64): v1 = iconst.i64 42 store v1, v0 return }
As the consumer is already responsible for writing to
v0
, and cranelift has no other need to know that the parameter will ultimately be a struct return, we could instead implement it as the following:function %f0(i64) -> i64 sret { block0(v0: i64): v1 = iconst.i64 42 store v1, v0 return v0 }
Benefit
This change would simplify the lowering code a bit, and make it more clear that struct returns are for the most part coordinated by the clif producer; cranelift only needs to know about a struct return to satisfy the requirements of the abi it's targeting.
Implementation
This should be a fairly straight forward refactoring.
Alternatives
We can certainly leave struct return the way it is, keeping the connection between the parameter and return value.
cfallin commented on issue #5401:
Strong +1 to this; in discussions about it, we started from the principle that CLIF should provide all the necessary primitives to conform to an ABI, but no more. "Struct return" as a concept is out-of-place in CLIF because CLIF does not have structs. Rather, the relevant detail here is that some ABIs when returning structs require a pointer to that struct to be returned in a different register than normal (
x8
on aarch64, vs. the usualx0
). So the key idea is to allow CLIF to express this directly. Thesret
name is irrelevant; one might as well think of it asspecial-return-in-different-slot
that happens to pickx8
, etc. The reification of the flow from input arg to output is important too as it avoids the need to special-case this (a hidden SSA value generated by ABI code essentially).
afonso360 commented on issue #5401:
For AArch64 this is covered in the AAPCS64 Section 6.9:
[...] The address of the memory block shall be passed as an additional argument to the function in x8. The callee may modify the result memory block at any point during the execution of the subroutine (there is no requirement for the callee to preserve the value stored in x8).
If I'm reading this correctly requires that the struct return argument is passed into the callee in x8. But when exiting the function x8 can be whatever the callee wants. Which would be better represented as
sret
on a function argument right?
afonso360 edited a comment on issue #5401:
For AArch64 this is covered in the AAPCS64 Section 6.9:
[...] The address of the memory block shall be passed as an additional argument to the function in x8. The callee may modify the result memory block at any point during the execution of the subroutine (there is no requirement for the callee to preserve the value stored in x8).
If I'm reading this correctly, it requires that the struct return argument is passed into the callee in x8. But when exiting the function x8 can be whatever the callee wants. Which would be better represented as
sret
on a function argument right?
afonso360 edited a comment on issue #5401:
For AArch64 this is covered in the AAPCS64 Section 6.9:
[...] The address of the memory block shall be passed as an additional argument to the function in x8. The callee may modify the result memory block at any point during the execution of the subroutine (there is no requirement for the callee to preserve the value stored in x8).
If I'm reading this correctly, it requires that the struct return argument is passed into the callee in x8. But when exiting the function x8 is clobbered. Which would be better represented as
sret
on a function argument right?
afonso360 edited a comment on issue #5401:
For AArch64 this is covered in the AAPCS64 Section 6.9:
[...] The address of the memory block shall be passed as an additional argument to the function in x8. The callee may modify the result memory block at any point during the execution of the subroutine (there is no requirement for the callee to preserve the value stored in x8).
If I'm reading this correctly, it requires that the struct return argument is passed into the callee in x8. But when exiting the function x8 is clobbered. Which would be better represented as
sret
on a function argument right?Edit:
For RISC-V I've found the RISC-V ELF psABI:
Values are returned in the same manner as a first named argument of the same type would be passed. If such an argument would have been passed by reference, the caller allocates memory for the return value, and passes the address as an implicit first parameter.
Note | There is no requirement that the address be returned from the function and so software should not assume that a0 will hold the address of the return value on return.
I assume that here the "implicit first parameter" means, always use a0. But it looks like a fairly similar mechanism to AArch64 where its more like a special argument than a special return value.
Last updated: Dec 23 2024 at 13:07 UTC