October 23, 2013
David Nadlinger:

> 244d52f3c4e03dc2ed5d84940aaa04ab  ldc2-0.12.0-mingw-x86.7z

If I compile some C-looking D code using -noruntime can't LDC2 not put those runtime routine inside the binary and produce a smaller binary?

-----------------------

A small test program:


void main() {
    import core.stdc.stdio, std.math;
    immutable r = 11;
    foreach (immutable y; -r .. r + 1) {
        foreach (immutable x; -2 * r .. 2 * r + 1) {
            bool circle(in int c, in int r) pure nothrow {
                return r ^^ 2 >= (x / 2) ^^ 2 + (y - c) ^^ 2;
            }
            putchar(circle(-r / 2, r / 6) ? '#' :
                    circle( r / 2, r / 6) ? '.' :
                    circle(-r / 2, r / 2) ? '.' :
                    circle( r / 2, r / 2) ? '#' :
                    circle(     0, r)     ? "#."[x < 0] :
                                          ' ');
        }
        '\n'.putchar;
    }
}


Compiling using ldc 0.12 with ldmd2 -O -release -inline -noboundscheck -output-s it produces (note the __d_allocmemory, dmd doesn't inline the lambda but it doesn't perform that call):


__Dmain:
    pushl   %ebp
    pushl   %ebx
    pushl   %edi
    pushl   %esi
    subl    $8, %esp
    movl    $8, (%esp)
    calll   __d_allocmemory
    movl    %eax, 4(%esp)
    movl    $-11, %edi
    .align  16, 0x90
LBB0_1:
    movl    4(%esp), %eax
    movl    %edi, (%eax)
    movl    $-22, %ebx
    .align  16, 0x90
LBB0_2:
    movl    4(%esp), %eax
    movl    %ebx, 4(%eax)
    movl    %ebx, %ecx
    shrl    $31, %ecx
    leal    (%ebx,%ecx), %edx
    sarl    %edx
    imull   %edx, %edx
    leal    5(%edi), %ebp
    imull   %ebp, %ebp
    addl    %edx, %ebp
    movl    $35, %eax
    cmpl    $2, %ebp
    jl  LBB0_8
    leal    -5(%edi), %esi
    imull   %esi, %esi
    addl    %edx, %esi
    movl    $46, %eax
    cmpl    $2, %esi
    jl  LBB0_8
    cmpl    $26, %ebp
    jl  LBB0_8
    cmpl    $26, %esi
    movl    $35, %eax
    jl  LBB0_8
    movl    %edi, %esi
    imull   %esi, %esi
    addl    %edx, %esi
    movl    $32, %eax
    cmpl    $121, %esi
    jg  LBB0_8
    movzbl  _.str(%ecx), %eax
    .align  16, 0x90
LBB0_8:
    calll   __D4core4stdc5stdio7putcharFNbNeiZi
    incl    %ebx
    cmpl    $23, %ebx
    jne LBB0_2
    movl    $10, %eax
    calll   __D4core4stdc5stdio7putcharFNbNeiZi
    incl    %edi
    cmpl    $12, %edi
    jne LBB0_1
    xorl    %eax, %eax
    addl    $8, %esp
    popl    %esi
    popl    %edi
    popl    %ebx
    popl    %ebp
    ret


If I replace the lambda with an inner function:

void main() {
    import core.stdc.stdio, std.math;
    immutable r = 11;
    foreach (immutable y; -r .. r + 1) {
        foreach (immutable x; -2 * r .. 2 * r + 1) {
            bool circle(in int c, in int r) pure nothrow {
                return r ^^ 2 >= (x / 2) ^^ 2 + (y - c) ^^ 2;
            }
            putchar(circle(-r / 2, r / 6) ? '#' :
                    circle( r / 2, r / 6) ? '.' :
                    circle(-r / 2, r / 2) ? '.' :
                    circle( r / 2, r / 2) ? '#' :
                    circle(     0, r)     ? "#."[x < 0] :
                                          ' ');
        }
        '\n'.putchar;
    }
}


Now ldc doesn't show the call to __d_allocmemory, is this expected?

__Dmain:
    pushl   %ebp
    pushl   %ebx
    pushl   %edi
    pushl   %esi
    subl    $12, %esp
    movl    $-11, %eax
    .align  16, 0x90
LBB0_1:
    movl    %eax, (%esp)
    movl    %eax, %ecx
    imull   %ecx, %ecx
    movl    %ecx, 8(%esp)
    leal    -5(%eax), %ecx
    imull   %ecx, %ecx
    movl    %ecx, 4(%esp)
    leal    5(%eax), %ebp
    imull   %ebp, %ebp
    movl    $-22, %esi
    .align  16, 0x90
LBB0_2:
    movl    %esi, %ecx
    shrl    $31, %ecx
    leal    (%esi,%ecx), %edx
    sarl    %edx
    imull   %edx, %edx
    leal    (%edx,%ebp), %edi
    movl    $35, %eax
    cmpl    $2, %edi
    jl  LBB0_8
    movl    4(%esp), %eax
    leal    (%edx,%eax), %ebx
    movl    $46, %eax
    cmpl    $2, %ebx
    jl  LBB0_8
    cmpl    $26, %edi
    jl  LBB0_8
    cmpl    $26, %ebx
    movl    $35, %eax
    jl  LBB0_8
    addl    8(%esp), %edx
    movl    $32, %eax
    cmpl    $121, %edx
    jg  LBB0_8
    movzbl  _.str(%ecx), %eax
    .align  16, 0x90
LBB0_8:
    calll   __D4core4stdc5stdio7putcharFNbNeiZi
    incl    %esi
    cmpl    $23, %esi
    jne LBB0_2
    movl    $10, %eax
    calll   __D4core4stdc5stdio7putcharFNbNeiZi
    movl    (%esp), %eax
    incl    %eax
    cmpl    $12, %eax
    jne LBB0_1
    xorl    %eax, %eax
    addl    $12, %esp
    popl    %esi
    popl    %edi
    popl    %ebx
    popl    %ebp
    ret


Bye,
bearophile
October 23, 2013
> A small test program:
>
>
> void main() {
>     import core.stdc.stdio, std.math;
>     immutable r = 11;
>     foreach (immutable y; -r .. r + 1) {
>         foreach (immutable x; -2 * r .. 2 * r + 1) {
>             bool circle(in int c, in int r) pure nothrow {
>                 return r ^^ 2 >= (x / 2) ^^ 2 + (y - c) ^^ 2;
>             }
>             putchar(circle(-r / 2, r / 6) ? '#' :
>                     circle( r / 2, r / 6) ? '.' :
>                     circle(-r / 2, r / 2) ? '.' :
>                     circle( r / 2, r / 2) ? '#' :
>                     circle(     0, r)     ? "#."[x < 0] :
>                                           ' ');
>         }
>         '\n'.putchar;
>     }
> }


Sorry, I have copied two times the same code. That first code should be:

void main() {
    import core.stdc.stdio, std.math;
    immutable r = 11;
    foreach (immutable y; -r .. r + 1) {
        foreach (immutable x; -2 * r .. 2 * r + 1) {
            enum circle = (in int c, in int r) pure nothrow =>
                r ^^ 2 >= (x / 2) ^^ 2 + (y - c) ^^ 2;
            putchar(circle(-r / 2, r / 6) ? '#' :
                    circle( r / 2, r / 6) ? '.' :
                    circle(-r / 2, r / 2) ? '.' :
                    circle( r / 2, r / 2) ? '#' :
                    circle(     0, r)     ? "#."[x < 0] :
                                          ' ');
        }
        '\n'.putchar;
    }
}


Bye,
bearophile
October 23, 2013
On Win32 I got a error

D:/Dev/ldc/bin/../lib/libphobos-ldc.a(demangle.obj):fake:(.text+0xa9b): undefine
d reference to `__mingw_strtold'

What I need to do?
October 23, 2013
On Wed, Oct 23, 2013 at 8:59 PM, Michael <pr@m1xa.com> wrote:
> On Win32 I got a error
>
> D:/Dev/ldc/bin/../lib/libphobos-ldc.a(demangle.obj):fake:(.text+0xa9b):
> undefine
> d reference to `__mingw_strtold'
>
> What I need to do?

Are you using a recent version of mingw-w64, as indicated in the release notes and the README? If so, which one?

__mingw_strtold should be available in the MinGW C runtime.

David
October 23, 2013
On Wed, Oct 23, 2013 at 8:40 PM, bearophile <bearophileHUGS@lycos.com> wrote:
> If I compile some C-looking D code using -noruntime can't LDC2 not put those runtime routine inside the binary and produce a smaller binary?
>
> -----------------------
>
> A small test program:
>
>
> void main() {
>     import core.stdc.stdio, std.math;
>     immutable r = 11;
>     foreach (immutable y; -r .. r + 1) {
>         foreach (immutable x; -2 * r .. 2 * r + 1) {
>             bool circle(in int c, in int r) pure nothrow {
>                 return r ^^ 2 >= (x / 2) ^^ 2 + (y - c) ^^ 2;
>             }
>             putchar(circle(-r / 2, r / 6) ? '#' :
>                     circle( r / 2, r / 6) ? '.' :
>                     circle(-r / 2, r / 2) ? '.' :
>                     circle( r / 2, r / 2) ? '#' :
>                     circle(     0, r)     ? "#."[x < 0] :
>                                           ' ');
>         }
>         '\n'.putchar;
>     }
> }

This program shouldn't even need to pull in std.math with LDC (we don't follow DMD w.r.t. the wonky requirement of importing std.math to use ^^). And indeed, if you remove the std.math import, no Phobos modules are pulled in.

> Compiling using ldc 0.12 with ldmd2 -O -release -inline -noboundscheck -output-s it produces (note the __d_allocmemory, dmd doesn't inline the lambda but it doesn't perform that call):

You are right, it shouldn't even allocate the lambda in the first place, but even if it did, one of the optimization passes should actually promote the allocation to the stack. Investigating…

David
October 23, 2013
David Nadlinger:

> You are right, it shouldn't even allocate the lambda in the first
> place, but even if it did, one of the optimization passes should
> actually promote the allocation to the stack. Investigating…

Please note the successive email I have written, where I have fixed a mistake. I have copied two times the same code. The code with the __d_allocmemory is the one with:

            enum circle = (in int c, in int r) pure nothrow =>
                r ^^ 2 >= (x / 2) ^^ 2 + (y - c) ^^ 2;

Bye,
bearophile
October 23, 2013
David Nadlinger:

> This program shouldn't even need to pull in std.math with LDC (we
> don't follow DMD w.r.t. the wonky requirement of importing std.math to
> use ^^).

D code must be written to work on both DMD and LDC as much as humanly possible, so I'll not use that nice feature of LDC, and I hope others will do the same :-(

Bye,
bearophile
October 23, 2013
Thanks David,

just updated mingw64 )

October 23, 2013
On Wed, Oct 23, 2013 at 9:30 PM, bearophile <bearophileHUGS@lycos.com> wrote:
> D code must be written to work on both DMD and LDC as much as humanly possible, so I'll not use that nice feature of LDC, and I hope others will do the same :-(

Yes, of course. I just meant that there is definitely something strange going on (i.e. LDC emits code it wouldn't need to), as importing std.math isn't actually needed.

So, there really shouldn't be any reason for Phobos code to end up in the executable even if you add the extra import, i.e. this is definitely a bug in LDC.

Could you add the program to the GitHub tracker (just post it as a whole, mentioning that no symbols from std.math should be pulled in)? If you do it yourself, you'll get a notification as soon as the bug is fixed.

Thanks,
David
October 23, 2013
What news about Win64/MSVC port?)