seeding the pot for 2.0 features

Mikola Lysenko mclysenk at mtu.edu
Sun Jan 28 07:42:02 PST 2007


Chad J wrote:
> Low dimensional primitive vectors would rock.  I have to wonder though 
> if array operations would do the trick instead though, especially with 
> static arrays.
> 
> uint4 foo;
> uint4 bar = someDefaultValue;
> foo.x = x;
> foo.y = y;
> foo.z = z;
> uint4 result = foo + bar;
> 
> becomes
> 
> uint[4] foo;
> uint[4] bar = someDefaultValue;
> foo[0] = x;
> foo[1] = y;
> foo[2] = z;
> uint[4] result = foo + bar;
> 
> Maybe not as readable, depending on the context, but that should 
> suffice, right?
> 
> The only trick then is to make sure the compiler recognizes these cases 
> and optimizes for them.  For example large dynamic arrays which are 
> worthy of some fixed overhead before jumping into simd instructions or 
> whatever, whereas the possibility of fixed overhead may change the way 
> these small static things get optimized.  Point is, maybe this is just a 
> quality of implementation issue once array operations are added?
> 
> Swizzling not templatable, really? ...
> 
> import std.stdio;
> import std.traits;
> 
> template doAssignment(dchar[] ordering, uint index = 0)
> {
>     static if ( index < ordering.length )
>     {
>         // dummy will get optimized away by dmd
>         auto dummy = temp[index] = vector[cast(uint)ordering[index]];
>         mixin doAssignment!(ordering, index + 1);
>     }
> }
> 
> void swizzle(T, dchar[] ordering)(T vector)
> {
>     T temp;
>     static if ( !isStaticArray!(T) )
>         temp.length = vector.length;
>     
>     mixin doAssignment!(ordering);
>     vector[0..ordering.length] = temp[0..ordering.length];
>     
>     static if ( !isStaticArray!(T) )
>         delete temp;
> }
> 
> void main()
> {
>     int[4] point = [7,73,42,5];
>     writefln( point ); // prints [7,73,42,5]
>     swizzle!(int[],[3,1,2,0])( point );
>     writefln( point ); // prints [5,73,42,7]
>     
>     real[] array = [81345.536,5.67,43.351,0.0,932.4,0.03,0.9852,57];
>     writefln( array );
>     swizzle!(real[],[0,1,2,4,3,5])(array);
>     writefln( array );
> }
> 
> Now this is suboptimal, but I have made an effort to get all of the 
> ordering values at compile time.  Now we can hand those to a template 
> and have it return information about optimal order of assignment and 
> temporary usage.  Now when you need to use said information, it should 
> be doable either by clever writing of the assignment operations or by 
> pasting together stuff using mixins.  As for the fact that swizzle is a 
> function, well it will probably get inlined, and if it doesn't, it 
> should (quality of implementation issue).


Right.  However, compare the syntax in the following two cases:

real4 a, b;
a = b.wzyx

versus:

real[4] a, b;
a = swizzle!(real[], [3, 2, 1, 0])(b);

There is also a chance that the compiler may miss inlining the swizzle, 
resulting in code bloat, (as you pointed out.)  Add in the fact that a 
compiler can exploit instructions like SSE's pshuf, and it becomes 
pretty clear that for low-d vectors a compiler level implementation is 
superior.

On the topic of using array operations as a replacement for 
low-dimension vectors, I still have some mixed feelings about it.  I 
think higher dimensional array ops are of dubious value, and vaguely 
reminiscent of APL.  For most applications, the higher dimension array 
operations are overkill, and they will inevitably commit horrible acts 
of obfuscation:

bool stricmp(char[] str1, char[] str2)
{
	return ((str1 ^ str2) & ~('a' - 'A')) == 0;
}

Faced with such monstrosities, it might be best to keep vector code in 
the lower dimensions where it is most strongly connected to its 
geometric meaning.


-Mik



More information about the Digitalmars-d mailing list