Another feature/optimization request (also: macro proposal)
downs
default_357-line at yahoo.de
Wed Jan 2 20:39:52 PST 2008
Okay, this is more of a compiler than language feature request.
While writing the OpenGL API for dglut, I found myself repeatedly using the following idiom:
>
> void glDoStuff(GLenum foo, int bar, void delegate()[] dgs...) {
> auto oldState=glGetStateFooBar(foo);
> scope(exit) glStateFooBar(foo, oldState);
> glStateFooBar(foo, bar);
>
> foreach (dg; dgs) dg();
> }
>
Seeing as this, worst-case, comes down to two function call layers, just to do some easier OpenGL stuff, I decided to test how this common situation gets inlined.
For this, I dumped EBP during several parts of the code.
>
> import std.stdio;
> void test(void delegate()[] dgs...) {
> writefln("test: ", getESP());
> foreach (dg; dgs) dg();
> }
>
> void *getESP() {
> void *res;
> asm { mov res, EBP; }
> return res;
> }
>
> void main() {
> writefln("main: ", getESP());
> test({ writefln("dg: ", getESP()); });
> }
>
The result: DMD doesn't inline at all. GDC inlines test, but not the delegate.
Because this might cause significant slowdowns, I'd like to request that the language spec guarantee the following:
that in a case such as,
>
> auto foo={}; foo();
> // or
> auto bar=[{}];
> foreach (b; bar) b(); // foreach can get unrolled at compile-time because the array is static
>
foo (and b) always get inlined.
Note that I propose no kind of complex value tracking, just this one, simple case.
The effect of this will be to place user-defined control structures taking delegate parameters on the same level as built-in statements.
* ALTERNATIVE PROPOSAL *
Another way to achieve this would be the introduction of a "block" type. This type would behave as follows:
- When used in a parameter list, block behaves like typesafe variadic void delegate()[], with the following modifications:
- All delegate and function *literals* that do not take parameters are implicitly converted to block. This conversion will make the following changes:
- If the literal returns a value, this value is stored until the control flow re-enters the function in which they were declared.
- At this point, the value is returned.
- non-literal delegate() variables are also implicitly convertible to block.
- Since the above modifications cannot be applied, the variables are treated as if they were wrapped in a literal.
- Block variables can be called like void delegate() variables. This causes immediate inlining.
- Lexically speaking, each block constitutes a scope.
The above example, rewritten using block, would look something like this:
>
> void glDoStuff(GLenum foo, int bar, block b) {
> auto oldState=glGetStateFooBar(foo);
> scope(exit) glStateFooBar(foo, oldState);
> glStateFooBar(foo, bar);
> b(); // gets inlined
> }
>
Since blocks are evaluated completely at compile-time, features like block AST introspection or modification might eventually be added,
thus tuning blocks into the foundation of macros.
The obligatory: what do you think? :)
-- downs
More information about the Digitalmars-d
mailing list