2016-02-29 1 views
5

作業からGCC __restrict__修飾子を停止すると、-O2(GCC 4.8.5)でコンパイルされた、いくつかのかなり簡単なコードです:何ここ

unsigned char * linebuf; 
int yuyv_tojpegycbcr(unsigned char * buf, int w) 
{ 
    int col; 
    unsigned char * restrict pix = buf; 
    unsigned char * restrict line = linebuf; 

    for(col = 0; col < w - 1; col +=2) 
    { 
      line[col*3] = pix[0]; 
      line[col*3 + 1] = pix[1]; 
      line[col*3 + 2] = pix[3]; 
      line[col*3 + 3] = pix[2]; 
      line[col*3 + 4] = pix[1]; 
      line[col*3 + 5] = pix[3]; 
      pix += 4; 
    } 
    return 0; 
} 

、ここでは、対応するアセンブリです:

0000000000000000 <yuyv_tojpegycbcr>: 
    0: 83 fe 01    cmp $0x1,%esi 
    3: 48 8b 05 00 00 00 00 mov 0x0(%rip),%rax  # a <yuyv_tojpegycbcr+0xa> 
    a: 7e 4e     jle 5a <yuyv_tojpegycbcr+0x5a> 
    c: 83 ee 02    sub $0x2,%esi 
    f: 31 d2     xor %edx,%edx 
    11: d1 ee     shr %esi 
    13: 48 8d 74 76 03   lea 0x3(%rsi,%rsi,2),%rsi 
    18: 48 01 f6    add %rsi,%rsi 
    1b: 0f 1f 44 00 00   nopl 0x0(%rax,%rax,1) 
    20: 0f b6 0f    movzbl (%rdi),%ecx 
    23: 48 83 c2 06    add $0x6,%rdx 
    27: 48 83 c7 04    add $0x4,%rdi 
    2b: 48 83 c0 06    add $0x6,%rax 
    2f: 88 48 fa    mov %cl,-0x6(%rax) 
    32: 0f b6 4f fd    movzbl -0x3(%rdi),%ecx 
    36: 88 48 fb    mov %cl,-0x5(%rax) 
    39: 0f b6 4f ff    movzbl -0x1(%rdi),%ecx 
    3d: 88 48 fc    mov %cl,-0x4(%rax) 
    40: 0f b6 4f fe    movzbl -0x2(%rdi),%ecx 
    44: 88 48 fd    mov %cl,-0x3(%rax) 
    47: 0f b6 4f fd    movzbl -0x3(%rdi),%ecx 
    4b: 88 48 fe    mov %cl,-0x2(%rax) 
    4e: 0f b6 4f ff    movzbl -0x1(%rdi),%ecx 
    52: 88 48 ff    mov %cl,-0x1(%rax) 
    55: 48 39 f2    cmp %rsi,%rdx 
    58: 75 c6     jne 20 <yuyv_tojpegycbcr+0x20> 
    5a: 31 c0     xor %eax,%eax 
    5c: c3      retq 

制限修飾子なしでコンパイルすると、出力は同じになります。 混在したロードとストアがたくさんあります。いくつかの値は2回読み込まれ、最適化が行われなかったようです。 pixとは私が十分にスマートで、とりわけpix [1]とpix [3]を一度だけロードします。

restrict修飾子を失格とする可能性のあることは何ですか?

PS: 新しいgcc(4.9.2)では、別のアーキテクチャ(腕v7)では結果が似ています。ここには、生成されたコードを制限付きで比較するためのテストスクリプトがあります。

#!/bin/sh 
gcc -c -o test.o -std=c99 -O2 yuyv_to_jpegycbcr.c 
objdump -d test.o > test.S 


gcc -c -o test2.o -O2 -D restrict='' yuyv_to_jpegycbcr.c 
objdump -d test2.o > test2.S 
+0

標準の 'restrict'修飾子を使用しない理由は何ですか? – Olaf

+0

私は有効なfeature_test_macrosを設定していないため、std = c99を使用すると自分のコードが壊れている可能性があります。私はこれを修正することができますが、それは違いが生じるとは思わない。 – shodanex

+0

ここでもベクトル化が期待されるはずです(コンパイルするデバイスがそれをサポートしていると仮定します)。 – marko

答えて

4

ローカル変数ではなく関数のパラメータにrestrictを設定します。

私の経験から、ほとんどのコンパイラ(GCCを含む)は、関数パラメータで指定されている場合に限り、制限を利用します。関数内のローカル変数に対するすべての使用は無視されます。

これは、エイリアシング解析が基本ブロックレベルではなく機能レベルで行われていると考えられます。しかし、私はこれを裏付ける証拠はない。さらに、それはおそらくコンパイラとコンパイラのバージョンによって異なります。

いずれにしても、これらの種類のものは信頼できるものではありません。したがって、パフォーマンスが重要な場合は、手動で最適化するか、コンパイラーをアップグレードまたは変更するたびに再訪することを忘れないでください。

+1

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60712のコメントごとに、gccは関数パラメータに限定して適用されるようです – shodanex

+0

ブロック行列の乗算でこれを正確に見ています。これには6つのループがあります。一番内側の3つのループを制約パラメータ付きの静的関数に入れると、関数を宣言しない場合の2倍の速さでコードが実行されます。私はGCC(6.3)とClang(4.0)と同じ効果を見ます。だから、コンパイラはローカル変数を無視しているように見えます。私はICCについて知らない。 –

+0

また、別の静的関数を宣言するときにコンパイラが悪い結果を出すこともあります。場合によっては、別のオブジェクトファイルでrestrictを使用して内部関数を宣言する必要があります。だから、あなたが言うことを正確に行う必要があります:最初にアセンブリをチェックし、各アップグレードまたはコンパイラを変更します。 –

関連する問題