[Bug c++/87631] new attribute for passing structures with multiple SIMD data members in registers

2018-10-17 Thread kretz at kde dot org
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.

[Bug c++/87631] new attribute for passing structures with multiple SIMD data members in registers

2018-10-17 Thread rguenth at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87631

Richard Biener  changed:

   What|Removed |Added

 Target||x86_64-*-*, i?86-*-*
  Component|other   |c++
   Severity|normal  |enhancement

--- Comment #1 from Richard Biener  ---
Note this will need target adjustments unless we go the
targetm.split_complex_arg
way of this (which is esp. ugly and should have been done in the regular ABI
handling way).

The other possibility would be of course to have the FEs handle this
attribute by adjusting calls and prototypes to this argument passing
convention accordingly.

Please specify how that attribute would work semantically and how you'd
name it and where you'd use it?  Sth like

struct X1 { V a, b; } __attribute__((pass_by_value_as_two_vector_args));

struct X2 { V a, b; int x } __attribute__((pass_by_value_as_two_vector_args));
// invalid

?  Or more general

struct X { ... } __attribute__((pass_by_value_as_pieces));

where individual fields are passed instead of the aggregate?  Does that
then mean individual copy-ctors need to be available for the members for
example?