Я заметил, что иногда MSVC 2010 не изменяет порядок инструкций SSE. Я думал, что мне не нужно заботиться о порядке инструкций внутри моего цикла, поскольку компилятор справляется с этим лучше всего, что, похоже, не так.
Как я должен думать об этом? Что определяет лучший порядок инструкций? Я знаю, что некоторые инструкции имеют более высокую задержку, чем другие, и что некоторые инструкции могут выполняться параллельно/асинхронно на уровне процессора. Какие показатели важны в контексте? Где я могу их найти?
Я знаю, что я мог избежать этого вопроса путем профилирования, однако такие профилировщики дороги (VTune XE) и Я хотел бы знать теорию, лежащую в ее основе, а не только эмпирические результаты.
Также мне следует заботиться о предварительной выборке программного обеспечения (_mm_prefetch
) или я могу предположить, что процессор будет работать лучше, чем я?
Допустим, у меня есть следующая функция. Должен ли я чередовать некоторые инструкции? Должен ли я делать магазины перед потоками, делать все нагрузки в порядке, а затем выполнять вычисления и т.д.?? Нужно ли мне рассматривать USWC против не-USWC, а также временные и невременные?
auto cur128 = reinterpret_cast<__m128i*>(cur);
auto prev128 = reinterpret_cast<const __m128i*>(prev);
auto dest128 = reinterpret_cast<__m128i*>(dest;
auto end = cur128 + count/16;
while(cur128 != end)
{
auto xmm0 = _mm_add_epi8(_mm_load_si128(cur128+0), _mm_load_si128(prev128+0));
auto xmm1 = _mm_add_epi8(_mm_load_si128(cur128+1), _mm_load_si128(prev128+1));
auto xmm2 = _mm_add_epi8(_mm_load_si128(cur128+2), _mm_load_si128(prev128+2));
auto xmm3 = _mm_add_epi8(_mm_load_si128(cur128+3), _mm_load_si128(prev128+3));
// dest128 is USWC memory
_mm_stream_si128(dest128+0, xmm0);
_mm_stream_si128(dest128+1, xmm1);
_mm_stream_si128(dest128+2, xmm2);;
_mm_stream_si128(dest128+3, xmm3);
// cur128 is temporal, and will be used next time, which is why I choose store over stream
_mm_store_si128 (cur128+0, xmm0);
_mm_store_si128 (cur128+1, xmm1);
_mm_store_si128 (cur128+2, xmm2);
_mm_store_si128 (cur128+3, xmm3);
cur128 += 4;
dest128 += 4;
prev128 += 4;
}
std::swap(cur, prev);