Vector API factories

John Rose john.r.rose at oracle.com
Tue Jul 18 00:43:40 UTC 2017


On Jul 17, 2017, at 5:20 PM, Paul Sandoz <paul.sandoz at oracle.com> wrote:
> 
> 
>> On 17 Jul 2017, at 16:55, Graves, Ian L <ian.l.graves at intel.com> wrote:
>> 
>> Hi Paul,
>> 
>> I love it!
>> 
>> I think you're right that it makes a lot of sense to offload instantiation routines to species and make them semi-concrete by element type.  This solves the issue of our element types being too unconstrained.  This approach lets us fix the instantiatable-element-types by exposing allowed ones through this semi-concrete species.  I think it also makes sense to refactor the vector construction methods to the Species class because instantiation is unique per-species and not per-vector.  That's a good play.
>> 
> 
> Ok. With that and separating FP and bitwise i think we have a reasonable API story.

I have to say that I'm having trouble visualizing this, but it sounds OK.
My main concern in the API design is that we allow suitable levels of
shape abstraction for common use cases.  That is, it should be possible
to code a loop that works across all shapes if you are just arranging
data.  And if you are doing FP stuff, it should be possible to code a
loop that works across all FP shapes (using a tighter bound on shape).

The point of shape-genericity is it gives us a way to write algorithms
that can be ported (even dynamically) to different vector sizes,
depending on late-breaking conditions (even profiling).  It also
gives more portability across ISAs, since shape determines
vector size, and if you allow generic shapes (subject perhaps
to lane characteristics) you can write one loop for multiple
platforms (that includes AVX2 vs. AVX512).  Finally, shape
polymorphism gives a "hook" for doing cleanup and setup
of loops, if you have special auxiliary shapes for those
tasks.

> 
>> 
>> 
>>> Also i am wondering about the horizontal reductions now returning a Vector.
>>> I can see why you did this, we really don’t want the primitive boxes being
>>> exposed and you can easily reuse the result in further calculations.
>>> 
>>> This works well for the fixed sized small vectors but what if we have different
>>> kinds of shape that signify a larger size?
>>> 
>>> An alternative is to move those reductions into the semi-concrete species. If
>>> there is a method to construct a new vector with an element at the first
>>> position then i bet the JIT can optimize to avoid register shuffling.
>>> 
>> 
>> Reductions are somewhat sensitive to species.  I can see how some operations that are more amenable to floating point (div, etc) would be better served to be placed in a more precise location.  Right now I think you're right that it makes sense to limit this placement to species and not Vector.
>> 
>> Would species form the basis of a future templated feature-set of Vector that could be dropped in?  Something that could come out of the enhanced generics work in Valhalla?
>> 
> 
> Yes, i think so. The lack of generics over primitives is steering me to keep Vector in the Vector world and species is the bridge to/from the Vector world.
> 
> Generics over values/primitives would be beneficial API-wise. Depending on the language features supported it may be possible to declare methods specific to the type parameter(s), so Vector<float> would have FP methods, where as Vector<int> would not (and vice versa for bitwise ops), thereby not requiring specific FP and bitwise interfaces.

Here's a stress test for shape genericity:  Can you use the same loop code
with different plugins for vectors of 2 doubles and vectors of 4 floats?
If you can say "any FP shape", then you ought to be able to bind the
same loop (on a machine where 128 bit vectors are native) to handle
both kinds of vectors in the same algorithm.

Going into the future, if we have genericity over byte/short/int/long, then
the same effect might show up when programming with a vector stream
of some lane type <any T>.  The platform logic would select the vector
size, and then the generic instantiation would expand the vector type
using the size (and type) of the lane and the size of the vector (which
is the shape-size).  So instantiating the same shape on <short> will
give four times as many lanes as instantiating it on <long>.  I think
this is all reasonable to do in the sort of specialization hooks we
are looking at.

Meanwhile, the selection of FP methods or not might be gated
by whether you said <float> or <int>, etc.  We have thought about
allowing conditional methods, gated on various factors.  FWIW,
the specific tactic that appeals to me is declaring additional bounds
on 'this' for selected methods, so in a Vector<any T,S> maybe there
is an arctan function with an extra bound of Vector<any T extends
FloatingPoint<T>>, S>.  Or maybe add piecemeal constraints on
in-scope type variables.  There are many ways to pull it off; the big
question is whether any of them are simple enough to analyze fully.

— John


More information about the panama-dev mailing list