2

以下は、タグ付けされた共用体テンプレート「Storage」のダウンストリップされた例です。これは、共用体で囲まれた 2 つの型 L と R と、それらのどちらが格納されているかを示す bool を想定できます。インスタンス化では 2 つの異なるサイズの型が使用され、小さい方は実際には空です。

#include <utility>

struct Empty
{
};

struct Big
{
        long a;
        long b;
        long c;
};

template<typename L, typename R>
class Storage final
{
public:
        constexpr explicit Storage(const R& right) : payload{right}, isLeft{false}
        {
        }

private:
        union Payload
        {
                constexpr Payload(const R& right) : right{right}
                {
                }
                L left;
                R right;
        };

        Payload payload;
        bool isLeft;
};

// Toggle constexpr here
constexpr static Storage<Big, Empty> createStorage()
{
        return Storage<Big, Empty>{Empty{}};
}

Storage<Big, Empty> createStorage2()
{        
        return createStorage();
}
  • コンストラクターはRメンバーをEmptyで初期化し、そのメンバーのユニオンのコンストラクターのみを呼び出しています
  • ユニオン全体がデフォルトで初期化されることはありません
  • すべてのコンストラクターは constexpr です

そのため、関数「createStorage2」は bool タグのみを設定し、union はそのままにしておく必要があります。したがって、デフォルトの最適化「-O」でコンパイル結果が期待されます。

createStorage2():
        mov     rax, rdi
        mov     BYTE PTR [rdi+24], 0
        ret

代わりに GCC と ICC の両方が次のようなものを生成します

createStorage2():
        mov     rax, rdi
        mov     QWORD PTR [rdi], 0
        mov     QWORD PTR [rdi+8], 0
        mov     QWORD PTR [rdi+16], 0
        mov     QWORD PTR [rdi+24], 0
        ret

32 バイト構造全体をゼロにし、clang は予想されるコードを生成します。これはhttps://godbolt.org/z/VsDQUuで再現できます。「createStorage」静的関数からconstexprを削除すると、GCCはboolタグのみの目的の初期化に戻りますが、ICCは感銘を受けず、32バイトすべてを埋めます。

未使用のビットが「未定義」であると、ゼロに設定されて不要な CPU サイクルが消費されるなど、何でも許可されるため、これはおそらく標準的な違反ではありません。しかし、最初に効率上の理由から組合を導入し、組合員の規模が大きく異なる場合は面倒です。

ここで何が起こっているのですか?constexpr をコンストラクターから削除し、静的関数を使用できない場合、この動作を回避する方法はありますか?

補足: https://godbolt.org/z/FnjoPCのように、すべての constexpr が削除された場合でも、ICC はいくつかの追加操作を実行するようです。

createStorage2():
        mov       rax, rdi                                      #44.16
        mov       BYTE PTR [-16+rsp], 0                         #39.9
        movups    xmm0, XMMWORD PTR [-40+rsp]                   #44.16
        movups    xmm1, XMMWORD PTR [-24+rsp]                   #44.16
        movups    XMMWORD PTR [rdi], xmm0                       #44.16
        movups    XMMWORD PTR [16+rdi], xmm1                    #44.16
        ret                                                     #44.16

これらのmovups命令の目的は何ですか?

4

1 に答える 1