Thank you so much for the help! It seems like the TREE_ADDRESSABLE bit is indeed what we have been looking for.
In regards to your questions: Sadly, most of this is barely documented if at all. The rust compiler documentation is... not good. I only know about this because somebody mentioned this in the Rust compiler chat when I asked about an ABI bug. The only place where this is mentioned at all is the compiler source code, in: https://github.com/rust-lang/rust/blob/64033a4ee541c3e9c178fd593e979c74bb798cdc/compiler/rustc_codegen_llvm/src/abi.rs#L464-L468 . > Why not just change rustc_codegen_gcc code generation to the same as what the target wants for a C like struct always? Even tough the Rust compiler ABI is not *stable*, it is still a real ABI all backends need to follow. In principle, LLVM, cranelift, and GCC should agree about the Rust ABI for a given compiler version. The idea is that people should be able to mix & match Rust code compiled with different compiler backends. We even have an ABI compatibility test suite: https://github.com/Gankra/abi-cafe. This is something that already runs in CI for each commit(for some backend combos) and something that we plan to use more extensively. While we could change the Rust ABI to only use `sret` where C would, that is very unlikely to happen. It is also not my decision to make. The Rust developers want to have freedom in how the ABI is defined, to continuously improve it in the future. There is also some fear regarding the brittleness of this approach. I believe the `abi-cafe` tool uncovered cases where clang and GCC disagreed on the C ABI, I think in regards to 128 bit ints on Windows. So, the fear here is that we would accidentally carry some of those bugs over to Rust. In theory, as long as each backend follows the frontends directions to the letter, the ABI should always match between the backends. That *should*, hopefully, mean we have a matching ABI between all the backends. Regards, Fractal Fir On Mon, 30 Jun 2025 at 20:32, Andrew Pinski <pins...@gmail.com> wrote: > 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. > > >> >>> > > > >> >>> > > >> >> > > >> > On Mon, 30 Jun 2025 at 20:32, Andrew Pinski <pins...@gmail.com> wrote: > 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. > > >> >>> > > > >> >>> > > >> >> > > >> >