Stream: git-wasmtime

Topic: wasmtime / issue #5401 Cranelift: Turn sret into a return...


view this post on Zulip Wasmtime GitHub notifications bot (Dec 08 2022 at 23:04):

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 the sret 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 turn sret 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.

view this post on Zulip Wasmtime GitHub notifications bot (Dec 08 2022 at 23:09):

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 usual x0). So the key idea is to allow CLIF to express this directly. The sret name is irrelevant; one might as well think of it as special-return-in-different-slot that happens to pick x8, 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).

view this post on Zulip Wasmtime GitHub notifications bot (Dec 08 2022 at 23:49):

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?

view this post on Zulip Wasmtime GitHub notifications bot (Dec 08 2022 at 23:51):

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?

view this post on Zulip Wasmtime GitHub notifications bot (Dec 08 2022 at 23:55):

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?

view this post on Zulip Wasmtime GitHub notifications bot (Dec 09 2022 at 00:04):

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