Thread overview | ||||||
---|---|---|---|---|---|---|
|
September 19, 2017 LDC, ARM (seems like x86 too) bug? | ||||
---|---|---|---|---|
| ||||
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 Re: LDC, ARM (seems like x86 too) bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jack Applegame | 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 Re: LDC, ARM (seems like x86 too) bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johan Engelen | 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 Re: LDC, ARM (seems like x86 too) bug? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jack Applegame | 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
|
Copyright © 1999-2021 by the D Language Foundation