Thread overview
LDC, ARM (seems like x86 too) bug?
Sep 20
Johan
September 19
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
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
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
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