Severe 2.084 regression when using staticArray on array of struct with class and bool member

Basile B. b2.temp at gmx.com
Tue Feb 12 20:26:55 UTC 2019


On Tuesday, 12 February 2019 at 14:44:10 UTC, ag0aep6g wrote:
> On 12.02.19 15:06, Per Nordlöw wrote:
>> class C
>> {
>>      this(int i) { this.i = i; }
>>      int i;
>> }
>> 
>> struct S
>> {
>>      C c;
>>      bool b;                  // removing this prevents bug
>> }
>> 
>> void main()
>> {
>>      import std.stdio : writeln;
>>      import std.array : staticArray;
>> 
>>      auto c = new C(42);
>> 
>>      const S[1] s1 = [S(c)].staticArray;
>>      const S[1] s2 = [S(c)];
>> 
>>      writeln(cast(void*)s1[0].c);
>>      writeln(cast(void*)s2[0].c);
>> 
>>      assert(s1[0].c is
>>             s2[0].c);
>> }
>
> Ouch. That looks bad. A reduction:
>
> ----
> struct S
> {
>     ulong c;
>     bool b;                  // removing this prevents bug
> }
>
> void main()
> {
>     S[1] a = [S(42)];
>     assert(a[0].c == 42); /* Passes. */
>     f(a);
> }
>
> void f(S[1] a)
> {
>     assert(a[0].c == 42); /* Fails. */
> }
> ----
>
> Fails since 2.070. https://run.dlang.io/is/LBhn4l

It's a bad codegen, or what i would call trivially "an ABI 
disagreement", explaining why LDC doesn't exhibits the bug.

As far as I can see the problem is that the static array is 
passed by the registers, so under linux, `c` in RDI, and `b` in 
RSI but then in `f()` the backend thinks that it's passed using 
the stack.

The bug goes away when S size is over or equal to 33 bytes 
because in this case the parameter is well copied.

material leading to this conclusion:

```
struct S
{
     ulong c;
     bool b;                  // removing this prevents bug
}

import disassembler, std.stdio; // godbolt is too noisy with dmd 
so i use mine

void main()
{
     S[1] a = [S(42, true)];
     showThatRegsAreUsed(a);
     showDmdBadCodegen(a);
     writeln(prettyDisasm(&showThatRegsAreUsed));
     writeln(prettyDisasm(&showDmdBadCodegen));
}

void showDmdBadCodegen(S[1] a)
{
     writeln(a[0].c);
}

void showThatRegsAreUsed(S[1] a)
{
     alias writeul = writeln!ulong;
     asm
     {
         naked;
         push RSI;
         call writeul; // 1st param, so 42
         pop RSI;
         mov RDI, RSI;
         call writeul; // 2nd so RSI
         ret;
     }
}
```

output:

compiling /tmp/temp_7F711D03FA50.d
using /usr/bin/dmd (dmd)
/tmp/temp_7F711D03FA50.d successfully compiled
Runnable build duration: 0 minutes, 0 seconds and 399 msecs
42
1
0
;------- SUB 00000000004511ACh -------; showThatRegsAreUsed
00000000004511ACh  push rsi
00000000004511ADh  call 00000000004516FCh
00000000004511B2h  pop rsi
00000000004511B3h  mov rdi, rsi
00000000004511B6h  call 00000000004516FCh
00000000004511BBh  ret
;-------------------------------------


;------- SUB 000000000045119Ch -------; showDmdBadCodegen
000000000045119Ch  push rbp
000000000045119Dh  mov rbp, rsp
00000000004511A0h  mov rdi, qword ptr [rbp+10h] ; ouch 42 is 
erased here !
00000000004511A4h  call 00000000004516FCh
00000000004511A9h  pop rbp
00000000004511AAh  ret
;-------------------------------------



More information about the Digitalmars-d mailing list