Re: Scope storage class

2008-12-04 Thread Steven Schveighoffer
"Sergey Gromov" wrote
> Mon, 1 Dec 2008 14:10:27 -0500, Steven Schveighoffer wrote:
>
>> "Walter Bright" wrote
>>> Steven Schveighoffer wrote:
 "Walter Bright" wrote
> Jarrett Billingsley wrote:
>> So my suspicion is correct, then?  That is:
>>
>> scope int delegate() b;
>> b = { ... };
>>
>> Will allocate on the heap?
> Yes. The scope for delegates takes effect as a parameter storage 
> class,
> not a local variable storage class. The reason is because it is the
> called function that decides what it's going to do with the delegate.

 Why?  It would be useful to allow local scope delegates.

 The compiler can just forbid passing the delegate to a function which
 does not declare its parameter as scope.  I assume the compiler knows a
 variable is scope since it must prevent escape of the delegate, no?  So
 just use that information.  I thought that was the point of all this...
>>>
>>> In order to make that work, the compiler would have to do full escape
>>> analysis, which is a lot of work to implement.
>>
>> Maybe I've misunderstood the point of declaring a delegate parameter 
>> scope.
>>
>> Take the following example:
>>
>> void delegate(int) global_dg;
>>
>> void foo(void delegate(int) dg)
>> {
>>global_dg = dg;
>> }
>>
>> void foo2(scope void delegate(int) dg)
>> {
>>dg(5);
>> }
>>
>> void bar(scope void delegate(int) dg)
>> {
>>foo(dg); // should this compile?
>>foo2(dg); // should this compile?
>> }
>>
>> void baz()
>> {
>>int y;
>>void dg(int x) { y += x; }
>>bar(&dg);
>> }
>>
>> Should bar's call to foo compile?
>
> It compiles.

I meant, should it compile in the final incarnation of this feature.

>> If it does, then the benefit of having
>> scope delegates is just a hint to the compiler that "I know what I'm 
>> doing".
>
> Yes, seems like for now it's just a hint.  No checking is done.
>
> The problem is, the declaration:
>
>  scope var = ...;
>
> means something completely different from
>
>  void foo(scope void delegate() dg);
>  foo(...);
>
> The former defines a scoped instance of a class.  Ideally it should fail
> if used with any non-class type because it makes no sense with
> non-classes.

I was proposing to MAKE scope var = &dg mean what I said it should mean.  I 
am not talking about the current spec.

> The latter defines a delegate in a non-escaping context.  Currently such
> definition is possible only as a parameter to a function call.

Currently being the key word here ;)

> If delegate is defined in a non-escaping context, it gets a stack
> closure.  If it is defined as a scoped instance of a class... well, it
> makes no sense, so the scope is ignored and the delegate is created as
> usual, with a heap-allocated closure.

It makes sense.  A scope variable doesn't escape it's scope.  Why should 
this be limited to classes?  In fact, the scope delegate versus non-scope 
delegate is 100% analogous to scope classes versus non-scope classes.

My point in all this is Walter is saying it cannot be done, when in fact it 
can, and should be easy to determine, assuming that the eventual goal of 
this feature is to prevent scope delegate escapes.  Without knowing which 
delegates are scope and which are not is very important to escape analysis. 
Even partial escape analysis.  If the compiler can't determine that, then 
all this does is give a hint to the compiler, which isn't very useful at 
all, and seems half-ass in the face of all the other great features D2 is 
creating.

-Steve 




Re: Scope storage class

2008-12-04 Thread Sergey Gromov
Mon, 1 Dec 2008 14:10:27 -0500, Steven Schveighoffer wrote:

> "Walter Bright" wrote
>> Steven Schveighoffer wrote:
>>> "Walter Bright" wrote
 Jarrett Billingsley wrote:
> So my suspicion is correct, then?  That is:
>
> scope int delegate() b;
> b = { ... };
>
> Will allocate on the heap?
 Yes. The scope for delegates takes effect as a parameter storage class, 
 not a local variable storage class. The reason is because it is the 
 called function that decides what it's going to do with the delegate.
>>>
>>> Why?  It would be useful to allow local scope delegates.
>>>
>>> The compiler can just forbid passing the delegate to a function which 
>>> does not declare its parameter as scope.  I assume the compiler knows a 
>>> variable is scope since it must prevent escape of the delegate, no?  So 
>>> just use that information.  I thought that was the point of all this...
>>
>> In order to make that work, the compiler would have to do full escape 
>> analysis, which is a lot of work to implement.
> 
> Maybe I've misunderstood the point of declaring a delegate parameter scope.
> 
> Take the following example:
> 
> void delegate(int) global_dg;
> 
> void foo(void delegate(int) dg)
> {
>global_dg = dg;
> }
> 
> void foo2(scope void delegate(int) dg)
> {
>dg(5);
> }
> 
> void bar(scope void delegate(int) dg)
> {
>foo(dg); // should this compile?
>foo2(dg); // should this compile?
> }
> 
> void baz()
> {
>int y;
>void dg(int x) { y += x; }
>bar(&dg);
> }
> 
> Should bar's call to foo compile?

It compiles.

> If it does, then the benefit of having 
> scope delegates is just a hint to the compiler that "I know what I'm doing".

Yes, seems like for now it's just a hint.  No checking is done.

The problem is, the declaration:

  scope var = ...;

means something completely different from

  void foo(scope void delegate() dg);
  foo(...);

The former defines a scoped instance of a class.  Ideally it should fail
if used with any non-class type because it makes no sense with
non-classes.

The latter defines a delegate in a non-escaping context.  Currently such
definition is possible only as a parameter to a function call.

If delegate is defined in a non-escaping context, it gets a stack
closure.  If it is defined as a scoped instance of a class... well, it
makes no sense, so the scope is ignored and the delegate is created as
usual, with a heap-allocated closure.


Re: Scope storage class

2008-12-01 Thread Steven Schveighoffer
"Walter Bright" wrote
> Steven Schveighoffer wrote:
>> "Walter Bright" wrote
>>> Jarrett Billingsley wrote:
 So my suspicion is correct, then?  That is:

 scope int delegate() b;
 b = { ... };

 Will allocate on the heap?
>>> Yes. The scope for delegates takes effect as a parameter storage class, 
>>> not a local variable storage class. The reason is because it is the 
>>> called function that decides what it's going to do with the delegate.
>>
>> Why?  It would be useful to allow local scope delegates.
>>
>> The compiler can just forbid passing the delegate to a function which 
>> does not declare its parameter as scope.  I assume the compiler knows a 
>> variable is scope since it must prevent escape of the delegate, no?  So 
>> just use that information.  I thought that was the point of all this...
>
> In order to make that work, the compiler would have to do full escape 
> analysis, which is a lot of work to implement.

Maybe I've misunderstood the point of declaring a delegate parameter scope.

Take the following example:

void delegate(int) global_dg;

void foo(void delegate(int) dg)
{
   global_dg = dg;
}

void foo2(scope void delegate(int) dg)
{
   dg(5);
}

void bar(scope void delegate(int) dg)
{
   foo(dg); // should this compile?
   foo2(dg); // should this compile?
}

void baz()
{
   int y;
   void dg(int x) { y += x; }
   bar(&dg);
}

Should bar's call to foo compile?  If it does, then the benefit of having 
scope delegates is just a hint to the compiler that "I know what I'm doing".

If it fails to compile the call to foo, what about the call to foo2?  If 
that fails to compile, then this is a common convention (forwarding a 
delegate) that will cause lots of problems in existing correct code.  If the 
call to foo2 should work, I don't see the difference between the above 
example and this:

void baz2()
{
   int y;
   void dg(int x) { y += x; }
   scope void delegate(int) dg2 = &dg;
   bar(dg2);
}

That is, if you can tell that a delegate is scope or not scope when it's 
being passed to another function, then why can't the compiler use that 
information when the delegate is assigned to another scope delegate?  No 
full escape analysis is needed.

-Steve 




Re: Scope storage class

2008-12-01 Thread Sergey Gromov
Mon, 01 Dec 2008 10:26:31 -0700, Russell Lewis wrote:

> The thing to remember is that "scope" is *not* transitive.  Scope limits 
> the most shallow reference, *not* not anything deeper.  It is perfectly 
> valid to have a scope pointer to a non-scope thing.  The point of scope 
> is to enforce that the pointer cannot escape; it does not say anything 
> about whether the pointed-to object escapes or not.
> 
> The point then, is that you can create a non-scope object, and assign it 
> to a scope pointer.  When you do something like:
> 
> BEGIN CODE
>   scope  a;
>   a = ;
> END CODE
> 
> ...you are doing exactly that.
> 
> (At least, that's how I think it ought to work.)

http://www.digitalmars.com/d/1.0/attribute.html#scope

Originally, the scope keyword wasn't about escaping, it was about memory
management.  The code

  scope C c = new C;

was a sugar for

  C c =new C;
  scope(exit) delete c;
  
The spec says, "Assignment to a scope, other than initialization, is not
allowed."  Therefore your example is illegal.  I think the fact that DMD
accepts such a code is a bug.  I'll file a bug report.


Re: Scope storage class

2008-12-01 Thread Russell Lewis

Robert Jacques wrote:

Just as a point of reference (in D1)
scope Object a = new Object(); // Stack Allocated
scope Object b;
b = new Object(); // Heap Allocated

So there may be some merit to scope int b() { .. } vs scope int b(); b = 
{...}


I can't find any spec on exactly how scope works, but this makes 100% 
sense to me.  Let me explain the way that I think scope 
does/might/should work:


The thing to remember is that "scope" is *not* transitive.  Scope limits 
the most shallow reference, *not* not anything deeper.  It is perfectly 
valid to have a scope pointer to a non-scope thing.  The point of scope 
is to enforce that the pointer cannot escape; it does not say anything 
about whether the pointed-to object escapes or not.


The point then, is that you can create a non-scope object, and assign it 
to a scope pointer.  When you do something like:


BEGIN CODE
scope  a;
a = ;
END CODE

...you are doing exactly that.

(At least, that's how I think it ought to work.)


Re: Scope storage class

2008-11-28 Thread Walter Bright

Brad Roberts wrote:
Accepting dubious 
definitions like 'public private int foo' and the above make life harder 
than it needs to be.


The code:

public private int foo;

produces the error message:

test.d(1): redundant protection attribute


Re: Scope storage class

2008-11-27 Thread bearophile
Brad Roberts:
> Walter, this is yet more evidence that shows that accepting and ignoring 
> these sorts of modifiers is the wrong thing to do.  Accepting dubious 
> definitions like 'public private int foo' and the above make life harder 
> than it needs to be.

I agree. What's the rationale behind accepting things and later ignoring them?
(Maybe to allow a different D compiler to compile code even if can't manage 
every one of those modifiers?)

Bye,
bearophile


Re: Scope storage class

2008-11-27 Thread Brad Roberts
On Thu, 27 Nov 2008, Walter Bright wrote:

> Jarrett Billingsley wrote:
> > So my suspicion is correct, then?  That is:
> > 
> > scope int delegate() b;
> > b = { ... };
> > 
> > Will allocate on the heap?
> 
> Yes. The scope for delegates takes effect as a parameter storage class, not a
> local variable storage class. The reason is because it is the called function
> that decides what it's going to do with the delegate.

Walter, this is yet more evidence that shows that accepting and ignoring 
these sorts of modifiers is the wrong thing to do.  Accepting dubious 
definitions like 'public private int foo' and the above make life harder 
than it needs to be.

Later,
Brad


Re: Scope storage class

2008-11-27 Thread bearophile
Walter Bright:
> In order to make that work, the compiler would have to do full escape 
> analysis, which is a lot of work to implement.

But the D2 programmer may enjoy some ways to state what he/she/shi wants 
anyway, like in a cast, to make the compiler behave like the D1 compiler and 
avoid a slowdown. And such ways have to be intuitive enough to use.

Bye,
bearophile


Re: Scope storage class

2008-11-27 Thread Walter Bright

Steven Schveighoffer wrote:

"Walter Bright" wrote

Jarrett Billingsley wrote:

So my suspicion is correct, then?  That is:

scope int delegate() b;
b = { ... };

Will allocate on the heap?
Yes. The scope for delegates takes effect as a parameter storage class, 
not a local variable storage class. The reason is because it is the called 
function that decides what it's going to do with the delegate.


Why?  It would be useful to allow local scope delegates.

The compiler can just forbid passing the delegate to a function which does 
not declare its parameter as scope.  I assume the compiler knows a variable 
is scope since it must prevent escape of the delegate, no?  So just use that 
information.  I thought that was the point of all this...


In order to make that work, the compiler would have to do full escape 
analysis, which is a lot of work to implement.


Re: Scope storage class

2008-11-27 Thread Steven Schveighoffer
"Walter Bright" wrote
> Jarrett Billingsley wrote:
>> So my suspicion is correct, then?  That is:
>>
>> scope int delegate() b;
>> b = { ... };
>>
>> Will allocate on the heap?
>
> Yes. The scope for delegates takes effect as a parameter storage class, 
> not a local variable storage class. The reason is because it is the called 
> function that decides what it's going to do with the delegate.

Why?  It would be useful to allow local scope delegates.

The compiler can just forbid passing the delegate to a function which does 
not declare its parameter as scope.  I assume the compiler knows a variable 
is scope since it must prevent escape of the delegate, no?  So just use that 
information.  I thought that was the point of all this...

-Steve 




Re: Scope storage class

2008-11-27 Thread Walter Bright

Jarrett Billingsley wrote:

So my suspicion is correct, then?  That is:

scope int delegate() b;
b = { ... };

Will allocate on the heap?


Yes. The scope for delegates takes effect as a parameter storage class, 
not a local variable storage class. The reason is because it is the 
called function that decides what it's going to do with the delegate.


Re: Scope storage class

2008-11-26 Thread Denis Koroskin

27.11.08 в 01:12 Robert Jacques в своём письме писал(а):

On Wed, 26 Nov 2008 13:24:57 -0500, Jarrett Billingsley  
<[EMAIL PROTECTED]> wrote:

scope int b() { .. }

The reason I wonder is because I would expect that the compiler is
still allocating the delegate on the heap if you use the first syntax.
 (the second is also shorter and clearer.)


Just as a point of reference (in D1)
scope Object a = new Object(); // Stack Allocated
scope Object b;
b = new Object(); // Heap Allocated

So there may be some merit to scope int b() { .. } vs scope int b(); b =  
{...}


If so, then why all the three usages

1) scope Object a;
2) scope Object a = b;
3) scope Object a = new Object();

are allowed when only 3rd one stack-allocates? I believe only third one  
should be allowed unless scope analisys is implemented (in its very basic  
form, at least):


scope Object a1 = new Object(); // ok
Object a2 = a1; // not ok
scope Object a3 = a1; // ok;
return a1; // not ok
return a2; // ok


Re: Scope storage class

2008-11-26 Thread Sergey Gromov
Wed, 26 Nov 2008 18:19:38 -0500, bearophile wrote:

> So compiling #2 witout -inline in D2 fulfulls my original desire of
> computing up to N=25 with D2 :-)
> 
> I presume the -inline uncovers a small bug of DMD, that will be fixed.

I think so, too.

> But what interests me more now is to understand how to write such
> fast code in general in D2.

Seems like right now delegates are stack allocated only if they're
passed directly as scope parameters.  Assigning a delegate to a variable
is always considered escaping, even if it's a local scope variable.
This is probably because scope for declarations is something completely
different than scope for arguments.


Re: Scope storage class

2008-11-26 Thread bearophile
Sergey Gromov:
> Remove -inline from your compiler options, and #2 compiles and runs
> faster in both D1 and D2 than #1.
> lazy seems to do something funny when -inline is in effect.

You are right, I have tested it on D1.
I think the codepad doesn't use -inline, that's why #2 works there.
#2 also uses less RAM on D1, for example N=24 requires about 707 MB instead of 
788 MB, and about 2.8 s instead of about 3 s.

Sergey Gromov:
> Remove -inline from your compiler options, and #2 compiles and runs
> faster in both D1 and D2 than #1.
> lazy seems to do something funny when -inline is in effect.

You are right, I have tested it on D1.
I think the codepad doesn't use -inline, that's why #2 works there.

#2 also uses less RAM on D1, for example N=24 requires about 710 MB instead of 
788 MB, and about 2.8 s instead of about 3 s.

This is the Asm of the #2 compiled with D1 with -O -release, it's shorter still 
(but note there are some other parts that I don't show here):

_D11man_or_boy21aFiLiLiLiLiLiZi comdat
assume  CS:_D11man_or_boy21aFiLiLiLiLiLiZi
L0: pushEAX
pushEBX
cmp dword ptr 034h[ESP],0
jg  L33
mov EAX,014h[ESP]
mov EDX,018h[ESP]
mov EBX,014h[ESP]
callEDX
pushEAX
sub ESP,4
mov EAX,014h[ESP]
mov EDX,018h[ESP]
mov EBX,014h[ESP]
callEDX
mov ECX,EAX
add ESP,4
pop EAX
add EAX,ECX
jmp short   L3C
L33:lea EAX,4[ESP]
callnear ptr _D11man_or_boy21aFiLiLiLiLiLiZi1bMFZi
L3C:pop EBX
pop ECX
ret 02Ch
_D11man_or_boy21aFiLiLiLiLiLiZi ends

--

I have then tested #1 and #2 without -inline on D2, and the results are very 
different from each other: #1 is very slow and uses lot of memory, while #2 
(that contains no scope) acts as D1, using "only" 707 MB with N=24 and working 
with n=25 too. The asm code is similar the one I have just shown here.
So compiling #2 witout -inline in D2 fulfulls my original desire of computing 
up to N=25 with D2 :-)

I presume the -inline uncovers a small bug of DMD, that will be fixed. But what 
interests me more now is to understand how to write such fast code in general 
in D2.

Bye,
bearophile


Re: Scope storage class [Was: DMD 1.037 and 2.020 releases]

2008-11-26 Thread Sergey Gromov
Wed, 26 Nov 2008 20:33:35 + (UTC), Jesse Phillips wrote:

> On Wed, 26 Nov 2008 12:18:27 -0800, Robert Fraser wrote:
>> Try marking all the "lazy" parameters as "scope" ("lazy" creates
>> delegates).
> 
> From change log: "The lazy storage class now implies scope so that lazy 
> arguments won't trigger a heap allocated closure."

Also, the whole point of this test is delegate propagation.  That's what
makes it interesting.


Re: Scope storage class

2008-11-26 Thread Sergey Gromov
Wed, 26 Nov 2008 17:02:54 -0500, bearophile wrote:

> While on DMD 1.036 the following code:
> 
> // code #2
> import std.c.stdio: printf;
> 
> int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int x5) 
> {
> int b() {
> k -= 1;
> return a(k, b(), x1, x2, x3, x4);
> }
> return k <= 0 ? x4 + x5 : b();
> }
> 
> void main() {
> printf("%d\n", a(24, 1, -1, -1, 1, 0));
> }
> 
> Outputs at compile time:
> 
> man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral1 is a nested function 
> and cannot be accessed from a
> man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral2 is a nested function 
> and cannot be accessed from a
> man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral3 is a nested function 
> and cannot be accessed from a
> man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral4 is a nested function 
> and cannot be accessed from a
> man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral5 is a nested function 
> and cannot be accessed from a
> 
> But this code works on the codepad site, that uses DMD v.1.026 (I think with 
> Tangobos), up to N=21 (then the site goes into timeout for safety):
> http://codepad.org/8GtKswm8

[snip]

> All the following compilations are done with and N=20 and:
> dmd -O -release -inline -L/STACK:17 man_or_boy.d
> dmd -O -release -inline -L/STACK:17 man_or_boy2.d

Remove -inline from your compiler options, and #2 compiles and runs
faster in both D1 and D2 than #1.

lazy seems to do something funny when -inline is in effect.


Re: Scope storage class

2008-11-26 Thread Robert Jacques
On Wed, 26 Nov 2008 13:24:57 -0500, Jarrett Billingsley  
<[EMAIL PROTECTED]> wrote:

scope int b() { .. }

The reason I wonder is because I would expect that the compiler is
still allocating the delegate on the heap if you use the first syntax.
 (the second is also shorter and clearer.)


Just as a point of reference (in D1)
scope Object a = new Object(); // Stack Allocated
scope Object b;
b = new Object(); // Heap Allocated

So there may be some merit to scope int b() { .. } vs scope int b(); b =  
{...}


Re: Scope storage class

2008-11-26 Thread bearophile
Walter Bright:
> There's no reason to suspect. Just obj2asm the output and see. 
> Furthermore, better results will come from:
>  int b() {
>  k -= 1;
>  return a(k, b(), x1, x2, x3, x4);
>  };
> instead of using the delegate.

I don't fully understand what's happening, maybe I am doing something wrong, so 
I just report what I have seen.



With DMD 1.036 this code works up to N=25, usign almost 1.6 GB of RAM (and I 
think a running time of just 6.4 seconds is very little, try to do this with 
any dynamic language, so I was impressed by D1):

// code #1
import std.c.stdio: printf;

int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int x5) {
int delegate() b;
b = {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(24, 1, -1, -1, 1, 0));
}



While on DMD 1.036 the following code:

// code #2
import std.c.stdio: printf;

int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int x5) {
int b() {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
}
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(24, 1, -1, -1, 1, 0));
}

Outputs at compile time:

man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral1 is a nested function 
and cannot be accessed from a
man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral2 is a nested function 
and cannot be accessed from a
man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral3 is a nested function 
and cannot be accessed from a
man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral4 is a nested function 
and cannot be accessed from a
man_or_boy2.d(6): delegate man_or_boy2.a.b.__dgliteral5 is a nested function 
and cannot be accessed from a


But this code works on the codepad site, that uses DMD v.1.026 (I think with 
Tangobos), up to N=21 (then the site goes into timeout for safety):
http://codepad.org/8GtKswm8

--

DMD v2.021 outputs the same errors with code #2.

--

DMD is able to run code #1 and the following #3:

// code #3
import std.c.stdio: printf;

int a(scope int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int 
x5) {
scope int delegate() b;
b = {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(22, 1, -1, -1, 1, 0));
}


All the following compilations are done with and N=20 and:
dmd -O -release -inline -L/STACK:17 man_or_boy.d
dmd -O -release -inline -L/STACK:17 man_or_boy2.d

Note: in D2 the code #1 and code #3 seem to use the same amount of RAM and time 
to run, 2.46 s and about 94MB RAM (N=20).

The same code #1 in DMD 1.036 runs in about 0.16 s and I am not able to know 
how much RAM it uses (N=20).

--
ASM of code #1 compiled with DMD 1.036:

_D10man_or_boy1aFiLiLiLiLiLiZi  comdat
assume  CS:_D10man_or_boy1aFiLiLiLiLiLiZi
sub ESP,0Ch
pushEBX
mov dword ptr 8[ESP],0
mov dword ptr 0Ch[ESP],0
lea EAX,0Ch[ESP]
mov ECX,offset 
FLAT:_D10man_or_boy1aFiLiLiLiLiLiZi12__dgliteral1MFZi
mov 8[ESP],EAX
mov 0Ch[ESP],ECX
cmp dword ptr 03Ch[ESP],0
jg  L56
mov EAX,01Ch[ESP]
mov EDX,020h[ESP]
mov EBX,01Ch[ESP]
callEDX
pushEAX
sub ESP,4
mov EAX,01Ch[ESP]
mov EDX,020h[ESP]
mov EBX,01Ch[ESP]
callEDX
mov ECX,EAX
add ESP,4
pop EAX
add EAX,ECX
jmp short   L62
L56:mov EAX,8[ESP]
mov EDX,ECX
mov EBX,8[ESP]
callEDX
L62:pop EBX
add ESP,0Ch
ret 02Ch

--
ASM of code #1 compiled with DMD 2.021:

assume  CS:_D10man_or_boy1aFiLiLiLiLiLiZi
L0: sub ESP,0Ch
pushEBX
pushESI
pushEDI
push030h
callnear ptr __d_allocmemory
mov ESI,EAX
mov dword ptr [ESI],0
mov EAX,048h[ESP]
mov 4[ESI],EAX
mov EDX,044h[ESP]
mov EAX,040h[ESP]
mov 010h[ESI],EAX
mov 014h[ESI],EDX
mov EDX,03Ch[ESP]
mov EAX,038h[ESP]
mov 018h[ESI],EAX
mov 01Ch[ESI],EDX
 

Re: Scope storage class

2008-11-26 Thread Jarrett Billingsley
On Wed, Nov 26, 2008 at 4:13 PM, Walter Bright
<[EMAIL PROTECTED]> wrote:
> Jarrett Billingsley wrote:
>>
>> The reason I wonder is because I would expect that the compiler is
>> still allocating the delegate on the heap if you use the first syntax.
>>  (the second is also shorter and clearer.)
>
> There's no reason to suspect. Just obj2asm the output and see.

That'd be great if I had it.  I don't want to get into that, though.

> Furthermore,
> better results will come from:
>
>int b() {
>k -= 1;
>return a(k, b(), x1, x2, x3, x4);
>};
>
> instead of using the delegate.

So my suspicion is correct, then?  That is:

scope int delegate() b;
b = { ... };

Will allocate on the heap?


Re: Scope storage class

2008-11-26 Thread Walter Bright

Jarrett Billingsley wrote:

The reason I wonder is because I would expect that the compiler is
still allocating the delegate on the heap if you use the first syntax.
 (the second is also shorter and clearer.)


There's no reason to suspect. Just obj2asm the output and see. 
Furthermore, better results will come from:


int b() {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};

instead of using the delegate.


Re: Scope storage class [Was: DMD 1.037 and 2.020 releases]

2008-11-26 Thread Jesse Phillips
On Wed, 26 Nov 2008 12:18:27 -0800, Robert Fraser wrote:

> bearophile wrote:
>> To test the new scoping features of D 2.021 I have used a small
>> stressing program, coming from this page, originally by Knuth:
>> 
>> http://www.rosettacode.org/wiki/Man_or_boy_test
>> 
>> More info:
>> http://en.wikipedia.org/wiki/Man_or_boy_test
>> 
>> My purpose is to see the D2 compiler being able to compute results up
>> to N=25 on my PC (that has 2 GB RAM and a 32 bit operating system).
>> 
>> ---
>> 
>> This is the code I have used for DMD 1.037:
>> 
>> import std.c.stdio: printf;
>> 
>> int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy
>> int x5) {
>> int delegate() b;
>> b = {
>> k -= 1;
>> return a(k, b(), x1, x2, x3, x4);
>> };
>> return k <= 0 ? x4 + x5 : b();
>> }
>> 
>> void main() {
>> printf("%d\n", a(15, 1, -1, -1, 1, 0)); // N is 15
>> }
>> 
>> ---
>> 
>> This is the code I have used for DMD 2.021. I was not sure how to use
>> the scope, so if you have improvements please tell me:
>> 
>> import std.c.stdio: printf;
>> 
>> int a(scope int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4,
>> lazy int x5) {
>> scope int delegate() b;
>> b = {
>> k -= 1;
>> return a(k, b(), x1, x2, x3, x4);
>> };
>> return k <= 0 ? x4 + x5 : b();
>> }
>> 
>> void main() {
>> printf("%d\n", a(15, 1, -1, -1, 1, 0)); // N is 15
>> }
>> 
>> ---
>> 
>> The results for higher values of N are: k   21   22   
>> 23 24  25 A   -389695 -865609 -1922362   
>> -4268854-9479595
>> 
>> In both cases I have compiled the code with: dmd -O -release -inline
>> -L/STACK:17 man_or_boy.d
>> 
>> The results:
>> 
>> DMD V.1.037 (exe: 168_476: bytes):
>>   N=24:  788 MB RAM, 3 seconds
>>   N=25: 1.57 GB RAM, 6.42 seconds
>> 
>> DMD V.2.021 (exe: 99_356 bytes):
>> 
>> The code was too much slow in D2, so I have stopped it. Do you know if
>> the D2 code can be improved to have performance similar to D1 ones?
>> 
>> Bye,
>> bearophile
> 
> Try marking all the "lazy" parameters as "scope" ("lazy" creates
> delegates).

>From change log: "The lazy storage class now implies scope so that lazy 
arguments won't trigger a heap allocated closure."


Re: Scope storage class [Was: DMD 1.037 and 2.020 releases]

2008-11-26 Thread Robert Fraser

bearophile wrote:

To test the new scoping features of D 2.021 I have used a small stressing 
program, coming from this page, originally by Knuth:

http://www.rosettacode.org/wiki/Man_or_boy_test

More info:
http://en.wikipedia.org/wiki/Man_or_boy_test

My purpose is to see the D2 compiler being able to compute results up to N=25 
on my PC (that has 2 GB RAM and a 32 bit operating system).

---

This is the code I have used for DMD 1.037:

import std.c.stdio: printf;

int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int x5) {
int delegate() b;
b = {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(15, 1, -1, -1, 1, 0)); // N is 15
}

---

This is the code I have used for DMD 2.021. I was not sure how to use the 
scope, so if you have improvements please tell me:

import std.c.stdio: printf;

int a(scope int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int 
x5) {
scope int delegate() b;
b = {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(15, 1, -1, -1, 1, 0)); // N is 15
}

---

The results for higher values of N are:
k   21   2223 24  25
A   -389695 -865609 -1922362-4268854-9479595

In both cases I have compiled the code with:
dmd -O -release -inline -L/STACK:17 man_or_boy.d

The results:

DMD V.1.037 (exe: 168_476: bytes):
  N=24:  788 MB RAM, 3 seconds
  N=25: 1.57 GB RAM, 6.42 seconds

DMD V.2.021 (exe: 99_356 bytes):

The code was too much slow in D2, so I have stopped it. Do you know if the D2 
code can be improved to have performance similar to D1 ones?

Bye,
bearophile


Try marking all the "lazy" parameters as "scope" ("lazy" creates delegates).


Re: Scope storage class

2008-11-26 Thread Jarrett Billingsley
On Wed, Nov 26, 2008 at 11:07 AM, bearophile <[EMAIL PROTECTED]> wrote:
>> Can you try declaring b as a nested function instead of as a delegate
>> literal and see if that helps?
>
> I think that may lead to nonworking code.

Uh, why?  You are declaring the delegate as 'scope', yes?  Meaning you
don't expect the delegate to be allocated on the heap?  Why don't you
try it and see what happens instead of arguing?

>> (why are you declaring it the way you are, anyway?
>
> Here you can find explanations:
> http://en.wikipedia.org/wiki/Man_or_boy_test
>
> Here you can find other two versions that work, but I think the version I 
> have shown is the more robust one (that is: able to computer up to higher N 
> values with D1 compiler):
> http://www.rosettacode.org/wiki/Man_or_boy_test#D

I don't really care about what test it is.  I'm just confused why you're doing:

scope int delegate() b;
b = { .. };

instead of:

scope int b() { .. }

The reason I wonder is because I would expect that the compiler is
still allocating the delegate on the heap if you use the first syntax.
 (the second is also shorter and clearer.)


Re: Scope storage class

2008-11-26 Thread bearophile
Jarrett Billingsley:
> Can you try declaring b as a nested function instead of as a delegate
> literal and see if that helps?

I think that may lead to nonworking code.

> (why are you declaring it the way you are, anyway?

Here you can find explanations:
http://en.wikipedia.org/wiki/Man_or_boy_test

Here you can find other two versions that work, but I think the version I have 
shown is the more robust one (that is: able to computer up to higher N values 
with D1 compiler):
http://www.rosettacode.org/wiki/Man_or_boy_test#D

Bye,
bearophile


Re: Scope storage class [Was: DMD 1.037 and 2.020 releases]

2008-11-26 Thread Jarrett Billingsley
On Wed, Nov 26, 2008 at 7:34 AM, bearophile <[EMAIL PROTECTED]> wrote:
> This is the code I have used for DMD 2.021. I was not sure how to use the 
> scope, so if you have improvements please tell me:
>
> import std.c.stdio: printf;
>
> int a(scope int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy 
> int x5) {
>scope int delegate() b;
>b = {
>k -= 1;
>return a(k, b(), x1, x2, x3, x4);
>};
>return k <= 0 ? x4 + x5 : b();
> }
>
> The code was too much slow in D2, so I have stopped it. Do you know if the D2 
> code can be improved to have performance similar to D1 ones?

Can you try declaring b as a nested function instead of as a delegate
literal and see if that helps?  (why are you declaring it the way you
are, anyway?


Scope storage class [Was: DMD 1.037 and 2.020 releases]

2008-11-26 Thread bearophile
To test the new scoping features of D 2.021 I have used a small stressing 
program, coming from this page, originally by Knuth:

http://www.rosettacode.org/wiki/Man_or_boy_test

More info:
http://en.wikipedia.org/wiki/Man_or_boy_test

My purpose is to see the D2 compiler being able to compute results up to N=25 
on my PC (that has 2 GB RAM and a 32 bit operating system).

---

This is the code I have used for DMD 1.037:

import std.c.stdio: printf;

int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int x5) {
int delegate() b;
b = {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(15, 1, -1, -1, 1, 0)); // N is 15
}

---

This is the code I have used for DMD 2.021. I was not sure how to use the 
scope, so if you have improvements please tell me:

import std.c.stdio: printf;

int a(scope int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int 
x5) {
scope int delegate() b;
b = {
k -= 1;
return a(k, b(), x1, x2, x3, x4);
};
return k <= 0 ? x4 + x5 : b();
}

void main() {
printf("%d\n", a(15, 1, -1, -1, 1, 0)); // N is 15
}

---

The results for higher values of N are:
k   21   2223 24  25
A   -389695 -865609 -1922362-4268854-9479595

In both cases I have compiled the code with:
dmd -O -release -inline -L/STACK:17 man_or_boy.d

The results:

DMD V.1.037 (exe: 168_476: bytes):
  N=24:  788 MB RAM, 3 seconds
  N=25: 1.57 GB RAM, 6.42 seconds

DMD V.2.021 (exe: 99_356 bytes):

The code was too much slow in D2, so I have stopped it. Do you know if the D2 
code can be improved to have performance similar to D1 ones?

Bye,
bearophile