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