Какой код C ++ компилирует инструкцию x86?
-
25-10-2019 - |
Вопрос
Я копирую элементы из одного массива другому в C ++. Я нашел rep movs
Инструкция в x86, которая, кажется, копирует массив в ESI в массиве EDI размера ECX. Однако ни for
ни while
петли, которые я попробовал собрать в rep movs
Инструкция в VS 2008 (на процессоре Intel Xeon X64). Как я могу написать код, который будет составлен в эту инструкцию?
Решение
Если вам нужна именно эта инструкция - используйте встроенный ассемблер и напишите эту инструкцию вручную. Вы не можете положиться на компилятор для создания какого -либо конкретного машинного кода - Даже если это излучает его в одном компиляции, он может принять решение издать какой -то другой эквивалент во время следующей компиляции.
Другие советы
Честно говоря, вы не должны. Rep - это своего рода устаревшее задержание в наборе инструкций, и на самом деле довольно медленное, поскольку он должен вызвать микрокодированную подпрограмму внутри процессора, который имеет задержку поиска ПЗУ и также не является неэпипленкой.
Почти в каждой реализации вы обнаружите, что memcpy()
Компилятор внутренний оба проще в использовании и работает быстрее.
Под MSVC есть __movsxxx
& __stosxxx
Внутренние, которые будут генерировать REP
Префиксированная инструкция.
Есть также «взлом», чтобы заставить внутренние memset
ака REP STOS
Под VC9+, поскольку внутренние больше не выходят, из -за разветвления SSE2 в ЭЛТ. это лучше, что __stosxxx
Из -за того, что компилятор может оптимизировать его для постоянных и правильно его заказать.
#define memset(mem,fill,size) memset((DWORD*)mem,((fill) << 24|(fill) << 16|(fill) << 8|(fill)),size)
__forceinline void memset(DWORD* pStart, unsigned long dwFill, size_t nSize)
{
//credits to Nepharius for finding this
DWORD* pLast = pStart + (nSize >> 2);
while(pStart < pLast)
*pStart++ = dwFill;
if((nSize &= 3) == 0)
return;
if(nSize == 3)
{
(((WORD*)pStart))[0] = WORD(dwFill);
(((BYTE*)pStart))[2] = BYTE(dwFill);
}
else if(nSize == 2)
(((WORD*)pStart))[0] = WORD(dwFill);
else
(((BYTE*)pStart))[0] = BYTE(dwFill);
}
конечно REP
не всегда лучшая вещь, которую можно использовать, им лучше использовать memcpy
, это будет ветвь в SSE2 или REPS MOV
На основе вашей системы (в соответствии с MSVC), если вы не чувствуете себя как написание пользовательской сборки для «горячих» областей ...
Повтодно и друзья были милыми, когда процессор x86 был промышленным промышленным процессором CISC с одной пийпели.
Но это изменилось. В настоящее время, когда процессор встречает Любые Инструкция, первое, что он делает,-это перевод его в более простой формат (vliw-подобные микроавтографии) и планирует его для будущего выполнения (это часть выполнения вне порядка, часть планирования между различными логическими ядрами ЦП, ИТ Может использоваться для упрощения записи-после записи последовательности в однопийные, et.c.). Этот механизм хорошо работает для инструкций, которые приводят к нескольким vliw-подобным Opcodes, но не в машинный код, который переводится в петли. Трансляционно-трансляционный код, вероятно, приведет к тому, что трубопровод выполнения остановится.
Вместо того, чтобы потратить сотни тысяч транзисторов в строительство ЦП-циркуитри для обработки петлевых участков микроволков в трубопроводе выполнения, они просто обрабатывают его в каком-то дерьмовом устаревшем режиме, который заикает трубопровод, и просят современных программ. Напишите свои чертовые петли!
Поэтому он редко используется, когда машины записывают код. Если вы столкнетесь с представителем в бинарном исполнении, это, вероятно, человеческая ассамблея, которая не знала лучше, или взломщик, который действительно нуждался в немногие байты, которые он сохранил, чтобы использовать его вместо реального цикла, который написал его.
(Однако. Возьмите все, что я только что написал, с зерном соли. Может быть, это больше не так. Я больше не на 100% в курсе внутренних процессов X86, я попал в другие хобби ..)
Я использую варианты префикса Rep* с CMPS*, MOVS*, SCAS* и STOS* Варианты инструкции для генерации встроенного кода, который минимизирует размер кода, избегает ненужных вызовов/прыжков и тем самым удерживать работу, выполняемые кехами. Альтернатива состоит в том, чтобы настроить параметры и вызвать мемсет или memcpy где-то еще, что в целом может быть быстрее, если я хочу скопировать сто байт или более в последний раз, когда я измерил).
Поскольку мой компилятор допускает спецификацию и использование встроенных функций сборки и включает в себя использование/модификацию их регистра в действиях оптимизации, я могу использовать их, когда обстоятельства являются правильными.
На историческом примечании - не имея никакого понимания стратегий производителя - было время, когда инструкции «Rep Movs*» (и т. Д.) Были очень медленными. Я думаю, что это было во время Pentium/Pentium MMX. Мой коллега (который имел больше понимания, чем я) сказал, что производители уменьшили область чипа (<=> меньше транзисторов/больше микрокода), выделенной на обработку повторения, и использовал ее для того, чтобы сделать другие, более использованные инструкции быстрее.
За пятнадцать лет или около того, так как представитель снова стал относительно быстрее, что предполагает больше транзисторов/меньшего микрокода.