Re: Request: __attribute__((vector_size))

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: Request: __attribute__((vector_size))

Alexander Nicholi
 > Technically it wouldn't be too much work to semantically support that

How involved would it be? My mainstay with work is writing C, but my
experience with compiler internals is limited.

We’re interested in having this syntax, as we use TCC for
quick-iteration builds of our game engine. As we may end up using SIMD
in the near future, being able to continue development with TCC would be
a boon for time.

We understand the relationship TCC bridges between simplicity and speed,
and have been using it to make quick debug builds for this reason.

 > but the values would need to be committed to memory (instead of
vector registers) and regarded as constant sized arrays (at which point
the function call ABI would be different from the respective native ABI,
which, again, would be hard to fix without proper support for vector
insns in the backends).

With its lack of optimisation flags, would it not be unreasonable to
expect performant code anyway? This should be acceptable given TCC’s
niche. I think the basic behaviour should be enough, at least for
purposes like ours.


_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel
Reply | Threaded
Open this post in threaded view
|

Re: Request: __attribute__((vector_size))

Michael Matz-4
Hello,

On Sun, 26 Jan 2020, Alexander Nicholi wrote:

> > Technically it wouldn't be too much work to semantically support that
>
> How involved would it be? My mainstay with work is writing C, but my
> experience with compiler internals is limited.

You need a new type category for CType (see tcc.h/VT_BTYPE).  I'd probably
go with the vectors being a complete new base type, because they have
value, not reference, semantics (unlike arrays, which are encoded as a
specially marked pointer type), and because they are final (i.e. no
vectors of vectors), so can be regarded as base type.  So, a new value
fitting into VT_BTYPE.  The elements type and size needs to be encoded in
the other bits (there are enough free bits).  Then you start hacking
either parse_btype or parse_attribute, probably in connection with
type_decl or post_type, to parse the syntax for vector types that you
want, and to set the right type for the decl in question.

You need to make a decision if you want to allow vector values to sit in
registers, or if you first want to always commit them on the stack.

Then you add various asserts at places that the type of vtop is no vector
type, and then you slowly but surely fix all the asserts you can trigger
with example code.

You need to change at least the following routines:
type_size: so that vector types are correctly sized
decl_initializer_alloc: for allocating vector-typed decls
gen_op: so that binary operations on vectors are expanded to the
  respective operations elementwise.
vstore: so that vector values can be stored at arbitrary locations (here
  vectors can be regarded as funny structs, i.e. memcpy)
gv: depending on the decision above (regs or only mem) this needs either
  code to accept that some values (vectors) aren't placed in registers, or
  the backends need code in load() to load into vector registers.
  If you decide on mem only (should be easier first) then the special code
  in gen_op to deal with vectors element-wise might make it so that gv()
  is never called on vector operands (i.e. you can leave the assert you've
  added earlier)
unary: for the post operations, for vectors that's array indexing

At this point you should be able to compile stuff like

-----
typedef int siv4 __attribute__((vector_size(16)));
int foo (int i)
{
  siv4 v4, w4;
  v4[0] = i; v4[1] = i + 1; v4[2] = i + 2; v4[3] = i + 3;
  w4[0] = i; w4[1] = i + 1; w4[2] = i + 2; w4[3] = i + 3;
  v4 = v4 + w4;
  return v4[0] + v4[1] + v4[2] + v4[3];
}
-----

Note how that avoids passing or returning vector types.  For that you need
to change the backends, e.g. in x86_64-gen.c:
gfunc_prolog: for accepting and setting up vector type parameters
gfunc_call: to pass vector arguments to callees
gfunc_sret: to return vector arguments

If you decide to implement your own ABI (e.g. without vector registers,
passing vectors in memory by value) life will be a bit easier and you
might implement most of it outside the backends in generic code, in
tccgen.c: unary (for function calls and acceptance of returned values),
and gfunc_return for the return statement.

Then assorted things like decl_initializer (to accept initializers for
vector variables), gen_cast and so on.


> > but the values would need to be committed to memory (instead of
> vector registers) and regarded as constant sized arrays (at which point the
> function call ABI would be different from the respective native ABI, which,
> again, would be hard to fix without proper support for vector insns in the
> backends).
>
> With its lack of optimisation flags, would it not be unreasonable to expect
> performant code anyway? This should be acceptable given TCC’s niche. I think
> the basic behaviour should be enough, at least for purposes like ours.

Quite possible, I was just mentioning it.


Ciao,
Michael.
_______________________________________________
Tinycc-devel mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/tinycc-devel