field initializer is not constant



  • #include <immintrin.h>
    
    struct Test
    {
        static constexpr  __m128i memberVar = _mm_set1_epi16(12);
    };
    
    int main()
    {
        return 0;
    }
    {
    

    Bei meiner memberVar beschwert sich g++: "error field initializer is not constant". Mit einfach Datentypen (int,.. ) funktioniert es. Wie kriege ich das mit __m128i hin?



  • Ich würde mal vermuten. das die Funktion _mm_set1_epi16 nicht constexpr ist. Was ist überhaupt ein __m128i?



  • Ein Vektorregister (MMX & Co.) mit insgesamt 128 Bit.



  • hustbaer schrieb:

    Ein Vektorregister (MMX & Co.) mit insgesamt 128 Bit.

    Wenn das Compiler-Intrinsic ist, ist natürlich schwer zu beantworten. Da müsste man in die Compiler-Doku schauen. Hast du mal versucht, einen constexpr __m128i mit einer Konstanten zu initialisieren? Versuch das mal um den Fehler weiter einzugrenzen.



  • Die SIMD-Typen wie __m128i sind soweit ich weiss Compiler-spezifische typedefs, wie z.B. typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__)) in GCC oder
    typedef union __declspec(intrin_type) __declspec(align(16)) {char c[16];} __m128i in Visual C.
    Wenn du diese statisch als constexpr initialisieren möchtest, wirst du diese Variablen wohl mit einem Ausdruck initialisieren müssen, der für den entsprechenden Compiler passt, also z.B. { 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12, 0, 12 } in Visual C.
    Das ist allerdings nicht sehr portabel und nicht gerade bequem wenn man wie du 16bit-Integer in die SIMD-Variable schrieben möchte.

    Ich würde daher eher so etwas hier vorschlagen:

    struct Test
    {
        alignas(16) static constexpr std::int16_t memberVar[8] = { 12, 12, 12, 12, 12, 12, 12, 12 };
    };
    
    alignas(16) constexpr std::int16_t Test::memberVar[8];
    

    Damit machst du dann alles zur Compile-Zeit weswegen du überhaupt in erster Linie die constexpr benötigst. Sobald du dann anfängst mit den Werten tatsächlich in einem SIMD-Register zu rechnen, lädst diese dann aus dem Speicher:

    __m128i r1 = _mm_load_si128(reinterpret_cast<const __m128i*>(Test::memberVar));
    

    ich weiss nicht ob das das eleganteste Weg ist, aber diesen würde ich persönlich einschlagen, wenn die Werte, mit denen die SIMD-Variablen initialisiert werden, undbedingt ein constexpr-Ausruck sein müssen.

    Gruss,
    Finnegan


Anmelden zum Antworten