Как выполнить косвенную нагрузку (собирать-разброс) в инструкциях AVX или SSE?
Я искал какое-то время, но не могу найти ничего полезного в документации или на SO. Этот вопрос действительно не помог мне, так как он делает ссылки на изменение сборки, и я пишу на C.
У меня есть код, делающий косвенный доступ, который я хочу векторизовать.
for (i = 0; i < LENGTH; ++i) {
foo[bar[i]] *= 2;
}
Поскольку у меня есть индексы, которые я хочу удвоить внутри bar
, мне было интересно, есть ли способ загрузить эти индексы foo
в векторный регистр, а затем я мог бы применить свою математику и сохранить ее обратно к тем же индексам.
Что-то вроде следующего. Инструкции по load
и store
я только что составил, потому что я не мог найти ничего подобного в документации AVX или SSE. Я думаю, что я где-то читал, что AVX2 имеет схожие функции, но процессор, с которым я работаю, не поддерживает AVX2.
for (i = 0; i < LENGTH; i += 8) {
// For simplicity, I'm leaving out any pointer type casting
__m256 ymm0 = _mm256_load_indirect(bar+i);
__m256 ymm1 = _mm256_set1_epi32(2); // Set up vector of just 2's
__m256 ymm2 = _mm256_mul_ps(ymm0, ymm1);
_mm256_store_indirect(ymm2, bar+i);
}
Существуют ли какие-либо инструкции в AVX или SSE, которые позволят мне загрузить векторный регистр с массивом индексов из другого массива? Или любые "хакерские" способы обойти его, если нет явной функции?
Ответы
Ответ 1
(Я пишу ответ на этот старый вопрос, так как думаю, что он может помочь другим.)
Короткий ответ
Нет. В наборах команд SSE и AVX нет инструкций разброса/сбора.
Более длинный ответ
Команды разброса/сбора данных являются дорогостоящими для реализации (с точки зрения сложности и степени использования кремния), потому что механизм разброса/сбора должен быть тесно переплетен с контроллером кэш-памяти. Я считаю, что это причина того, что эта функциональность отсутствовала в SSE/AVX.
Для более новых наборов инструкций ситуация иная. В AVX2 у вас есть
- VGATHERDPD, VGATHERDPS, VGATHERQPD, VGATHERQPS для сбора с плавающей запятой (здесьвстроено)
- VPGATHERDD, VPGATHERQD, VPGATHERDQ, VPGATHERQQ для целочисленной сборки (здесьвстроено)
В AVX-512 мы получили
- VSCATTERDPD, VSCATTERDPS, VSCATTERQPD, VSCATTERQPS для рассеяния с плавающей запятой
(встроенные здесь)
- VPSCATTERDD, VPSCATTERQD, VPSCATTERDQ, VPSCATTERQQ для целочисленного рассеяния (здесьвстроено)
Тем не менее, все еще остается вопрос, будет ли использование scatter/collect для такой простой операции окупиться.