[rust-dev] RFC: Tuple Swizzling/Shuffling

Carter Schonwald carter.schonwald at gmail.com
Tue Jan 14 12:14:01 PST 2014


good points all!

why not have the operation just be
shuffleSimdVector(a,b,masktuple) ?
seems a bit more human friendly than a   mix of @ and <- and ->

I'm a bit confused about the l/rvalue remark, could you explain more?


On Tue, Jan 14, 2014 at 3:06 PM, Richard Diamond <
wichard at vitalitystudios.com> wrote:

>
> On Tue, Jan 14, 2014 at 1:07 PM, Carter Schonwald <
> carter.schonwald at gmail.com> wrote:
>
>> Neat proposal:
>> thoughts
>> 0) seems like you need to add a notion of const expr to the type system
>> for this proposal, right? I started staring at that and it's pretty subtle
>> (though I may have been looking at it wrong)
>>
> I did add the const expr notion a bit, but it's only in anticipation of
> somebody wanting to specify the mask in such terms. Of course, boarder
> support for const expr's would be required.
>
> 1) do rust tuples actually map to the llvm simd vector types?
>>
> They do with #[simd]. Though I think it would be worth considering whether
> all tuples of a single primitive type should be automatically considered
> #[simd] and be lowered to a LLVM vector type. In fact one way I'm
> considering impling this is to treat the mask as a tuple and lower it as a
> vector into a shufflevector mask operand.
>
> 2) so this would require some special syntax support right? Could it be
>> prototyped with a procedural macro plus having the shuffle ast code
>> generated internally?
>>
> Yes. Sadly not; I've tried. Moreover procedural macros don't exist at a
> stage where tuple type info is known, so such a macro would only be able to
> operate on literals and still wouldn't be able to dictate trans.
>
> 3) would the internal rep properly treat the shuffle mask ints as part of
>> the op itself so that it won't get cse'd or the like?
>>
> Yes.
>
> 4) would the syntax do a type / syntax error when you use a tuple position
>> index that's too large?
>>
> Yes.
>
>
>> 5) the llvm shuffle vector intrinsic takes two vectors of values and
>> let's you express interleaving them, not just rearranging a single one
>> (which seems to be a restriction on your example).  Both styles matter, and
>> respectively correspond to different platform specific shuffle instructions
>>
> Yeah, not even ten minutes after sending the proposal, I realized I had
> forgotten about that one detail. I'm not terribly fond of any of my
> envisioned solutions, but the best one uses the recently removed '@':
> let vec1 = (10, 11, 12, 13);
> let vec2 = (9, 8, 7, 6);
> let shuffled = vec1 @ vec2 -> (7, 6, 5, 4, 0, 1, 2, 3); // think
> concATenate; it'll likely be thought of as such in rustc.
>
>  As an aside, note the arrows point towards what type of value the
> expression is supposed to be (lvalue is <-, rvalue is ->).
>
> I like the idea of something like this, and it's definitely simpler than
>> the shuffle proposals I've been trying to draft, though using a word like
>> "shuffle" may be. Though it doesn't give a way to use the same idea for
>> someone using the platform specific shuffle intrinsics that hopefully would
>> be added eventually. (Any such platform specific intrinsics would be for
>> fixed tuple size and type).
>>
> Thank you!
> The intent is to lean on LLVM's platform independenceness; LLVM supports
> vectors (the SIMD type) of any length, so in an effort to be forward
> compatible with future SIMD sizes, offer a generic way to 'do the shuffle'.
> Access to more specialized shuffles could be done via functions with a
> #[link_name] attribute (because such instructions operate on operands of
> specific types anyway, they wouldn't be very amenable to a generic
> solution) in unstable::simd or an external library. But that's another
> project ;)
>
>>
>> *An Alternative approach*? *Int *
>>
>> One way around the const expr requirement for the type system
>> that someone suggested was pretty neat: expose the various platform
>> specific simd shuffle ops, an have their shuffle mask int args actually be
>> "type args". Apparently there's some protean support for type level numbers
>> because of sized vectors, and because rust requires all generics to be
>> monomorphized, this actually would capture the right "constness at compile
>> time"
>>
>
>> an example of this idea would be to take the VSHUFPD intel instruction
>> (in the intel architecture), and modify the intrinsic from the c code
>> version
>>
>> (nb: __m256d == v4f64 in rust parlance)
>>   __m256d _mm256_shuffle_pd (__m256d a, __m256d b, const int select);
>>
>> into
>>
>> fn  _mm256_shuffle_pd<const int select>(__m256d a, __m256d b)-> __m256d
>>
>> I'm not sure how such a type level int application would work out, but It
>> may be the nicest way to conservatively add type safe SIMD  shuffle primops
>> to rust, though I could be completely wrong. (I was initially meh on this
>> type application idea, but its grown on me, it exploits the way rust
>> generics work very very nicely!)
>>
>> *note* while exposing the architecture specific intrinsics would be bit
>> more work, it would also mean that the SIMD support in rust have a more
>> transparent mapping to various architectures, allow better architecture/cpu
>> microarchitecture based tuning (writing an version of BLIS
>> http://code.google.com/p/blis/ in rust might be a good stress test), and
>> it'd be less coupled to the vagaries of how LLVM lowers the shuffle
>> instruction to the target architecture. This actually matters in the
>> context of writing code that uses the "optimal" instruction sequence by
>> detecting the cpu micro architecture at runtime and branching to the tune
>> variant internally, something OpenBLAS does very nicely, see here for
>> examples https://github.com/xianyi/OpenBLAS/tree/develop/kernel/x86_64
>>
>> That said, having a systematic way to support the llvm shuffle intrinsic
>> In it's full generality would be lovely, it's a much more friendly
>> operation that people can use to get started with doing simd in a somewhat
>> user friendly way.
>>
>> point being: I support there being better shuffle simd support / simd
>> support period :), though how to do  it best seems unclear to me (and
>> theres also a few ways that arent good too)
>> -Carter
>>
>>
>> On Tuesday, January 14, 2014, Richard Diamond wrote:
>>
>>> Basically the idea here is to support shuffling for SIMD types in a way
>>> that can be easily lowered to IR (LLVM's shufflevector requires the mask be
>>> a vector of constants, so an intrinsic function is out of the question),
>>> however I image this sugar could extend to tuples with multiple types.
>>>
>>> Some examples:
>>>
>>> let vec = (1.0f32, 2.0f32, 3.0f32, 4.0f32);
>>> let all_x = vec -> (0, 0, 0, 0); // perhaps this should be "vec <- (0,
>>> 0, 0, 0)"?
>>> assert_eq!(all_x, (1.0f32, 1.0f32, 1.0f32, 1.0f32));
>>> let single_x = vec -> (0);
>>> assert_eq!(single_x, (1.0f32));
>>>
>>> let mut vec = vec;
>>> vec <- (0) = 5.0f32; // set x only
>>> vec <- (1, 2) = (6.0f32, 7.0f32) // set y & z
>>> assert_eq!(vec, (5.0f32, 6.0f32, 7.0f32, 4.0f32));
>>>
>>> let vec = vec;
>>> // the mask may be arbitrarily long:
>>> assert_eq!(vec -> (0, 1, 2, 3, 0), (5.0f32, 6.0f32, 7.0f32, 4.0f32,
>>> 5.0f32));
>>>
>>> // leaves vec unchanged
>>> let functional_update = vec -> (0, 1, 3) .. (0.5f32, 1.0f32, 10.0f32);
>>> // functional_update would take it's type from vec
>>> assert_eq!(vec, (5.0f32, 6.0f32, 7.0f32, 4.0f32));
>>> assert_eq!(functional_update, (0.5f32, 1.0f32, 7.0f32, 10.0f32));
>>>
>>> A couple of things would need to be disallowed, however:
>>>
>>> let mut vec = vec;
>>> // no duplicate assignments/functional updates:
>>> vec <- (0, 0) = (..);
>>> let _ = vec -> (0, 1, 2, 3, 0) .. (..);
>>> // no out-of-bounds:
>>> vec <- (5, 9000) = (..);
>>> let _ = vec -> (5, 9001);
>>> let _ = vec -> (5, 9002) .. (..);
>>> let _ = vec -> (0, 1, 2, 3, 4) .. (..);
>>> // all mask values must be a const expr:
>>> let mut non_const_expr = 15;
>>> vec <- (non_const_expr) = (..);
>>> let _ = vec -> (non_const_expr) .. (..);
>>> let _ = vec -> (non_const_expr);
>>> // mismatched tuple sizes:
>>> vec <- (0, 1) = (0.0f32, 0.0f32, 0.0f32);
>>> let _ = vec -> (0) .. (0.0f32, 0.0f32);
>>>
>>> AIUI, the notation would be:
>>> tuple_mask : '(' integer [ ',' integer ] * ')' ;
>>> tuple_expr : '(' expr [ ',' expr ] * ')' |
>>>                   tuple_expr "->" tuple_mask [ ".." tuple_expr ] ? ;
>>>
>>> I'm willing to write this myself, but I'd like some consensus/feedback
>>> regarding ze proposed sugar.
>>>
>>
>
>
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20140114/fbf83cf7/attachment-0001.html>


More information about the Rust-dev mailing list