4

構造体の割り当てを最適化する際にコンパイラがどの程度優れているかを知りたくて、いくつかのテストを行ったところ、驚くべき結果が得られました。(この質問は GCC に伝えたいと思います。)

特に、GCC 4.6.3 (-O3) (編集: GCC 4.8.0 の出力も含めます) が次のコードを生成するアセンブラーを見ていました。

template<class T>
struct C
{
  T F[3];
  C(){}
  C(const T& t0,const T& t1,const T& t2): F{{t0},{t1},{t2}} {}
};

template<class T>
__attribute__((always_inline))
C<T>
operator+( const C<T>& l , const C<T>& r )
{
  return C<T>( l.F[0] + r.F[0] , 
           l.F[1] + r.F[1] , 
           l.F[2] + r.F[2] );
}

int main() 
{
  C<C<C<float> > > a,b,c;

  a=b+c;

  printf("%s",(const char*)&a);
}

ここでアセンブラ:

movss   264(%rsp), %xmm0
leaq    48(%rsp), %rbx
leaq    156(%rsp), %rbp
addss   376(%rsp), %xmm0
movss   %xmm0, 4(%rsp)

movss   260(%rsp), %xmm0
addss   372(%rsp), %xmm0
movss   %xmm0, 8(%rsp)

movss   256(%rsp), %xmm0
addss   368(%rsp), %xmm0
movss   %xmm0, 12(%rsp)

movss   252(%rsp), %xmm0
addss   364(%rsp), %xmm0
movss   %xmm0, 16(%rsp)

movss   248(%rsp), %xmm0
addss   360(%rsp), %xmm0
movss   %xmm0, 20(%rsp)

movss   244(%rsp), %xmm0
addss   356(%rsp), %xmm0
movss   %xmm0, 24(%rsp)

movss   240(%rsp), %xmm0
addss   352(%rsp), %xmm0
movss   %xmm0, 28(%rsp)

movss   236(%rsp), %xmm0
addss   348(%rsp), %xmm0
movss   %xmm0, 32(%rsp)

movss   232(%rsp), %xmm0
addss   344(%rsp), %xmm0
movss   %xmm0, 36(%rsp)

movss   228(%rsp), %xmm0
addss   340(%rsp), %xmm0
movss   %xmm0, 40(%rsp)

movss   224(%rsp), %xmm0
addss   336(%rsp), %xmm0
movss   %xmm0, 44(%rsp)    // 11-th

movss   220(%rsp), %xmm0
movss   164(%rsp), %xmm14
movss   160(%rsp), %xmm15
addss   332(%rsp), %xmm0
addss   272(%rsp), %xmm15
movss   216(%rsp), %xmm1
addss   276(%rsp), %xmm14
movss   212(%rsp), %xmm2
movss   208(%rsp), %xmm3
addss   328(%rsp), %xmm1
movss   204(%rsp), %xmm4
addss   324(%rsp), %xmm2
movss   200(%rsp), %xmm5
addss   320(%rsp), %xmm3
movss   196(%rsp), %xmm6
addss   316(%rsp), %xmm4
movss   192(%rsp), %xmm7
addss   312(%rsp), %xmm5
movss   188(%rsp), %xmm8
addss   308(%rsp), %xmm6
movss   184(%rsp), %xmm9
addss   304(%rsp), %xmm7
movss   180(%rsp), %xmm10
addss   300(%rsp), %xmm8
movss   176(%rsp), %xmm11
addss   296(%rsp), %xmm9
movss   172(%rsp), %xmm12
addss   292(%rsp), %xmm10
movss   168(%rsp), %xmm13
addss   288(%rsp), %xmm11
addss   284(%rsp), %xmm12
movss   %xmm15, 384(%rsp)
addss   280(%rsp), %xmm13  // all 27 floats added
movss   %xmm14, 388(%rsp)
movss   %xmm0, 444(%rsp)
movss   44(%rsp), %xmm0
movss   %xmm0, 448(%rsp)
movss   40(%rsp), %xmm0
movss   %xmm0, 452(%rsp)
movss   36(%rsp), %xmm0
movss   %xmm0, 456(%rsp)
movss   32(%rsp), %xmm0
movss   %xmm0, 460(%rsp)
movss   28(%rsp), %xmm0
movss   %xmm0, 464(%rsp)
movss   24(%rsp), %xmm0
movss   %xmm0, 468(%rsp)
movss   20(%rsp), %xmm0
movss   %xmm0, 472(%rsp)
movss   16(%rsp), %xmm0
movss   %xmm0, 476(%rsp)
movss   12(%rsp), %xmm0
movss   %xmm0, 480(%rsp)
movss   8(%rsp), %xmm0
movss   %xmm13, 392(%rsp)
movss   %xmm12, 396(%rsp)
movss   %xmm11, 400(%rsp)
movss   %xmm10, 404(%rsp)
movss   %xmm9, 408(%rsp)
movss   %xmm8, 412(%rsp)
movss   %xmm7, 416(%rsp)
movss   %xmm6, 420(%rsp)
movss   %xmm5, 424(%rsp)
movss   %xmm4, 428(%rsp)
movss   %xmm3, 432(%rsp)
movss   %xmm2, 436(%rsp)
movss   %xmm1, 440(%rsp)
movss   %xmm0, 484(%rsp)  // Storing of temporary finished
movq    384(%rsp), %rax   // Now begin copy temporary to destination
movss   4(%rsp), %xmm0
movss   %xmm0, 488(%rsp)
movq    %rax, 48(%rsp)
movq    392(%rsp), %rax
movq    %rax, 56(%rsp)
movq    400(%rsp), %rax
movq    %rax, 64(%rsp)
movq    408(%rsp), %rax
movq    %rax, 72(%rsp)
movq    416(%rsp), %rax
movq    %rax, 80(%rsp)
movq    424(%rsp), %rax
movq    %rax, 88(%rsp)
movq    432(%rsp), %rax
movq    %rax, 96(%rsp)
movq    440(%rsp), %rax
movq    %rax, 104(%rsp)
movq    448(%rsp), %rax
movq    %rax, 112(%rsp)
movq    456(%rsp), %rax
movq    %rax, 120(%rsp)
movq    464(%rsp), %rax
movq    %rax, 128(%rsp)
movq    472(%rsp), %rax
movq    %rax, 136(%rsp)
movq    480(%rsp), %rax
movq    %rax, 144(%rsp)
movl    488(%rsp), %eax
movl    %eax, 152(%rsp)  // Whole struct copied
.p2align 4,,10

アセンブラは、示された行から始まる (ネストされた) 構造体全体の追加のコピーを表示します。これは、コンパイラーが割り当てを発行する必要があるためだと言う人もいるかもしれません (省略できるコピーとは対照的に)。

実験を繰り返しました。今回は、3 重にネストされた構造体の代わりに、2 重にネストされた構造体のみを使用しました。その後、追加のコピーは行われません。2 番目の実験のコードは次のとおりです。

int main() 
{
  C<C<float> > a,b,c;

  a=b+c;

  printf("%s",(const char*)&a);
}

そしてアセンブラ:

    movss   80(%rsp), %xmm0
    movq    %rsp, %rdx
    movss   76(%rsp), %xmm1
    addss   128(%rsp), %xmm0
    movss   72(%rsp), %xmm2
    addss   124(%rsp), %xmm1
    movss   68(%rsp), %xmm3
    addss   120(%rsp), %xmm2
    movss   64(%rsp), %xmm4
    addss   116(%rsp), %xmm3
    movss   60(%rsp), %xmm5
    addss   112(%rsp), %xmm4
    movss   56(%rsp), %xmm6
    addss   108(%rsp), %xmm5
    movss   52(%rsp), %xmm7
    addss   104(%rsp), %xmm6
    movss   48(%rsp), %xmm8
    addss   100(%rsp), %xmm7
    addss   96(%rsp), %xmm8
    xorl    %eax, %eax
    movss   %xmm2, 24(%rsp)
    movss   %xmm3, 20(%rsp)
    movss   %xmm4, 16(%rsp)
    movss   %xmm5, 12(%rsp)
    movss   %xmm6, 8(%rsp)
    movss   %xmm7, 4(%rsp)
    movss   %xmm8, (%rsp)
    movss   %xmm1, 28(%rsp)
    movss   %xmm0, 32(%rsp)

一時構造体 (の結果を保持するためb+c) をレジスタ ファイル (9 レジスタ、xmm0-xmm8) に完全に割り当て、その後コピーせずに格納できることは明らかです。

ただし、操作 (追加 + 代入) は、ストレージ コンテナーで動作する命令に対して弱いデータ依存性しかもたらしません。私が尋ねている質問は次のとおりです。最初の実験では、データの依存関係により命令の最適なスケジューリングが可能になるため、追加のコピーが不要になるようにコンパイラが命令をスケジュールしないのはなぜですか。つまり、結果を直接保存する最終メモリアドレスに?コンパイラが調べることができない依存関係または境界の側面があり、この種の最適化を効果的に妨げていますか?

編集:

GCC 4.8.0 (-std=c++0x -S -O3) から作成されたアセンブラー:

movss   264(%rsp), %xmm0
leaq    48(%rsp), %rdx
movss   260(%rsp), %xmm1
addss   376(%rsp), %xmm0
movss   256(%rsp), %xmm2
addss   372(%rsp), %xmm1
movss   252(%rsp), %xmm3
addss   368(%rsp), %xmm2
movss   248(%rsp), %xmm4
addss   364(%rsp), %xmm3
movss   244(%rsp), %xmm5
addss   360(%rsp), %xmm4
addss   356(%rsp), %xmm5
movss   196(%rsp), %xmm11
addss   308(%rsp), %xmm11
movss   %xmm0, 4(%rsp)
movss   %xmm1, 8(%rsp)
movss   %xmm2, 12(%rsp)
movss   %xmm3, 16(%rsp)
movss   %xmm4, 20(%rsp)
movss   %xmm5, 24(%rsp)
movss   240(%rsp), %xmm0
movss   236(%rsp), %xmm1
movss   232(%rsp), %xmm2
addss   352(%rsp), %xmm0
movss   228(%rsp), %xmm3
addss   348(%rsp), %xmm1
movss   224(%rsp), %xmm4
addss   344(%rsp), %xmm2
movss   220(%rsp), %xmm5
addss   340(%rsp), %xmm3
movss   216(%rsp), %xmm6
addss   336(%rsp), %xmm4
movss   212(%rsp), %xmm7
addss   332(%rsp), %xmm5
movss   208(%rsp), %xmm8
addss   328(%rsp), %xmm6
movss   204(%rsp), %xmm9
addss   324(%rsp), %xmm7
movss   200(%rsp), %xmm10
addss   320(%rsp), %xmm8
addss   316(%rsp), %xmm9
addss   312(%rsp), %xmm10
movss   %xmm11, 28(%rsp)
movss   192(%rsp), %xmm12
movss   188(%rsp), %xmm13
movss   184(%rsp), %xmm14
addss   304(%rsp), %xmm12
movss   180(%rsp), %xmm15
addss   300(%rsp), %xmm13
addss   296(%rsp), %xmm14
movss   176(%rsp), %xmm11
addss   292(%rsp), %xmm15
addss   288(%rsp), %xmm11
movss   %xmm12, 32(%rsp)
movss   %xmm13, 36(%rsp)
movss   %xmm14, 40(%rsp)
movss   %xmm15, 44(%rsp)
movss   172(%rsp), %xmm12
movss   168(%rsp), %xmm13
movss   164(%rsp), %xmm14
addss   284(%rsp), %xmm12
movss   160(%rsp), %xmm15
addss   280(%rsp), %xmm13
addss   276(%rsp), %xmm14
movss   %xmm11, 400(%rsp)
addss   272(%rsp), %xmm15
movss   %xmm12, 396(%rsp)
movss   %xmm13, 392(%rsp)
movss   %xmm14, 388(%rsp)
movss   36(%rsp), %xmm13
movss   40(%rsp), %xmm14
movss   %xmm15, 384(%rsp)
movss   32(%rsp), %xmm12
movss   44(%rsp), %xmm15
movss   %xmm15, 404(%rsp)
movss   %xmm14, 408(%rsp)
movss   %xmm13, 412(%rsp)
movss   %xmm12, 416(%rsp)
movq    384(%rsp), %rax
movss   28(%rsp), %xmm11
movss   %xmm11, 420(%rsp)
movq    %rax, 48(%rsp)
movq    392(%rsp), %rax
movss   %xmm5, 444(%rsp)
movss   %xmm4, 448(%rsp)
movss   24(%rsp), %xmm5
movq    %rax, 56(%rsp)
movss   %xmm3, 452(%rsp)
movq    400(%rsp), %rax
movss   20(%rsp), %xmm4
movss   16(%rsp), %xmm3
movss   %xmm2, 456(%rsp)
movq    %rax, 64(%rsp)
movq    408(%rsp), %rax
movss   %xmm1, 460(%rsp)
movss   12(%rsp), %xmm2
movss   8(%rsp), %xmm1
movq    %rax, 72(%rsp)
movq    416(%rsp), %rax
movss   %xmm0, 464(%rsp)
movss   4(%rsp), %xmm0
movss   %xmm10, 424(%rsp)
movss   %xmm9, 428(%rsp)
movss   %xmm8, 432(%rsp)
movss   %xmm7, 436(%rsp)
movss   %xmm6, 440(%rsp)
movss   %xmm5, 468(%rsp)
movss   %xmm4, 472(%rsp)
movss   %xmm3, 476(%rsp)
movss   %xmm2, 480(%rsp)
movss   %xmm1, 484(%rsp)
movss   %xmm0, 488(%rsp)
movq    %rax, 80(%rsp)
movq    424(%rsp), %rax
movq    %rax, 88(%rsp)
movq    432(%rsp), %rax
movq    %rax, 96(%rsp)
movq    440(%rsp), %rax
movq    %rax, 104(%rsp)
movq    448(%rsp), %rax
movq    %rax, 112(%rsp)
movq    456(%rsp), %rax
movq    %rax, 120(%rsp)
movq    464(%rsp), %rax
movq    %rax, 128(%rsp)
movq    472(%rsp), %rax
movq    %rax, 136(%rsp)
movq    480(%rsp), %rax
movq    %rax, 144(%rsp)
movl    488(%rsp), %eax
movl    %eax, 152(%rsp)

追加のコピーはまだそこにあります。

4

0 に答える 0