January 28, 2007
Chad J wrote:
> 
> The only computers I know of that lack float4 are smartphone and PDA type devices running modern ARM processors.  Even some of the recent ARM-XSCALE processors have MMX instructions, which doesn't give float4 but does give short4 and int2.  I'm also not sure about modern supercomputers and the like, since I haven't worked with those.

Actually, newer ARM devices support the NEON/VFP instruction set extensions, which provides SIMD capabilities similar to SSE.  It is strange that most modern ISA's have better support for geometric vectors than higher level programming languages...


-Mik
January 28, 2007
Mikola Lysenko wrote:
> Helix is not a bad project, but in order for a standard vector to be useful it needs to come packaged with the compiler.  The temptation to roll your own is too great otherwise.  Even putting it in the standard library is not enough to prevent people from reinventing the wheel, as we have seen by the numerous variations on C++'s std::list.  Ideally, small vectors should be in the global namespace, right alongside complex numbers and dynamic arrays.

Hmmm…  D’s complex types seem to be syntactic sugar over a construct much like C++’s complex template.  I’d think that a template library ought to come first, with incorporation into the language later.

> Effective vector code needs correct data alignment, instruction scheduling and register use.  Each of these issues is most effectively handled in the compiler/code gen stage, and therefore suggests that at the very least the compiler implementation ought to be aware of the vector type in some way.  By applying the "D Builtin Rationale," it is easy to see that vectors meet all the required criteria.

As I understand it, D’s inline assembler would be the tool to use for this in a library implementation.  I don’t think the complex types use SIMD, so the vectors can be the only things using those registers.

> An optimal strategy would be to have the vector types builtin, with a simple per-component multiplication defined, and a separate standard math library for doing more complex operations.  Here is an example:
> 
> import std.vecmath;
> 
> float4 a = [1, 2, 3, 4];
> float4 b = [2, 3, 4, 5];
> float4 c = a * b;        //c = [2, 6, 12, 20]
> float  d = dot(a, b);        //Defined in std.vecmath

Considering that the primary vector types for physics or 3-D animation are 3-tuples (v ∊ ℝ³) and Hamiltonian quaternions (q ∊ ℍ or q ∊ ℝ⁴), and by extension with the complex types, how about a v prefix for 3-tuples and an h prefix for quaternions:
	vfloat v = [1, 2, 3];	// vfloat ≈ float3
	hreal q = [2, 3, 4, 5];	// hreal ≈ real4
and the additional operators needed to handle them “right”:
	vfloat a = [1, 2, 3];
	vfloat b = [2, 3, 4];
	vfloat p = a*b;	// element-wise product, [1*2, 2*3, 3*4]
	float d = a•b;	// dot product, [1*2 + 2*3 + 3*4]
	vfloat c = a×b	// cross product
Some notation for inverses (a postfix operator ⁻¹, perhaps) and notation for 3×3 and 4×4 matrices would be useful too, along with defining the dot and cross product for the complex numbers…

… or this can all go in a library until the interface and implementation are well defined and understood.

I’m only just learning the language and I’m watching it grow.

--Joel
January 29, 2007
Chad J wrote:
> Bill Baxter wrote:
>> Mikola Lysenko wrote:
>>
>>> I'll bite.  Here are the two features I consider most important:
>>>
>>> 2. Low dimensional vectors as primitive types
>>>
>>> Specifically I would like to see the types int, real, float etc. extended into 2-4 dimensional vectors.  ie. int2, real4, float3.
>>>
>>> This would be exceptionally useful in many applications which require coordinate geometry.  Here is a very brief list:
>>>
>>> Scientific Programs
>>> Physics Simulation
>>> Computer Graphics
>>> Video Games
>>> User Interfaces
>>> Computational Geometry
>>> Robotics
>>> Fluid Simulation
>>
>>
>> It's still a tiny fraction of the number of applications that use, say, strings.  So the ubiquity argument for inclusion is pretty weak, I think.
>>
> 
> What applications don't use vector instructions?

Business applications?  I'm not sure what you mean exactly.  But the question is not so much does app xyz use vector instructions, but rather would the programmer of app xyz have benefited from having int2/3/4 or float2/3/4 type primitives.

> Also, I think it's more important to consider what /D applications/ will be using SIMD instructions, rather than what applications in general do or do not use coordinate geometry.  That's because a lot of those applications may not even be written in D or have anything to do with D, like the mass of stuff written in dynamic languages like perl, python, ruby, etc.

Well judging from posts around here it seems like web programming folks and DB users make up a significant percentage of active D users.  But gamers and scientific folk are another significant group it seems.

> I have to wonder, has any language out there really given good support for SIMD primitives, besides assembly?  I think D could stand a lot to gain here.  That said, I don't mind if it's done in a library as long as it looks polished and is not cumbersome.

Agreed.

--bb
January 29, 2007
Mikola Lysenko wrote:
> Bill Baxter wrote:
>> Mikola Lysenko wrote:
>>> 2. Low dimensional vectors as primitive types

"Vectors are more common than complex, and complex is built-in".

This is a good argument.  Although, there seem to be a number of things out there that are more common, or least as-common as 'complex'.  For instance, there's a contingent here that wants to see decimal arithmetic supported in the core.  There was a strong push for regexp to be in the core for a while.


"Most CPUs today have *some* kind of SSE/Altivec type thing"

That may be, but I've heard that at least SSE is really not that suited to many calculations -- especially ones in graphics.  Something like you have to pack your data so that all the x components are together, and all y components together, and all z components together.  Rather than the way everyone normally stores these things as xyz, xyz.  Maybe Altivec, SSE2 and SSE3 fix that though.  At any rate I think maybe Intel's finally getting tired of being laughed at for their graphics performance so things are probably changing.


"Library vs Core"

I think there's really not much that you can ask from the core.  A small vector of 4 numbers can represent any number of things.  So I think your best hope for the core is to support some very basic operations on small vectors -- like component-wise +,-,*,/, and dot product -- to optimize those kind of expressions as best as possible, and leave everything else to libraries.  I guess that's pretty much how it works with HW shader languages.  Except they add swizzles to the set of primitive ops.


So what you're left with would be satisfied in large part by just having vector math work on small static arrays (and be optimized well).

     float[4] v = a*b + c*d;

you can even make aliases if you like.

     alias float[4] float4;

But your 3D graphics library will still need to be a library on top of that.

Good news is that I think vector math like the above is something that Walter is interested in adding to the language at some point.  Bad news is that noone knows when that will be.   I'd guess though that a kick-ass vector expression optimizer would be a long way off, judging by how hard it's been for C++ compilers to get SSE type optimizations implemented.


"Getting it in the standard library"

I agree, though, that lo-D math is common enough that it should be included in a standard library.  I wonder if the Tango developers would be willing to include a vector math class...or if they already have one in there.

I'd certainly like to be a contributor to that if so.

--bb
January 29, 2007
Wolfgang Draxinger wrote:
> A quite cool feature was something similair to Python's
> __getattr__, __setattr__ special functions.
> 
> So if one writes
> 
> class foo
> {
>         ... // foo does not declare a function or member bar
> 
>         // special operators do not return anything
>         opGetAttr(out T val, char[] identifier);
>         opSetAttr(in T val, char[] identifier);
> };
I think this could be a great feature, but be better as a template, because compile-time variables can be accessed at runtime, but not vice versa. Also remember that properties can mimic member variables, so supporting member functions should be enough. For any arbitrary call like
   foo.bar(a, b, c);
the compiler would then follow the following law: if no member 'bar' is found that overloads satisfactorily, try rewriting it to
   foo.opFakeMember!("bar")(a, b, c);
and see if a satisfactory overload can be found.

This would allow more things, yet often keep the overhead restricted to compile time.  For instance, you could use this to generate 'swizzling' functions, as discussed in the 'small vector' thread above, or generate conversions to all possible color spaces (rgba, bgra, etc):

struct MyVector
{
   template opFakeMember(char[] ident)
   {
      static if (ident[0..7] == "swizzle" && ident.length == 11)
          alias swizzle!(ident[7..11]).swizzle opFakeMember;
   }

   MyVector swizzle(char[] order)()
   {
      // Do some more template meta-programming to generate a swizzle
   }
}

And, having it as a template doesn't exclude transmitting the identifier at runtime:

class MyDynamicPythonClass
{
   void* opFakeMember(char[] ident)()
   {
      return runPythonLookupToGetThisVariable(ident); // Run at runtime
   }

   void opFakeMember(char[] ident)(void* foo)
   {
       setPythonVariable(ident, foo); // Run at runtime
   }

   unittest
   {
      auto test = new MyDynamicPythonClass();
      test.bar = 5; // Property syntax allows variable mimicry;
      writeflln(test.boom);
   }
}

Cheers,

Reiner
January 29, 2007
I think something like a 'super static' function could also be good (just to avoid using new keywords ;-) ). The idea would be that plain D code could be called by template functions, and the compiler would evaluate them at compile-time.

As I see it, there are only a few requirements for this (which are recursive across all functions called):

  1. the source code is available
  2. there's no assembly or C (or any external library) called
  3. the functions are pure (ie no static variables are read or changed, and the passed parameters are unchanged)

This would mean, for instance, that practically all of std.string would be accessible via templates, avoiding the much of the need for separate meta-programming libraries. You could then just call such functions straight from your template code:

import std.string;

template foo(char[] bar)
{
    static if (bar.splitlines()[0] == "cheese")
        pragma(msg, "You like cheese");
}


The compiler can check whether a function can be evaluated at compile-time, and you may wish to ensure that yours is, since you are writing it for template code. In that case, you annotate your function 'super static' and the compiler will give you an error if it fails any of the three criteria.

Cheers,

Reiner
January 29, 2007
Bill Baxter wrote:
> Mikola Lysenko wrote:
> 
>> Bill Baxter wrote:
>>
>>> Mikola Lysenko wrote:
>>>
>>>> 2. Low dimensional vectors as primitive types
> 
> 
> "Vectors are more common than complex, and complex is built-in".
> 
> This is a good argument.  Although, there seem to be a number of things out there that are more common, or least as-common as 'complex'.  For instance, there's a contingent here that wants to see decimal arithmetic supported in the core.  There was a strong push for regexp to be in the core for a while.
> 
> 
> "Most CPUs today have *some* kind of SSE/Altivec type thing"
> 
> That may be, but I've heard that at least SSE is really not that suited to many calculations -- especially ones in graphics.  Something like you have to pack your data so that all the x components are together, and all y components together, and all z components together.  Rather than the way everyone normally stores these things as xyz, xyz.  Maybe Altivec, SSE2 and SSE3 fix that though.  At any rate I think maybe Intel's finally getting tired of being laughed at for their graphics performance so things are probably changing.
> 
> 
> "Library vs Core"
> 
> I think there's really not much that you can ask from the core.  A small vector of 4 numbers can represent any number of things.  So I think your best hope for the core is to support some very basic operations on small vectors -- like component-wise +,-,*,/, and dot product -- to optimize those kind of expressions as best as possible, and leave everything else to libraries.  I guess that's pretty much how it works with HW shader languages.  Except they add swizzles to the set of primitive ops.
> 
> 
> So what you're left with would be satisfied in large part by just having vector math work on small static arrays (and be optimized well).
> 
>      float[4] v = a*b + c*d;
> 
> you can even make aliases if you like.
> 
>      alias float[4] float4;
> 
> But your 3D graphics library will still need to be a library on top of that.

Yeah I mentioned static arrays earlier, but I realized that they can be a bit of a pain in the ass to work with.  This probably means that static arrays should be fixed, then they could be useful vectors. Consider trying to return a float4 from a function.  You can't return a float[4].  I remember talk on this ng about how static arrays were this kinda sucky inbetween-value-and-reference-type sort of thing.  I'd hope that at least gets fixed before static arrays are used for lo-D vectors.

> 
> Good news is that I think vector math like the above is something that Walter is interested in adding to the language at some point.  Bad news is that noone knows when that will be.   I'd guess though that a kick-ass vector expression optimizer would be a long way off, judging by how hard it's been for C++ compilers to get SSE type optimizations implemented.
> 
> 
> "Getting it in the standard library"
> 
> I agree, though, that lo-D math is common enough that it should be included in a standard library.  I wonder if the Tango developers would be willing to include a vector math class...or if they already have one in there.
> 
> I'd certainly like to be a contributor to that if so.
> 
> --bb
January 29, 2007
Chad J wrote:
> Bill Baxter wrote:
>> Mikola Lysenko wrote:
>>
>>> Bill Baxter wrote:
>>>
>>>> Mikola Lysenko wrote:
>>>>
>>>>> 2. Low dimensional vectors as primitive types
>[...]

>>
>>      float[4] v = a*b + c*d;
>>
>> you can even make aliases if you like.
>>
>>      alias float[4] float4;
>>
>> But your 3D graphics library will still need to be a library on top of that.
> 
> Yeah I mentioned static arrays earlier, but I realized that they can be a bit of a pain in the ass to work with.  This probably means that static arrays should be fixed, then they could be useful vectors. 

Agreed.  So basically the D 2.0 wish list item becomes to make float[4] act more like a plain-old-data value type, give it simple math operations, optimize the heck out of it, and make it possible to alias it to float4 for convenience.

And maybe add the .xyzw accessors and swizzles too. :-)

I suspect the "optimize the heck out of it" step will be a long time coming though.  Probably more like D 3.0.

--bb
January 29, 2007
Bill Baxter wrote:
> Chad J wrote:
> 
>> Bill Baxter wrote:
>>
>>> Mikola Lysenko wrote:
>>>
>>>> Bill Baxter wrote:
>>>>
>>>>> Mikola Lysenko wrote:
>>>>>
>>>>>> 2. Low dimensional vectors as primitive types
>>
>> [...]
> 
> 
>>>
>>>      float[4] v = a*b + c*d;
>>>
>>> you can even make aliases if you like.
>>>
>>>      alias float[4] float4;
>>>
>>> But your 3D graphics library will still need to be a library on top of that.
>>
>>
>> Yeah I mentioned static arrays earlier, but I realized that they can be a bit of a pain in the ass to work with.  This probably means that static arrays should be fixed, then they could be useful vectors. 
> 
> 
> Agreed.  So basically the D 2.0 wish list item becomes to make float[4] act more like a plain-old-data value type, give it simple math operations, optimize the heck out of it, and make it possible to alias it to float4 for convenience.
> 
> And maybe add the .xyzw accessors and swizzles too. :-)
> 
> I suspect the "optimize the heck out of it" step will be a long time coming though.  Probably more like D 3.0.
> 
> --bb

*sigh* but I want my uber vector operations NOW! :)
January 29, 2007
Reiner Pope wrote:
> I think something like a 'super static' function could also be good (just to avoid using new keywords ;-) ). The idea would be that plain D code could be called by template functions, and the compiler would evaluate them at compile-time.
> 
> As I see it, there are only a few requirements for this (which are recursive across all functions called):
> 
>   1. the source code is available
>   2. there's no assembly or C (or any external library) called
>   3. the functions are pure (ie no static variables are read or changed, and the passed parameters are unchanged)
> 
> This would mean, for instance, that practically all of std.string would be accessible via templates, avoiding the much of the need for separate meta-programming libraries. You could then just call such functions straight from your template code:
> 
> import std.string;
> 
> template foo(char[] bar)
> {
>     static if (bar.splitlines()[0] == "cheese")
>         pragma(msg, "You like cheese");
> }
> 
> 
> The compiler can check whether a function can be evaluated at compile-time, and you may wish to ensure that yours is, since you are writing it for template code. In that case, you annotate your function 'super static' and the compiler will give you an error if it fails any of the three criteria.
> 
> Cheers,
> 
> Reiner
Alternatively, if this is too hard to implement (since I think it effectively means writing a D interpreter within the compiler -- for the references only, since almost anything with value semantics already needs to be const-foldable for templates) another option could be the (slightly less cool) approach that Nemerle takes: precompile the library to a .dll file, and direct the compiler to that when it runs.