4

私はしばらくの間、これに頭を悩ませてきました。私はGCC4.4.4を使用しています(GCC 3.4.6、4.4.6、および4.6.3をチェックしました)。実行していた数学で問題が発生しました。この例を次の自己完結型プログラムにまとめました。

#include <stdio.h>
int main()
{
    float something[4] = { 1.0f, 2.0f, 3.0f, 4.0f };
    asm volatile
    (
        "movups %0, %%xmm0 \n\t"
        "movups %%xmm0, %0 \n\t"
        : "=m" (*something)
        :
        : "memory", "xmm0"
    );
    printf("%.0f %.0f %.0f %.0f\n",
        something[0], something[1], something[2], something[3]);
    return 0;
}

で簡単にコンパイル

gcc -msse -O -o something something.c

どういうわけか最初の配列要素が破損して失敗します(私が試したGCC 3.4.6を除いて...そこでは正常に動作します)。私の人生の間、ここで根本的に間違っているものを見ることはできません。

代わりに、問題のASMブロックを次のように変更します。

_mm_storeu_ps(something, _mm_loadu_ps(something));

それはうまくいきます。生成されたアセンブリコードを確認したところ、ASMブロックを含むバージョンには、SSE部分に至るまでのストア操作が1つ少ないことがわかりました。

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $64, %esp
    movl    $0x40000000, 52(%esp)
    movl    $0x40400000, 56(%esp)
    movl    $0x40800000, 60(%esp)

対より正確(組み込み関数を使用したコード):

main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $64, %esp
    movl    $0x3f800000, 48(%esp)
    movl    $0x40000000, 52(%esp)
    movl    $0x40400000, 56(%esp)
    movl    $0x40800000, 60(%esp)

WTFは私またはGCCのどちらかで間違っていますか?

(これは、私が追跡した根本的な問題を示す、要約された簡潔な例です。ASMブロックとvolatileキーワードには理由がありますが、これらはすべて、私が置いている主な懸念事項に実際には対応していないようです。ここに転送します。)

4

1 に答える 1

3

間違った制約を使用しました(ちなみに、これは今日ここで尋ねられる2番目の問題です)。は出力を意味するので、gccは、最初の配列要素=を割り当てるつもりだと考えました。*somethingとにかく上書きするので、初期化を省略できると考えました。次のように、符号を使用+してオペランドを入出力としてマークする必要があります"+m" (*something)

"=m" (something)一般に、gccがすべての初期化を省略することを決定する可能性があるため、ポインタに割り当てることを意味します。配列の場合、同等のCコードがコンパイルしないのと同じように、これはコンパイルすらすべきではないことに注意してください。それがコンパイルされ、動作するのは幸運な事故(別名コンパイラのバグ)です。

于 2013-01-12T00:23:56.207 に答える