Runtime version statement
Martin Nowak
dawg at dawgfoto.de
Mon Jan 9 22:09:15 PST 2012
Am 07.01.2012, 21:44 Uhr, schrieb Piotr Szturmaj <bncrbme at 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);
More information about the Digitalmars-d
mailing list