Thread overview
Runtime version statement
Jan 07, 2012
Piotr Szturmaj
Jan 07, 2012
Manu
Jan 07, 2012
Manu
Jan 10, 2012
Martin Nowak
Jan 10, 2012
Manu
Jan 10, 2012
Martin Nowak
Jan 10, 2012
Iain Buclaw
Jan 10, 2012
Iain Buclaw
Jan 11, 2012
Martin Nowak
January 07, 2012
The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies.

Examples of such versions may be:
* supported SIMD CPU extensions MMX, SSE, SSE2, etc.
* AMD vs Intel CPU, to use instructions that are not available on both
* different OS versions (XP/Vista/7, Linux kernel versions)

Why that instead of current if statement?
* some additional speed, avoids multiple checks in frequent operations
* making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time

Code example:

void main()
{
    version(rt_SSE4)
    {
        ...
    }
    else version(rt_SSE2)
    {
        ...
    }
    else
    {
        // portable code
    }
}

In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match.

Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid.

Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main().

Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided.

Just thinking loud :)
January 07, 2012
On 7 January 2012 22:44, Piotr Szturmaj <bncrbme@jadamspam.pl> wrote:

> The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies.
>
> Examples of such versions may be:
> * supported SIMD CPU extensions MMX, SSE, SSE2, etc.
> * AMD vs Intel CPU, to use instructions that are not available on both
> * different OS versions (XP/Vista/7, Linux kernel versions)
>
> Why that instead of current if statement?
> * some additional speed, avoids multiple checks in frequent operations
> * making specific executables (f.i. SSE4 only) by limiting set of
> supported runtime options during compile time
>
> Code example:
>
> void main()
> {
>    version(rt_SSE4)
>    {
>        ...
>    }
>    else version(rt_SSE2)
>    {
>        ...
>    }
>    else
>    {
>        // portable code
>    }
> }
>
> In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match.
>
> Runtime version identifiers may be set inside shared static constructors
> of modules (this implies that rt-version may not be used inside of them).
> SIMD extensions would preferably be set by druntime with help of core.cpuid.
>
> Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main().
>
> Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided.
>
> Just thinking loud :)
>

... you could just use if() ?
Perhaps detection of these features could be added to the standard library.
But I have a feeling it already IS actually (core.cpuid, something I am
extremely cynical of)


January 07, 2012
On 8 January 2012 00:31, Manu <turkeyman@gmail.com> wrote:

> On 7 January 2012 22:44, Piotr Szturmaj <bncrbme@jadamspam.pl> wrote:
>
>> The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies.
>>
>> Examples of such versions may be:
>> * supported SIMD CPU extensions MMX, SSE, SSE2, etc.
>> * AMD vs Intel CPU, to use instructions that are not available on both
>> * different OS versions (XP/Vista/7, Linux kernel versions)
>>
>> Why that instead of current if statement?
>> * some additional speed, avoids multiple checks in frequent operations
>> * making specific executables (f.i. SSE4 only) by limiting set of
>> supported runtime options during compile time
>>
>> Code example:
>>
>> void main()
>> {
>>    version(rt_SSE4)
>>    {
>>        ...
>>    }
>>    else version(rt_SSE2)
>>    {
>>        ...
>>    }
>>    else
>>    {
>>        // portable code
>>    }
>> }
>>
>> In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match.
>>
>> Runtime version identifiers may be set inside shared static constructors
>> of modules (this implies that rt-version may not be used inside of them).
>> SIMD extensions would preferably be set by druntime with help of core.cpuid.
>>
>> Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main().
>>
>> Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided.
>>
>> Just thinking loud :)
>>
>
> ... you could just use if() ?
> Perhaps detection of these features could be added to the standard
> library. But I have a feeling it already IS actually (core.cpuid, something
> I am extremely cynical of)
>

Sorry, I only half read your post >_<
Many(/most?) systems won't let you write to code memory, so using self
modifying code in this way this may be a problem...
Additionally, many modern systems use encrypted code memory, so self
modifying code is impossible on these systems. But it's an interesting
idea, which I have thought about myself too on occasion.


January 10, 2012
Am 07.01.2012, 21:44 Uhr, schrieb Piotr Szturmaj <bncrbme@jadamspam.pl>:

> The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies.
>
> Examples of such versions may be:
> * supported SIMD CPU extensions MMX, SSE, SSE2, etc.
> * AMD vs Intel CPU, to use instructions that are not available on both
> * different OS versions (XP/Vista/7, Linux kernel versions)
>
> Why that instead of current if statement?
> * some additional speed, avoids multiple checks in frequent operations
> * making specific executables (f.i. SSE4 only) by limiting set of supported runtime options during compile time
>
> Code example:
>
> void main()
> {
>      version(rt_SSE4)
>      {
>          ...
>      }
>      else version(rt_SSE2)
>      {
>          ...
>      }
>      else
>      {
>          // portable code
>      }
> }
>
> In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match.
>
> Runtime version identifiers may be set inside shared static constructors of modules (this implies that rt-version may not be used inside of them). SIMD extensions would preferably be set by druntime with help of core.cpuid.
>
> Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main().
>
> Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided.
>
> Just thinking loud :)

Because it could only fix non-inlined code you
can as well use lazy binding using thunks.

// use static to make it re-entrant safe
__gshared R function(Args) doSomething = &setThunk;

R setThunk(Args args)
{
   if (sse4)
   {
      doSomeThing = &sse4Impl;
   }
   else if (sse2)
   {
      doSomeThing = &sse2Impl;
   }
   else
   {
      doSomeThing = &nativeImpl;
   }

   return doSomeThing(args);
}

Much simpler, thread safe and more efficient.

__gshared SSE2 = tuple("foo", &sse2Foo, "bar", &sse2Bar);
__gshared SSE4 = tuple("foo", &sse4Foo, "bar", &sse4Bar);
__gshared typeof(SSE2)* _impl;

shared static this()
{
   if (sse4)
   {
      _impl = &SSE4;
   }
   else if (sse2)
   {
      _impl = &SSE2;
   }
   else
   {
      _impl = &Native;
   }
}

_impl.foo(args);
January 10, 2012
On 10 January 2012 08:09, Martin Nowak <dawg@dawgfoto.de> wrote:

> Am 07.01.2012, 21:44 Uhr, schrieb Piotr Szturmaj <bncrbme@jadamspam.pl>:
>
>
>  The idea is to make versions of code that are environment dependent and
>> never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies.
>>
>> Examples of such versions may be:
>> * supported SIMD CPU extensions MMX, SSE, SSE2, etc.
>> * AMD vs Intel CPU, to use instructions that are not available on both
>> * different OS versions (XP/Vista/7, Linux kernel versions)
>>
>> Why that instead of current if statement?
>> * some additional speed, avoids multiple checks in frequent operations
>> * making specific executables (f.i. SSE4 only) by limiting set of
>> supported runtime options during compile time
>>
>> Code example:
>>
>> void main()
>> {
>>     version(rt_SSE4)
>>     {
>>         ...
>>     }
>>     else version(rt_SSE2)
>>     {
>>         ...
>>     }
>>     else
>>     {
>>         // portable code
>>     }
>> }
>>
>> In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match.
>>
>> Runtime version identifiers may be set inside shared static constructors
>> of modules (this implies that rt-version may not be used inside of them).
>> SIMD extensions would preferably be set by druntime with help of core.cpuid.
>>
>> Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main().
>>
>> Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided.
>>
>> Just thinking loud :)
>>
>
> Because it could only fix non-inlined code you
> can as well use lazy binding using thunks.
>
> // use static to make it re-entrant safe
> __gshared R function(Args) doSomething = &setThunk;
>
> R setThunk(Args args)
> {
>   if (sse4)
>   {
>      doSomeThing = &sse4Impl;
>   }
>   else if (sse2)
>   {
>      doSomeThing = &sse2Impl;
>   }
>   else
>   {
>      doSomeThing = &nativeImpl;
>   }
>
>   return doSomeThing(args);
> }
>
> Much simpler, thread safe and more efficient.
>
> __gshared SSE2 = tuple("foo", &sse2Foo, "bar", &sse2Bar);
> __gshared SSE4 = tuple("foo", &sse4Foo, "bar", &sse4Bar);
> __gshared typeof(SSE2)* _impl;
>
> shared static this()
> {
>   if (sse4)
>   {
>      _impl = &SSE4;
>   }
>   else if (sse2)
>   {
>      _impl = &SSE2;
>   }
>   else
>   {
>      _impl = &Native;
>   }
> }
>
> _impl.foo(args);
>

Function pointers are super-slow on some architectures. I don't think it's a particularly good solution unless the functions you're calling do a lot of work.


January 10, 2012
> Function pointers are super-slow on some architectures. I don't think it's
> a particularly good solution unless the functions you're calling do a lot
> of work.
If you're working on very specific platforms you can likely determine
such things at compile time. Alternative approaches are distributing multiple
executables or using template parameterization of whole engines.
January 10, 2012
On 7 January 2012 22:31, Manu <turkeyman@gmail.com> wrote:
> On 7 January 2012 22:44, Piotr Szturmaj <bncrbme@jadamspam.pl> wrote:
>>
>> The idea is to make versions of code that are environment dependent and never change during runtime, _without_ resorting to if statements. This statement would be valid only inside function bodies.
>>
>> Examples of such versions may be:
>> * supported SIMD CPU extensions MMX, SSE, SSE2, etc.
>> * AMD vs Intel CPU, to use instructions that are not available on both
>> * different OS versions (XP/Vista/7, Linux kernel versions)
>>
>> Why that instead of current if statement?
>> * some additional speed, avoids multiple checks in frequent operations
>> * making specific executables (f.i. SSE4 only) by limiting set of
>> supported runtime options during compile time
>>
>> Code example:
>>
>> void main()
>> {
>>    version(rt_SSE4)
>>    {
>>        ...
>>    }
>>    else version(rt_SSE2)
>>    {
>>        ...
>>    }
>>    else
>>    {
>>        // portable code
>>    }
>> }
>>
>> In this example program checks the supported extensions only once, before calling main(). Then it modifies the function code to make it execute only versions that match.
>>
>> Runtime version identifiers may be set inside shared static constructors
>> of modules (this implies that rt-version may not be used inside of them).
>> SIMD extensions would preferably be set by druntime with help of core.cpuid.
>>
>> Code modification mechanism is up to implementation. One that come to my mind is inserting unconditional jumps by the compiler then and fixing them up before calling main().
>>
>> Additional advantage is possibility to generate executables for particular environments. This may help reduce execucutable size when targeting specific CPU, especially some constrained/embedded system. Also many cpuid checks inside druntime may be avoided.
>>
>> Just thinking loud :)
>
>
> ... you could just use if() ?
> Perhaps detection of these features could be added to the standard library.
> But I have a feeling it already IS actually (core.cpuid, something I am
> extremely cynical of)

This.

If you want CPU detection at runtime, you need to write your own assembly or use core.cpuid.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
January 10, 2012
On 10 January 2012 09:42, Martin Nowak <dawg@dawgfoto.de> wrote:
>> Function pointers are super-slow on some architectures. I don't think it's a particularly good solution unless the functions you're calling do a lot of work.
>
> If you're working on very specific platforms you can likely determine
> such things at compile time. Alternative approaches are distributing
> multiple
> executables or using template parameterization of whole engines.

I did have GDC hooked up to the C pre-processor macros, which defined a lot of target-specific identifiers (GNU_SSE, GNU_SSE2, etc) depending on the default target flags, and what extra target flags you passed to the compiler - but was dropped because of growing number of stub dependencies it incurred, and the fact that most macros were about as useful as marmite sundae.   I would be certainly up for addressing this in a pragmatic way though.

-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
January 11, 2012
You could make use of shared library filters where
you link against a native implementation. During installation
you can then provide specialized implementations.