Вопрос

Я копирую элементы из одного массива другому в 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. Мой коллега (который имел больше понимания, чем я) сказал, что производители уменьшили область чипа (<=> меньше транзисторов/больше микрокода), выделенной на обработку повторения, и использовал ее для того, чтобы сделать другие, более использованные инструкции быстрее.

За пятнадцать лет или около того, так как представитель снова стал относительно быстрее, что предполагает больше транзисторов/меньшего микрокода.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top