www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.ldc - LDC, ARM (seems like x86 too) bug?

reply Jack Applegame <japplegame gmail.com> writes:
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:


         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:


         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:


         cmp     r1, r0
         blo     .LBB1_1
         bx      lr
See https://godbolt.org/g/t2arr7
Sep 19 2017
parent reply Johan Engelen <j j.nl> writes:
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
Sep 19 2017
parent reply Jack Applegame <japplegame gmail.com> writes:
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.
Sep 19 2017
parent Johan <j j.nl> writes:
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
Sep 20 2017