https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87631
--- Comment #2 from Matthias Kretz ---
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 b;
};
void f(A);
could call f by "unpacking" A and call f'(int, std::vector). 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>;
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 member_type;
template
class [[gnu::pass_via_register(4)]] member_type> {
using V [[gnu::vector_size(16)]] = float;
V data[N];
};
template class simd {
member_type 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> 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.