6

私は SSE 命令に不慣れで、このサイトから学ぼうとしていました: http://www.codeproject.com/Articles/4522/Introduction-to-SSE-Programming

Intel Core i7 960 CPU を搭載した Ubuntu 10.10 で GCC コンパイラを使用しています。

これは、私が試みた記事に基づくコードです。

長さ ARRAY_SIZE の 2 つの配列について、計算します。

fResult[i] = sqrt( fSource1[i]*fSource1[i] + fSource2[i]*fSource2[i] ) + 0.5

ここにコードがあります

#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h>
#include <xmmintrin.h> // Contain the SSE compiler intrinsics
#include <malloc.h>
void myssefunction(
          float* pArray1,                   // [in] first source array
          float* pArray2,                   // [in] second source array
          float* pResult,                   // [out] result array
          int nSize)                        // [in] size of all arrays
{
    int nLoop = nSize/ 4;

    __m128 m1, m2, m3, m4;

    __m128* pSrc1 = (__m128*) pArray1;
    __m128* pSrc2 = (__m128*) pArray2;
    __m128* pDest = (__m128*) pResult;


    __m128 m0_5 = _mm_set_ps1(0.5f);        // m0_5[0, 1, 2, 3] = 0.5

    for ( int i = 0; i < nLoop; i++ )
    {
        m1 = _mm_mul_ps(*pSrc1, *pSrc1);        // m1 = *pSrc1 * *pSrc1
        m2 = _mm_mul_ps(*pSrc2, *pSrc2);        // m2 = *pSrc2 * *pSrc2
        m3 = _mm_add_ps(m1, m2);                // m3 = m1 + m2
        m4 = _mm_sqrt_ps(m3);                   // m4 = sqrt(m3)
        *pDest = _mm_add_ps(m4, m0_5);          // *pDest = m4 + 0.5

        pSrc1++;
        pSrc2++;
        pDest++;
    }
}

int main(int argc, char *argv[])
{
  int ARRAY_SIZE = atoi(argv[1]);
  float* m_fArray1 = (float*) _aligned_malloc(ARRAY_SIZE * sizeof(float), 16);
  float* m_fArray2 = (float*) _aligned_malloc(ARRAY_SIZE * sizeof(float), 16);
  float* m_fArray3 = (float*) _aligned_malloc(ARRAY_SIZE * sizeof(float), 16);

  for (int i = 0; i < ARRAY_SIZE; ++i)
    {
      m_fArray1[i] = ((float)rand())/RAND_MAX;
      m_fArray2[i] = ((float)rand())/RAND_MAX;
    }

  myssefunction(m_fArray1 , m_fArray2 , m_fArray3, ARRAY_SIZE);

  _aligned_free(m_fArray1);
   _aligned_free(m_fArray2);
   _aligned_free(m_fArray3);

  return 0;
}

次のコンパイルエラーが発生します

[Programming/SSE]$ g++ -g -Wall -msse sseintro.cpp 
sseintro.cpp: In function ‘int main(int, char**)’:
sseintro.cpp:41: error: ‘_aligned_malloc’ was not declared in this scope
sseintro.cpp:53: error: ‘_aligned_free’ was not declared in this scope
[Programming/SSE]$ 

私はどこを台無しにしていますか?いくつかのヘッダー ファイルがありませんか? 関連するものはすべて含まれているようです。

4

3 に答える 3

16

_aligned_malloc_aligned_freeはマイクロソフト主義です。Linuxなどでposix_memalignまたはmemalignを使用します。Mac OS X の場合は、常に 16 バイトにアラインされているため、malloc を使用できます。移植可能な SSE コードの場合、一般的に整列されたメモリ割り当て用のラッパー関数を実装する必要があります。

void * malloc_simd(const size_t size)
{
#if defined WIN32           // WIN32
    return _aligned_malloc(size, 16);
#elif defined __linux__     // Linux
    return memalign(16, size);
#elif defined __MACH__      // Mac OS X
    return malloc(size);
#else                       // other (use valloc for page-aligned memory)
    return valloc(size);
#endif
}

の実装はfree_simd、読者の課題として残されています。

于 2012-08-21T13:24:33.540 に答える
1

簡単な答え: and の代わりに_mm_mallocand _mm_freefromを使用します。xmmintrin.h_aligned_malloc_aligned_free

討論

SSE/AVX コードを記述するときは、、、 、またはその他のものを使用しないでください。これらはすべてコンパイラ/プラットフォーム固有の関数 (MSVC または GCC または POSIX) です。_aligned_malloc_aligned_freeposix_memalignmemalign

Intelは、SIMD 計算専用の関数_mm_mallocとIntel コンパイラを導入しました (これを参照してください)。x86 ターゲット アーキテクチャを備えた他のコンパイラもそれらを追加しました(Intel 組み込み関数を定期的に追加するのと同じように)。この意味で、これらは唯一のクロスプラットフォーム ソリューションです。SSE をサポートするすべてのコンパイラで利用できるはずです。_mm_free

これらの関数はxmmintrin.hヘッダーで宣言されています。新しい SSE/AVX バージョンのヘッダーには、以前のヘッダーが自動的に含まれるため、たとえば、smmintrin.hまたはのみを含めるだけで十分です。emmintrin.h

于 2015-09-12T12:20:37.020 に答える
0

これはあなたの質問に直接答えるものではありませんが、あなたのSSEコードが間違って書かれていることを指摘したいと思います。それが機能するなら、私は驚きます。整列されたfloat配列のような整列された非sseタイプを含む非sseタイプでロード/ストア操作を使用する必要があります(SSEタイプの動的配列がある場合でもこれを行う必要があります)。SSEを使用している場合、SSEデータ型はSSEレジスタ内のデータを表すと想定されており、他のすべてのものは通常、システムメモリまたは非SSEレジスタにあるため、 /レジスタとメモリ。関数は次のようになります。

void myssefunction
(
    float* pArray1,                   // [in] first source array
    float* pArray2,                   // [in] second source array
    float* pResult,                   // [out] result array
    int nSize                         // [in] size of all arrays
)                                   
{
    const __m128 m0_5 = _mm_set_ps1(0.5f);        // m0_5[0, 1, 2, 3] = 0.5
    for (size_t index = 0; index < nSize; index += 4)
    {
        __m128 pSrc1 = _mm_load_ps(pArray1 + index); // load 4 elements from memory into SSE register
        __m128 pSrc2 = _mm_load_ps(pArray2 + index); // load 4 elements from memory into SSE register

        __m128 m1   = _mm_mul_ps(pSrc1, pSrc1);        // m1 = *pSrc1 * *pSrc1
        __m128 m2   = _mm_mul_ps(pSrc2, pSrc2);        // m2 = *pSrc2 * *pSrc2
        __m128 m3   = _mm_add_ps(m1, m2);                // m3 = m1 + m2
        __m128 m4   = _mm_sqrt_ps(m3);                   // m4 = sqrt(m3)
        __m128 pDest  = _mm_add_ps(m4, m0_5);          // pDest = m4 + 0.5

        _mm_store_ps(pResult + index, pDest); // store 4 elements from SSE register to memory.
    }
}

また、特定の時間に使用できるレジスタの数には制限があることに注意してください(SSE2の場合は16など)。制限を超えて使用しようとするコードを記述できますが、これによりレジスタがスピルします。

于 2012-08-22T08:23:55.370 に答える