Какой код C ++ компилируется в инструкцию x86 REP? - PullRequest
5 голосов
/ 27 января 2011

Я копирую элементы из одного массива в другой в C ++.Я нашел инструкцию rep movs в x86, которая, кажется, копирует массив в ESI в массив в EDI размера ECX.Однако ни циклы for, ни while, которые я пробовал, скомпилированы в инструкцию rep movs в VS 2008 (на процессоре Intel Xeon x64).Как я могу написать код, который будет скомпилирован в эту инструкцию?

Ответы [ 6 ]

11 голосов
/ 27 января 2011

Честно говоря, вы не должны. REP - это своего рода устаревшее удержание в наборе команд, и на самом деле оно довольно медленное, поскольку ему приходится вызывать микрокодированную подпрограмму внутри ЦП, которая имеет задержку поиска в ПЗУ и также не имеет конвейера.

Практически в каждой реализации вы обнаружите, что встроенный компилятор memcpy() проще в использовании и работает быстрее.

5 голосов
/ 27 января 2011

В MSVC есть __movsxxx & __stosxxx, которые генерируют инструкцию с префиксом REP.

есть также «взлом» для принудительной установки встроенного memset aka REP STOS в vc9 +, так как встроенное больше не выходит из-за ветвления sse2 в crt. это лучше, чем __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), если только вы чувствуешь, что пишешь нестандартную сборку для «горячих» областей ...

3 голосов
/ 27 января 2011

Если вам нужна именно эта инструкция - используйте встроенный ассемблер и напишите эту инструкцию вручную. Вы не можете полагаться на то, что компилятор выдаст какой-либо конкретный машинный код - даже если он выдает его в одной компиляции, он может решить испустить какой-то другой эквивалент во время следующей компиляции.

1 голос
/ 03 августа 2017

REP и друзья были хороши когда-то, когда процессор x86 был однопоточным промышленным CISC-процессором.

Но это изменилось.В настоящее время, когда процессор сталкивается с любой инструкцией, первое, что он делает, переводит ее в более простой формат (VLIW-подобные микрооперации) и планирует ее на будущее выполнение (это часть неупорядоченноговыполнение, часть планирования между различными логическими ядрами ЦП, это может использоваться для упрощения последовательностей записи после записи в отдельные записи и т. д.).Этот механизм хорошо работает для инструкций, которые преобразуются в несколько VLIW-подобных кодов операций, но не для машинного кода, который преобразуется в циклы.Преобразованный в цикле машинный код, вероятно, приведет к остановке конвейера выполнения.

Вместо того, чтобы тратить сотни тысяч транзисторов на создание схем ЦП для обработки циклических частей микроопераций в конвейере выполнения, они просто обрабатываютэто в каком-то дерьмовом унаследованном режиме, который останавливает конвейер и просит современных программистов писать свои собственные чертовы циклы!

Поэтому он редко используется, когда машины пишут код.Если вы встретите REP в двоичном исполняемом файле, то это, вероятно, человеческий ассемблер-маппет, который не знал лучше, или взломщик, которому действительно нужно было сохранить несколько байтов, чтобы использовать его вместо реального цикла, который написал его.

(Однако. Возьмите все, что я только что написал, с недоверием. Может быть, это больше не так. Я не на 100% в курсе внутренних дел процессоров x86, я увлекся другими увлечениями ...)

0 голосов
/ 27 января 2011

На исторической ноте - не имея представления о стратегиях производителя - было время, когда инструкции «rep movs *» (и т. Д.) Были очень медленными. Я думаю, что это было во времена Pentium / Pentium MMX. Мой коллега (у которого было больше информации, чем у меня) сказал, что производители уменьшили площадь микросхемы (<=> меньше транзисторов / больше микрокода), выделенную для обработки повторов, и использовали ее, чтобы ускорить выполнение других, более используемых инструкций.

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

0 голосов
/ 27 января 2011

Я использую варианты префикса rep * с вариантами команд cmps *, movs *, scas * и stos *, чтобы сгенерировать встроенный код, который минимизирует размер кода, избегает ненужных вызовов / переходов и тем самым снижает объем работы, выполняемой кэшами. Альтернатива состоит в том, чтобы установить параметры и вызвать memset или memcpy где-нибудь еще, что в целом может быть быстрее, если я хочу скопировать сто байт или более, но если это всего лишь 10-20 байт, использование rep быстрее (или, по крайней мере, было в последний раз я измерял).

Поскольку мой компилятор позволяет задавать и использовать встроенные функции сборки и включает использование / модификацию их регистров в действиях по оптимизации, я могу использовать их, когда обстоятельства верны.

...