#c #c #sse
#c #c #sse
Вопрос:
На C или C как бы вы написали код для добавления без знака двух массивов, которые, вероятно, будут оптимизированы, скажем, GCC, в одну 128-битную инструкцию добавления SSE без знака?
Комментарии:
1. Какого размера элементы массива? 8 бит, 16 бит, 32 бит, 64 бит?
2. Просто добавьте соответствующие флаги в gcc, чтобы он знал, что может использовать оптимизацию SSE. Это в основном означает добавление флагов для указания целевого оборудования, на котором будет выполняться приложение.
3. 1 за вопрос, как написать чистый код и позволить оптимизатору делать свое дело, а не использовать ASM / встроенные хаки, специфичные для ISA.
Ответ №1:
// N number of ints to be added
// a, b input array
// c sum array
// nReg number of required vector registers
const unsigned nReg = N*sizeof(uint32_t)/sizeof(__v4si);
__v4si a[nReg], b[nReg], c[nReg];
for (unsigned i=0; i<nReg; i)
c[i] = _mm_add_epi32(a[i], b[i]);
// in c simply
for (unsigned i=0; i<nReg; i)
c[i] = a[i] b[i];
Разворачивайте цикл и выполняйте предварительную выборку элементов по вашему желанию. Рекомендуется профилирование. Замените __v4si __v16qi, __v8hi, __v2di для 8, 16, 64-битных целых чисел.
Комментарии:
1. Вероятно, потому, что OP спросил, как написать C или C-код, который будет оптимизирован компилятором для использования SSE, а не как написать какие-то уродливые встроенные функции, специфичные для конкретной машины.
2. В примере c не используются встроенные функции
3. Деление на
sizeof(uint32_t)
(что является действительно уродливым способом написания 4 …), вероятно, не относится к версии C …4. На самом деле в более ранней версии было 4, я отредактировал его, чтобы было ясно, откуда оно взялось. Но дело в том, будет ли ваш компилятор векторизировать цикл, зависит от точной версии, флагов (-ftree-vectorize) и текущего состояния вашего процессора 🙂 Вы можете использовать -ftree-vectorizer-verbose = 2, чтобы получить некоторую помощь, как я писал в другом ответе, но единственный способ убедиться, что ваш компилятор действительно использует SSE, — это использовать встроенные или, в случае c , векторные типы, которые для большинства логических и арифметических операторов сопоставляются с эквивалентными встроенными
5. Почему
N
должно быть количество байтов, а не количество элементов?
Ответ №2:
for (i=0; i<N; i ) c[i] = a[i] b[i];
Комментарии:
1. Я не отрицал вас, но один вопрос: вы действительно когда-нибудь писали какой-то код, который нужно было выполнять в SSE?
2. Да, и я написал это в asm. Однако вопрос OP заключается не в том, как написать код SSE, а скорее в том, как написать C или C код, который оптимизатор компилятора может легко векторизовать. И лучший способ сделать это — сделать код как можно более простым.
3. Есть промежуточный вариант: используйте встроенные компоненты (которые напрямую сопоставляются с инструкциями asm) и позвольте компилятору выполнять планирование ввода. Особенно в коде, который содержит невекторный код и смешанный векторный код, это может дать превосходные результаты. Большие блоки SSE лучше выполнять в asm, я согласен.
4. Я обычно считаю, что встроенные функции хуже. Они зависят не только от ISA, но и от компилятора. Но вы правы насчет потенциальных преимуществ.
5. @R.: Встроенные функции не зависят от компилятора. Они определены Intel, реализованы в их компиляторе C
icc
и реализованы идентичноgcc
,clang
MSVC, … — лично я чувствую, что это делает их превосходящими встроенный asm.