-1

昨日これに遭遇しました。MSVC12 (VS2013, 120)およびMSVC14 (VS2015, 140)で失敗する明確で単純な例を挙げようとします。x64 ではすべてが暗黙的に /arch:SSE+ です。

説明のために、定義されたマクロ _MM_TRANSPOSE4_PS を使用して、この問題を単純な行列転置の例に単純化します。これは、L/H 8 バイト ブロックを移動するのではなく、シャッフルの観点から実装されています。

float4x4 Transpose(const float4x4& m) {

    matrix4x4 n = LoadMatrix(m);
    _MM_TRANSPOSE4_PS(n.row[0], n.row[1], n.row[2], n.row[3]);
    return StoreMatrix(n);

}

これmatrix4x4は、4 つのメンバーを含む単なる POD 構造体__m128であり、多少暗黙的ではありますが、すべてが 16 バイト境界に整然と配置されています。

__declspec(align(16)) struct matrix4x4 {

    __m128 row[4];

};

これはすべて、/O1、/O2、および /Ox で失敗します。

// Doesn't work.
float4x4 resultsPlx = Transpose( GiveMeATemporary() );

// Changing Transpose to take float4x4, or copy a temporary
float4x4 Transpose(float4x4 m) { ... }

// Trying again, doesn't work.
float4x4 resultsPlx = Transpose( GiveMeATemporary() );

不思議なことに、これは機能します:

// A constant reference to an rvalue, a temporary
const float4x4& temporary = GiveMeATemporary();
float4x4 resultsPlx = Transpose(temporary);

ポインターベースの転送についても同じことが言えます。これは、基になるメカニズムが同じであるため論理的です。C++11 仕様の関連部分は §12.2/5 です。

2 番目のコンテキストは、参照がテンポラリにバインドされる場合です。参照がバインドされている一時オブジェクト、または一時オブジェクトがバインドされているサブオブジェクトへの完全なオブジェクトである一時オブジェクトは、以下に指定されている場合を除き、参照の存続期間中存続します。コンストラクターの ctor-initializer (§12.6.2 [class.base.init]) 内の参照メンバーへの一時的なバインドは、コンストラクターが終了するまで持続します。関数呼び出し (§5.2.2 [expr.call]) の参照パラメーターへの一時的なバインドは、呼び出しを含む完全な式が完了するまで持続します。

これは、呼び出し環境が範囲外になるまで存続する必要があることを意味します。これは、関数が戻った後です。それで、何が得られますか?他のすべての場合、次の例外を除いて、変数は「最適化されずに」取得されます。

Access violation reading location 0xFFFFFFFFFFFFFFFF

解決策は明らかですが、ユーザーが他のライブラリのようにポインターベースの転送で一時ファイルを直接渡さないようにします。ビューを詰まらせずに、実際にはもう少しエレガントにすることを望んでいました.

4

1 に答える 1

0

レイアウトに実際に影響を与えることなく、(非仮想) メンバー関数を構造体に追加できます。したがって、構造体が破棄されたときに「I'm here %p」を出力するデストラクタを追加し、関数で「I'm there」を出力します。(他の一時コピーが使用されていることを理解できるように、このアドレスを含めてください)。

次に、最適化されたコードで寿命を観察できます。それがあなたの問題であるかどうかを確認してください。スタックフレームの有効なアドレスであるため、ライフタイムが悪いと実際に何かを意味するのではないかと思います。

さらに、浮動小数点数が存在するはずのビットを変更すると、最悪の場合、非数または特別な値が得られる可能性があり、その場合、ベクトル処理はスローまたはフォールトしませんが、その悪い結果としてフラグ値を設定しますエレメント。 ポインターがないのに、なぜ -1 を逆参照するのでしょうか?

失火はもっと面白いことが原因だと思います。

デバッガーで実行し、どの命令が原因かを確認します。

于 2015-03-07T08:49:42.870 に答える