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