Manually set sret parameter
Antoni Boucher
bouanto@zoho.com
Mon Jun 30 17:31:36 GMT 2025
Hi.
Let me introduce you Fractal Fir who's a student working on
rustc_codegen_gcc for the Google Summer of Code.
He found some ABI issues (one related to sret) in rustc_codegen_gcc and
wanted to join this discussion in order to share more details about what
we want to achieve here.
Thanks.
Le 2025-06-30 à 10 h 51, Andrew Pinski a écrit :
> On Mon, Jun 30, 2025 at 7:25 AM Antoni Boucher <bouanto@zoho.com> wrote:
>>
>>
>>
>> Le 2025-06-29 à 19 h 42, Andrew Pinski a écrit :
>>>
>>>
>>> On Sun, Jun 29, 2025, 4:36 PM Antoni Boucher <bouanto@zoho.com
>>> <mailto:bouanto@zoho.com>> wrote:
>>>
>>>
>>>
>>> Le 2025-06-29 à 10 h 46, Andrew Pinski a écrit :
>>> >
>>> >
>>> > On Sun, Jun 29, 2025, 7:43 AM Andrew Pinski <pinskia@gmail.com
>>> <mailto:pinskia@gmail.com>
>>> > <mailto:pinskia@gmail.com <mailto:pinskia@gmail.com>>> wrote:
>>> >
>>> > On Sun, Jun 29, 2025, 7:36 AM Antoni Boucher via Gcc
>>> > <gcc@gcc.gnu.org <mailto:gcc@gcc.gnu.org>
>>> <mailto:gcc@gcc.gnu.org <mailto:gcc@gcc.gnu.org>>> wrote:
>>> >
>>> > Hi.
>>> > Is there a way in GENERIC to specify that a parameter will be
>>> > passed in
>>> > "sret", or is this solely controlled by the hook
>>> struct_value_rtx?
>>> >
>>> >
>>> > It is only controlled by the hook.
>>> > What exactly are trying to do?
>>> > You could set the return slot optimization bit on the call
>>> > expression if you want the lhs of a call not to be copied and
>>> just
>>> > passed as the address via sret.
>>>
>>> I'm trying to follow the Rust ABI for rustc_codegen_gcc: they manually
>>> specify whether a param is "sret".
>>>
>>>
>>> Not all ABI/targets have a sret specific register. So this is even more
>>> confusing.
>>>
>>>
>>>
>>> >
>>> > That is if you have:
>>> > StructVar = func(...);
>>> >
>>> > You set the return slot optimization bit on the call expr in
>>> generic
>>> > and which will copy that bit to the gimple GIMPLE_CALL and then
>>> > during expand will again copy it back to the generic
>>> call_expr and
>>> > expand will use the target for the address.
>>> >
>>> >
>>> > CALL_EXPR_RETURN_SLOT_OPT is the macro.
>>>
>>> Is this a guaranteed optimization? I'm asking because this is for ABI
>>> correctness and I need a solution that will always work.
>>> If not, would there be another way to do this?
>>> Thanks.
>>>
>>>
>>> Yes it is guaranteed that if the return type is returned via memory
>>> reference to the other function it will use that memory location.
>>
>> How does this work on the side of the function declaration? Do we need
>> to set something so that it follows the correct convention?
>
> So there are 2 separate things here.
> First there is an ABI of having struct return in memory.
> Note if TREE_ADDRESSABLE is set on a struct type, then return value is
> always through memory:
> ```
> In ..._TYPE nodes, it means that objects of this type must be fully
> addressable. This means that pieces of this object cannot go into
> register parameters, for example. If this a function type, this
> means that the value must be returned in memory.
> ```
> The ABI part is independent of the CALL_EXPR and dependent on the
> FUNCTION_TYPE that is being used and the target.
>
> Second is specifying if you can reuse the memory of the lhs of a
> modify_expr with a call_expr when the ABI says the memory is return in
> memory.
> This is specified via CALL_EXPR_RETURN_SLOT_OPT on the CALL_EXPR.
>
> I am trying to understand how the rustc front-end sets up this. Does
> it implement the ABI of each target as that is needed for LLVM?
> This is the major difference here as GCC's front-ends normally don't
> care much about the ABI except in specific cases (e.g. returns this
> and a few others). GCC's front-end don't handle the call argument ABI
> at all; rather it is more like you build call_expr which act like
> function calls in C (well with the addition of reference types but
> those are really just pointers at that point). And the middle-end
> (with help from the backend) which implements the full ABI.
>
> The reason why this is done this way is an abstraction layer and
> allows new front-ends for backends that are known to it at the time
> without additional work (e.g. gfortran adding support for riscv or
> aarch64; no changes to the front-end were made). This seems like the
> opposite of LLVM where there is no tight coupling of the 2 and there
> is no abstraction for most of the ABI call work and each front-end
> needs to implement that again.
>
> Hope this helps explain GCC front-end interactions with the GCC's
> middle-end better.
>
>>
>> Thanks a lot for your help.
>>
>>>
>>> Even for things like a->b = func(...)[RSO]. It is even used by the c++
>>> frontend that way.
>>>
>>>
>>>
>>> >
>>> >
>>> >
>>> > Is that what you are looking for?
>>> >
>>> >
>>> > Thanks,
>>> > Andrew
>>> >
>>> > Thanks.
>>> >
>>>
>>
More information about the Gcc
mailing list