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. > >> >>> > > >> >>> > >> >> > >>