Vulpo
Vulpo

Reputation: 893

sse segfault on _mm_load_si128

I have a segmentation fault when I try to use _mm_load_si128 in C for intrinsics. I saw that the data must be 16-bits aligned, and that a union does this correctly. But this does not resolve my problem.

#include <xmmintrin.h>

int main(void){
    const int N = 8;
    short int  matrice1[] = {
        10, 11, 12, 13, 14, 15, 16, 17,
        20, 21, 22, 23, 24, 25, 26, 27,
        30, 31, 32, 33, 34, 35, 36, 37,
        40, 41, 42, 43, 44, 45, 46, 47,
        50, 51, 52, 53, 54, 55, 56, 57,
        60, 61, 62, 63, 64, 65, 66, 67,
        70, 71, 72, 73, 74, 75, 76, 77,
        80, 81, 82, 83, 84, 85, 86, 87
    };

    transpose_simd(matrice1, N);

 return 0;
}

union Line{
    short int* row;
    __m128i sRow;
};

void transpose_simd(short int * matrice1, int N){
    short int i, n, j;

    union Line line1, line2; //matrix line

    __m128i sLine1, sLine2; //sse version of the matrix line
    __m128i sLine3, sLine4;

    /*
    There will be a loop surrounding the following code, but first I kept it simple
    */
            // THE NEXT LINE GIVES A SEGMENTATION FAULT
            sLine1 = _mm_load_si128((__m128i*) line1.row); //loads 1 matrix line (8 shorts of 16 bits = 128)
            sLine2 = _mm_load_si128((__m128i*) line2.row);

            sLine3 = _mm_unpackhi_epi16 ( sLine1, sLine2 ); //shuffle the first 4 elements
            sLine4 = _mm_unpackhi_epi16 ( sLine1, sLine2 ); //shuffle the last 4 elements

            _mm_store_si128((__m128i*)line1.row, sLine3);
            _mm_store_si128((__m128i*)line2.row, sLine4);
}

So I got the solution from the answers. It is working fine after implementing correctly the two loops:

void transpose_simd(short int * matrice1, short int* matrice2, int N){
    short int i=0, n=0;

    short int* __attribute__ ((aligned (16))) line1; //ligne de matrice
    short int* __attribute__ ((aligned (16))) line2;

    __m128i sLine1, sLine2; //ligne en version sse
    __m128i sLine3, sLine4;

    /*
    There will be a loop surrounding the following code, but first I kept it simple
    */

            line1 = matrice1 + N*i;
            line2 = matrice1 + N*(N/2 + i);

            sLine1 = _mm_loadu_si128((__m128i*) line1); //charge 1 ligne (8 nombres de 16 bits = 128, "coup de bol")
            sLine2 = _mm_loadu_si128((__m128i*) line2);

            sLine3 = _mm_unpacklo_epi16 ( sLine1, sLine2 ); //shuffle les 4 premiers chiffres de line1, voir p74
            sLine4 = _mm_unpackhi_epi16 ( sLine1, sLine2 ); //shuffle les 4 premiers chiffres de line1, voir p74

            _mm_storeu_si128((__m128i*) (matrice2 + N*2*i), sLine3);
            _mm_storeu_si128((__m128i*) (matrice2 + N*(2*i+1)), sLine4);

}

Basically, __attribute__ ((aligned (16))) aligns my variables, as the union keeps the offset but does not set the alignment. Also, for more security, the unaligned-compatible functions _mm_storeu_si128 and _mm_loadu_si128 are used. However, I don't know if it's slowler than the alignment-dependent version of these methods.

Upvotes: 3

Views: 2955

Answers (1)

Vikram Dattu
Vikram Dattu

Reputation: 881

Yes you are right, your data is unaligned and the intrinsic you are using is for aligned data access.

Use _mm_loadu_si128 instead of _mm_load_si128 or align the array to 16 bytes using align attribute.

P.S.:You should be careful while using aligned load/stores. Union won't align the data. You need to explicitly do that with align attribute.

Upvotes: 6

Related Questions