2011-01-27 2 views
5

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

+2

Позвольте мне понять это прямо. Вы хотите использовать C++ (язык среднего и высокого уровня) для написания инструкций ассемблера? Что дальше? Вы хотите использовать C++ для подключения диода к вашей материнской плате? –

+0

@JUST Вы понимаете, что C++ имеет сборные блоки? –

+2

@ Майкл: Не переносимо. Например, для MSVC он даже не поддерживается на x64, и он устарел (в пользу intrinsics) на x86. –

ответ

3

Если вам нужна именно эта инструкция - используйте встроенный ассемблер и напишите эту инструкцию вручную. You can't rely on the compiler to produce any specific machine code - даже если он испускает его в одной компиляции, он может решить испустить какой-то другой эквивалент во время следующей компиляции.

+0

Написание инструкции вручную часто нарушает оптимизацию компилятора, и в таких случаях - если скорость важна - вам лучше позвонить в библиотечные процедуры. –

+0

@ Olof Forshell: Ну, да. Но зачем кому-то понадобиться конкретно эта инструкция? – sharptooth

+0

Как я уже писал здесь, есть конкретные ситуации, когда встроенный rep movsb/movsw/movsd и др. Будут быстрее и компактнее, что приведет к уменьшению работы кеша на стороне инструкции. Если я хочу скопировать менее 32 байт, зачем вызывать процедуру где-то еще, которая оптимизирована для 32 байтовых кусков, когда я могу сделать это быстрее и менее разрушительной встроенной? –

10

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

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

+0

REP не является инструкцией, это префикс инструкции. Это также далеко не устарело (см. Набор инструкций amd64). –

+5

@Michael Foukarakis См. «Руководство по оптимизации программного обеспечения AMD для процессоров AMD64», раздел 8.3. «Не используйте префикс REP при выполнении строковых операций, особенно при копировании блоков из памяти .В общем случае использование префикса REP для многократного выполнения строковых инструкций менее оптимально, чем другие методы, особенно при копировании блоков памяти. " – Crashworks

+0

Интересно. Я знаю, что это не по теме, но что будет - в x86 или amd64 ассемблере - оптимальный способ скопировать блок памяти – avakar

5

В соответствии с 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), если вы не чувствуете, как запись пользовательских сборок для «горячих» областей ...

0

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

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

0

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

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

0

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

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

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^