Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Битовая операция над 128-битным числом


Автор: ksili 6.5.2009, 11:50
Решил освоить возможности SSE (2/3). В частности, работу со 128-битными целыми числами. И наткнулся на вот такую проблему. 
Есть массив 128-битных чисел (тип _m128i). Есть 128-битная маска, такого же типа. Вот такой код компилируется:
Код

__declspec(align(64)) __m128i *arr_128;
unsigned int K;
__m128i mask128;

....

arr_128 = new __m128i[K];

for(i = 0; i< K; i++)
{
   ....  // здесь готовим маску

   arr_128[i] = _mm_or_si128(arr_128[i], mask128);          // OR двух 128-разрядных чисел
}


Однако при выполнении на первой же команде  _mm_or_si128 происходит исключение
Цитата

Access violation reading location 0xffffffff

Память под массив перед этим выделяется нормально. В чём проблема не понятно. К тому же нашёл у Агнера Фога очень похожий код 
Код

a = _mm_or_si128(a, mask); 

который видимо является рабочим.

Автор: nickless 7.5.2009, 19:27
А если так (задекларировать указатель выровненым на 16 байт ИМХО не достаточно)?
Код

#include <cstdlib>
#include <malloc.h>
#include <emmintrin.h>

void *operator new(size_t aSize) {
#ifdef _WIN32
    return _aligned_malloc(aSize, 16);
#else
    void *ret;
    posix_memalign((void**)&ret, 16, aSize);
    return ret;
#endif
}

void operator delete( void * aData) {
#ifdef _WIN32
    _aligned_free(aData);
#else
    free(aData);
#endif
}

int main() {
    const int K = 8;
    __m128i mask128 = _mm_set_epi32(0x11111111, 0xffffffff, 0x00000008, 0x00000004);
    __m128i * arr_128 = new __m128i[K];

    for(int i = 0; i< K; i++) {
        arr_128[i] = _mm_set1_epi32(i);
    }

    for(int i = 0; i< K; i++) {
        arr_128[i] = _mm_or_si128(arr_128[i], mask128);
    }

    delete[] arr_128;
    return 0;
}

Автор: ksili 8.5.2009, 06:48
nickless, не вижу принципиальных отличий. Проблема была почему-то с чтением из массива типа  __m128i, когда он был в качестве аргумента какой-нибудь SSE-шной функции, как _mm_or_si128 в примере. Я сейчас уже сделал так, что работаю с двумя 64-битными  переменными (__int64 qwords[2]), а потом пишу их в arr_128[i] командой memcpy. Хотел было вместо memcpy копировать командой  _mm_set_epi64x, но оказалось, что она из SSE3, а мой проц его не поддерживает - illegal instruction.

С выравниванием на 64 байта я конечно загнул, спасибо, что поправили.

Автор: nickless 8.5.2009, 21:01
Цитата(ksili @  8.5.2009,  05:48 Найти цитируемый пост)
nickless, не вижу принципиальных отличий

Насколько я понимаю, __align указывает выравнивание только самой переменной, т.е. указателя arr_128, а тебе надо чтобы память выделенная new была выравнена на 16 байт, иначе будет access violation. Посмотри на значение arr_128 % 16 и всё станет ясно.

Добавлено через 21 секунду
ЗЫ. В http://msdn.microsoft.com/en-us/library/83ythb65(VS.80).aspx об этом кстати тоже написано.

Добавлено через 2 минуты и 23 секунды
ksili, ты кстати мой код пробовал? У меня на линуксе он работает нормально.

Автор: ksili 12.5.2009, 05:02
nickless, спасибо. Благодаря вашим комментариям, вопрос решён.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)