www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 14451] New: static-foreach uses huge stack for no reason

https://issues.dlang.org/show_bug.cgi?id=14451

          Issue ID: 14451
           Summary: static-foreach uses huge stack for no reason
           Product: D
           Version: D2
          Hardware: x86_64
                OS: Linux
            Status: NEW
          Severity: major
          Priority: P1
         Component: DMD
          Assignee: nobody puremagic.com
          Reporter: tomerfiliba gmail.com

Using static foreach (on a compile-time known range) basically expands the code
block so many times. That's excellent, except that variables declared inside
the foreach-body are not scoped properly, which causes needless, huge stack
allocation.

Consider the following snippet:

================================================
import std.traits;

struct S {ubyte a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;}

string[] staticForeach1() {
    string[] arr;

    foreach(string name; __traits(allMembers, S)) {
        ulong[100] x;
        arr ~= name;
    }
    return arr;
}

string[] staticForeach2() {
    string[] arr;

    foreach(string name; __traits(allMembers, S)) {
        (){
            ulong[100] x;
            arr ~= name;
        }();
    }
    return arr;
}
================================================

The first version compiles to 

Dump of assembler code for function staticForeach1:
   0x0000000000426170 <+0>:     push   %rbp
   0x0000000000426171 <+1>:     mov    %rsp,%rbp
   0x0000000000426174 <+4>:     sub    $0x52f8,%rsp   <<<<<
   0x000000000042617b <+11>:    push   %rbx
   0x000000000042617c <+12>:    movq   $0x0,-0x52f0(%rbp)
   0x0000000000426187 <+23>:    movq   $0x0,-0x52e8(%rbp)

requiring over 20K of stack space. The second version compiles to

Dump of assembler code for function staticForeach2:
   0x0000000000426c48 <+0>:     push   %rbp
   0x0000000000426c49 <+1>:     mov    %rsp,%rbp
   0x0000000000426c4c <+4>:     sub    $0x10,%rsp    <<<<<
   0x0000000000426c50 <+8>:     movq   $0x0,-0x10(%rbp)
   0x0000000000426c58 <+16>:    movq   $0x0,-0x8(%rbp)
   0x0000000000426c60 <+24>:    mov    %rbp,%rdi
   0x0000000000426c63 <+27>:    callq  0x426d40
<staticForeach2FZ9__lambda1MFNbNfZv>
   0x0000000000426c68 <+32>:    mov    %rbp,%rdi
   0x0000000000426c6b <+35>:    callq  0x426db8
<staticForeach2FZ9__lambda2MFNbNfZv>
   0x0000000000426c70 <+40>:    mov    %rbp,%rdi

requiring only 16 bytes. I tried adding more scoping braces inside the foreach,
e.g.,

    foreach(string name; __traits(allMembers, S)) {
        {
            ulong[100] x;
            arr ~= name;
        }
    }

but anything other than actually invoking a separate function does not work.
Since I'm using fibers with small stacks, this is a real issue for me. I can
usually find workarounds (as described here), but there's no reason why so much
stack be wasted here.

--
Apr 16 2015