Thread overview
LDC, ARM (seems like x86 too) bug?
Sep 19, 2017
Jack Applegame
Sep 19, 2017
Johan Engelen
Sep 20, 2017
Jack Applegame
Sep 20, 2017
Johan
September 19, 2017
Code:

> // values from linker script
> extern(C) extern __gshared {
> 	uint src_beg; // source begin 	uint trg_beg; // target begin
> 	uint trg_end; // target end }
> 
> void copy(uint* ss, uint* ts, const uint* te) {
>  	while(ts != te) *ts++ = *ss++;
> }
> 
> void foo() {
>  	copy(&src_beg, &trg_beg, &trg_end);
> }

Function `copy` dump:

> void example.copy(uint*, uint*, const(uint*)):
>         cmp     r1, r0
>         it      eq
>         bxeq    lr
> .LBB0_1:
>         ldr     r3, [r2], #4
>         str     r3, [r1], #4
>         cmp     r0, r1
>         bne     .LBB0_1
>         bx      lr

Everything looks good.

Function `foo` dump:

> void example.foo():
>         movw    r0, :lower16:trg_beg
>         movw    r1, :lower16:src_beg
>         movw    r2, :lower16:trg_end
>         movt    r0, :upper16:trg_beg
>         movt    r1, :upper16:src_beg
>         movt    r2, :upper16:trg_end
> .LBB1_1:
>         ldr     r3, [r1], #4
>         str     r3, [r0], #4
>         cmp     r2, r0
>         bne     .LBB1_1
>         bx      lr

Function `copy` is inlined - very good, but the loop condition check must be before the loop body.

See https://godbolt.org/g/NtjvQM

Apparently, LDC believes that addresses of `trg_beg` and `trg_end` can not be initially equal and moves check to the end. But this is not always the case.

Changing condition to `<` fixes issue:

> void example.foo():
>         movw    r0, :lower16:trg_end
>         movw    r1, :lower16:trg_beg
>         movt    r0, :upper16:trg_end
>         movt    r1, :upper16:trg_beg
>         cmp     r1, r0
>         it      hs
>         bxhs    lr
>         movw    r1, :lower16:trg_beg
>         movw    r2, :lower16:src_beg
>         movt    r1, :upper16:trg_beg
>         movt    r2, :upper16:src_beg
> .LBB1_1:
>         ldr     r3, [r2], #4
>         str     r3, [r1], #4
>         cmp     r1, r0
>         blo     .LBB1_1
>         bx      lr

See https://godbolt.org/g/t2arr7
September 19, 2017
On Tuesday, 19 September 2017 at 09:52:12 UTC, Jack Applegame wrote:
> Code:
>
>> // values from linker script
>> extern(C) extern __gshared {
>> 	uint src_beg; // source begin 	uint trg_beg; // target begin
>> 	uint trg_end; // target end }
>> 
>> void copy(uint* ss, uint* ts, const uint* te) {
>>  	while(ts != te) *ts++ = *ss++;
>> }
>> 
>> void foo() {
>>  	copy(&src_beg, &trg_beg, &trg_end);
>> }

[snip]

> Apparently, LDC believes that addresses of `trg_beg` and `trg_end` can not be initially equal and moves check to the end. But this is not always the case.

This is a question of spec details. We are assuming C semantics for extern variables: just like normal variables, they cannot alias.
See also: https://stackoverflow.com/questions/5559281/c-externs-that-alias-the-same-address

LLVM optimizes these cases more aggressively than GCC: https://godbolt.org/g/yJdp9P

-Johan


September 20, 2017
On Tuesday, 19 September 2017 at 21:21:41 UTC, Johan Engelen wrote:
> This is a question of spec details. We are assuming C semantics for extern variables: just like normal variables, they cannot alias.
> See also: https://stackoverflow.com/questions/5559281/c-externs-that-alias-the-same-address
>
> LLVM optimizes these cases more aggressively than GCC: https://godbolt.org/g/yJdp9P
>
> -Johan

Thank you for explanation.
September 20, 2017
On Wednesday, 20 September 2017 at 06:57:19 UTC, Jack Applegame wrote:
> On Tuesday, 19 September 2017 at 21:21:41 UTC, Johan Engelen wrote:
>> This is a question of spec details. We are assuming C semantics for extern variables: just like normal variables, they cannot alias.
>> See also: https://stackoverflow.com/questions/5559281/c-externs-that-alias-the-same-address
>>
>> LLVM optimizes these cases more aggressively than GCC: https://godbolt.org/g/yJdp9P
>>
>> -Johan
>
> Thank you for explanation.

Is it important for you to be able to alias external symbols?
(ARM's compiler and others have __attribute__((alias)) for it)

-Johan