https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87631
--- Comment #2 from Matthias Kretz <kretz at kde dot org> --- My (current) use case is structures (nested) of builtin types and vector types. These structures have a trivial copy constructor. Generalization --------------- I believe generalization of this approach should be possible, but I'm not sure how useful it would be. E.g. struct [[gnu::pass_via_register]] A { int a; std::vector<int> b; }; void f(A); could call f by "unpacking" A and call f'(int, std::vector<int>). I believe the effort of supporting types with non-trivial copy ctor is not worth the effort (such types are typically passed via const-ref anyway). What I believe is worthwhile ----------------------------- pass_via_register (max_registers) This attribute, attached to a struct type definition, specifies that function arguments and function return values are passed via up to max_registers registers, thus potentially using a different calling convention. If the number of registers required for passing a value exceeds max_registers, the default calling convention is used instead. Specifically, `struct S { int a, b, c; } __attribute__((pass_via_register(1)));` may still pass via two registers if it would do so without the attribute. If a structure has a single non-static data member of a type declared with the pass_via_register attribute, the attribute is also applied to the outer structure: struct S { ... } __attribute__((pass_via_register(4))); struct inherited { S x; }; // implicit pass_via_register(4) If a structure has two or more non-static data members the resulting type does not inherit the pass_via_register attribute. You may only specify this attribute on the definition of a struct, not on a typedef that does not also define the structure. Example from std::experimental::simd ------------------------------------- using V = simd<float, __sse_x<2>>; This essentially asks for { __m128[2] }, similar to `float attribute((vector_size(32)))` when AVX is not available, except that I'd like to pass arguments and return values via registers: V f(V x, V y); Function f reads x from %xmm0 and %xmm1, y from %xmm2 and %xmm3, and returns via %xmm0 and %xmm1. The simd class would be defined like this (note that `simd` itself would not have the attribute): template <class T, class Abi> class member_type; template <int N> class [[gnu::pass_via_register(4)]] member_type<float, __sse_x<N>> { using V [[gnu::vector_size(16)]] = float; V data[N]; }; template <class T, class Abi> class simd { member_type<T, Abi> data; }; simd inherits the pass_via_register(4) attribute from its data member because it has only one data member. ill-formed ----------- I'd make the following ill-formed: struct [[gnu::pass_via_register]] A { A(const A &); }; The non-trivial copy ctor clashes with pass_via_register. dropping the attribute ----------------------- Example: struct X { simd<float, __sse_x<2>> a; int b; }; a is pass_via_register, b in principle is pass_via_register (on x86_64), but X is not (two or more non-static data members). The default calling convention applies. implementation strategy ------------------------ I don't see how the frontend could reliably implement the attribute. Does the frontend know whether a certain type is passed via register (and how many)? E.g. `void f(int)` passes via the stack on i686. `struct S { int a, b; };` passes via a single register on x86_64, unpacking `f(S)` to `f(int, int)` would be suboptimal.