28

組み込み関数を使用してコーディングすることを学ぼうとしていますが、以下は加算を行うコードです

compiler used: icc

#include<stdio.h>
#include<emmintrin.h>
int main()
{
        __m128i a = _mm_set_epi32(1,2,3,4);
        __m128i b = _mm_set_epi32(1,2,3,4);
        __m128i c;
        c = _mm_add_epi32(a,b);
        printf("%d\n",c[2]);
        return 0;
}

以下のエラーが表示されます。

test.c(9): error: expression must have pointer-to-object type
        printf("%d\n",c[2]);

cタイプの変数の値を出力するにはどうすればよいですか__m128i

4

4 に答える 4

26

これらを印刷するには、次の関数を使用します。

#include <stdint.h>
#include <string.h>

void print128_num(__m128i var)
{
    uint16_t val[8];
    memcpy(val, &var, sizeof(val));
    printf("Numerical: %i %i %i %i %i %i %i %i \n", 
           val[0], val[1], val[2], val[3], val[4], val[5], 
           val[6], val[7]);
}

印刷する前に、128ビットを16ビット(または32ビット)に分割します。

これは、64ビットのサポートを利用できる場合の64ビットの分割と印刷の方法です。

#include <inttypes.h>

void print128_num(__m128i var) 
{
    int64_t v64val[2];
    memcpy(v64val, &var, sizeof(v64val));
    printf("%.16llx %.16llx\n", v64val[1], v64val[0]);
}

注:またはに&var直接キャストするとMSVCも機能しますが、これは厳密なエイリアシングに違反し、未定義の動作です。を使用することは、同じことを行うための標準準拠の方法であり、最小限の最適化で、コンパイラーはまったく同じバイナリコードを生成します。int*uint16_t*memcpy

于 2012-11-06T18:42:48.537 に答える
18
  • gcc/clang/ICC/MSVC、C、C++ で移植可能。
  • すべての最適化レベルで完全に安全: 厳格なエイリアス違反なし UB
  • u8、u16、u32、または u64 要素として 16 進数で出力します ( @AG1 の回答に基づく)
  • メモリ順に出力します ( のように、最下位の要素が最初になり_mm_setr_epiXます)。最も重要な要素が左側にあるインテルのマニュアルと同じ順序で印刷したい場合は、配列インデックスを逆にします ( など_mm_set_epiX)。関連:ベクトル レジスタの表示規則

a を使用し__m128i*ての配列からロードするintことは安全です。これは、__m128型が ISO C と同様にエイリアシングを許可するように定義されているためunsigned char*です。(たとえば、gcc のヘッダーでは、定義に が含まれ__attribute__((may_alias))ます。)

は安全ではありません(オブジェクトint*の一部を指す)。__m128iMSVC は安全であることを保証しますが、GCC/clang は保証しません。(-fstrict-aliasingはデフォルトでオンになっています)。GCC/clang で動作することもありますが、なぜそれを危険にさらすのでしょうか? 最適化を妨げることさえあります。この Q&Aを参照してください。ハードウェア SIMD ベクトル ポインターと対応する型の間の「reinterpret_cast」は未定義の動作ですか?も参照してください。

(uint32_t*) &my_vectorC および C++ のエイリアシング規則に違反しており、期待どおりに動作することは保証されていません。ローカル配列に格納してからアクセスすることは、安全であることが保証されています。ほとんどのコンパイラで最適化が行われないため、たとえば、実際のストア/リロードではなく、xmm から整数レジスタにmovq/を直接取得します。pextrq

Godbolt コンパイラ エクスプローラでのソース + asm 出力: MSVC などでコンパイルされていることの証明。

#include <immintrin.h>
#include <stdint.h>
#include <stdio.h>

#ifndef __cplusplus
#include <stdalign.h>   // C11 defines _Alignas().  This header defines alignas()
#endif

void p128_hex_u8(__m128i in) {
    alignas(16) uint8_t v[16];
    _mm_store_si128((__m128i*)v, in);
    printf("v16_u8: %x %x %x %x | %x %x %x %x | %x %x %x %x | %x %x %x %x\n",
           v[0], v[1],  v[2],  v[3],  v[4],  v[5],  v[6],  v[7],
           v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]);
}

void p128_hex_u16(__m128i in) {
    alignas(16) uint16_t v[8];
    _mm_store_si128((__m128i*)v, in);
    printf("v8_u16: %x %x %x %x,  %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
}

void p128_hex_u32(__m128i in) {
    alignas(16) uint32_t v[4];
    _mm_store_si128((__m128i*)v, in);
    printf("v4_u32: %x %x %x %x\n", v[0], v[1], v[2], v[3]);
}

void p128_hex_u64(__m128i in) {
    alignas(16) unsigned long long v[2];  // uint64_t might give format-string warnings with %llx; it's just long in some ABIs
    _mm_store_si128((__m128i*)v, in);
    printf("v2_u64: %llx %llx\n", v[0], v[1]);
}

C99 または C++03 以前 (つまり、C11 / C++11 なし) への移植性が必要な場合は、 を削除して代わりにalignas()使用します。または代わりにor を使用します。storeustore__attribute__((aligned(16)))__declspec( align(16) )

-std=gnu++03(組み込み関数を使用してコードを記述している場合は、最新のコンパイラ バージョンを使用する必要があります。通常、新しいコンパイラは、SSE/AVX 組み込み関数を含め、古いコンパイラよりも優れた asm を作成します。しかし、 C++03で gcc-6.3 を使用したい場合があります。C++11 などの準備ができていないコードベースのモードです。)


で 4 つの関数すべてを呼び出した場合の出力例

// source used:
__m128i vec = _mm_setr_epi8(1, 2, 3, 4, 5, 6, 7,
                            8, 9, 10, 11, 12, 13, 14, 15, 16);

// output:

v2_u64: 0x807060504030201 0x100f0e0d0c0b0a09
v4_u32: 0x4030201 0x8070605 0xc0b0a09 0x100f0e0d
v8_u16: 0x201 0x403 0x605 0x807  | 0xa09 0xc0b 0xe0d 0x100f
v16_u8: 0x1 0x2 0x3 0x4 | 0x5 0x6 0x7 0x8 | 0x9 0xa 0xb 0xc | 0xd 0xe 0xf 0x10

出力幅を一定にするために先行ゼロを埋め込む場合は、フォーマット文字列を調整します。を参照してくださいprintf(3)

于 2017-10-15T07:01:02.657 に答える
2
#include<stdio.h>
#include<emmintrin.h>
int main()
{
    __m128i a = _mm_set_epi32(1,2,3,4);
    __m128i b = _mm_set_epi32(1,2,3,4);
    __m128i c;

    const int32_t* q; 
    //add a pointer 
    c = _mm_add_epi32(a,b);

    q = (const int32_t*) &c;
    printf("%d\n",q[2]);
    //printf("%d\n",c[2]);
    return 0;
}

このコードを試してください。

于 2013-12-25T01:57:20.430 に答える