On Mon, Jun 30, 2025 at 11:22 AM Andrew Pinski <pins...@gmail.com> wrote:
>
> On Mon, Jun 30, 2025 at 11:10 AM Fractal Fir <fractalfir...@gmail.com> wrote:
> >
> > Hi!
> >
> > I am one of the folk currently working on `rustc_codegen_gcc`, and I 
> > thought that I will provide some more context.
> >
> > > So I looked into this further, it is not rust that specifies sret but
> > rather rust transformation into llvm code generation that does that.
> >
> > > So you need to explain what exactly what you need.
> >
> > The problem here is as follows:
> >
> > The Rust ABI is specified in terms of "PassMode"s. The `PassMode::Indirect` 
> > should *always* correspond to LLVM's `sret` attribute when applied to a 
> > return value.
> >
> > The Rust frontend is free to use `sret` however it pleases. It can choose 
> > to use it in cases where C would not, or not use it where C would.
> >
> > As an example:
> >
> > ```rust
> > #[repr(C)] // Same layout as in C
> > struct Foo {
> >     a: u128,
> > }
> >
> > #[unsafe(no_mangle)]
> > // Function with the Rust ABI:
> > extern "Rust" fn rust_func() -> Foo {
> >     Foo { a: 1 }
> > }
> > ```
> >
> > This struct will be passed via `sret` by Rust:
> > ```arm
> > rust_func:
> >         mov     w9, #1
> >         stp     x9, xzr, [x8]
> >         ret
> > ```
> >
> > However, GCC(following the C ABI) will pass the struct in a register:
> >
> > ```c
> > struct Foo{
> >     __uint128_t a
> > };
> > struct Foo c_func(){
> >     struct Foo res = {1};
> >     return res;
> > }
> > ```
> >
> > ```arm
> > c_func:
> >         mov     x0, 1
> >         mov     x1, 0
> >         ret
> > ```
> >
> > We need some way to force GCC to pass the return value in `sret`, to match 
> > the Rust ABI. Otherwise, we will get subtle ABI bugs.
>
> So to force GCC to the struct type in memory, you need to have
> TREE_ADDRESSABLE set on the RECORD_TYPE.
> I partly mentioned this but it looks like you missed that part.
>
> So in this case it looks like you need 2 different RECORD_TYPEs, one
> which has TREE_ADDRESSABLE set on it and one without it.
> You can use VIEW_CONVERT_EXPR to "convert" between the 2 as needed.
> You use the one with TREE_ADDRESSABLE not set for the C
> arguments/return types and then use the rest otherwise.
>
> CALL_EXPR_RETURN_SLOT_OPT is a separate (though related) issue.
>
> I hope this helps. And the C++ front-end uses TREE_ADDRESSABLE for
> non-pod (for ABI reasons) in a similar way.

One more question, where is this documented if at all? Because I
looked into the rust language/compiler specifications and didn't see
it anywhere.
Why not just change rustc_codegen_gcc code generation to the same as
what the target wants for a C like struct always?

Thanks,
Andrew


>
> Thanks,
> Andrew Pinski
>
>
> >
> >
> > We need to do so both on the calle and the caller side. I believe 
> > `CALL_EXPR_RETURN_SLOT_OPT` is applied on the caller side only, which is 
> > insufficient for our purposes.
> >
> > Is there something we could use to achieve this effect?
> >
> > If no, I'd be willing to work on adding such an attribute. Do you have a 
> > rough idea about where I should start?
> >
> > Thank you for taking the time to help us with this issue!
>
> >
> >
> >
> > On Mon, 30 Jun 2025 at 19:31, Antoni Boucher <boua...@zoho.com> wrote:
> >>
> >> 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 <boua...@zoho.com> wrote:
> >> >>
> >> >>
> >> >>
> >> >> Le 2025-06-29 à 19 h 42, Andrew Pinski a écrit :
> >> >>>
> >> >>>
> >> >>> On Sun, Jun 29, 2025, 4:36 PM Antoni Boucher <boua...@zoho.com
> >> >>> <mailto:boua...@zoho.com>> wrote:
> >> >>>
> >> >>>
> >> >>>
> >> >>>      Le 2025-06-29 à 10 h 46, Andrew Pinski a écrit :
> >> >>>       >
> >> >>>       >
> >> >>>       > On Sun, Jun 29, 2025, 7:43 AM Andrew Pinski <pins...@gmail.com
> >> >>>      <mailto:pins...@gmail.com>
> >> >>>       > <mailto:pins...@gmail.com <mailto:pins...@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.
> >> >>>       >
> >> >>>
> >> >>
> >>

Reply via email to