Самый быстрый способ установить одну ячейку памяти в ноль или константу в сборке x86?

Каков самый быстрый способ обнулить одну ячейку памяти в x86? Обычно я это делаю так:

C745D800000000  MOV [ebp-28], 0

Как видите, у него довольно короткая кодировка, поскольку в качестве константы используются все 4 байта. С простым регистром я могу использовать MVZE, который более компактен, но MVZE не работает с памятью.

Я подумал, может быть, очистить регистр, а затем MOV значение регистра в память. Тогда это будут две инструкции, но всего 5 байтов вместо одной 7-байтовой инструкции, указанной выше. Это может быть предпочтительнее, следуя правилу «короче, обычно быстрее».


person Tyler Durden    schedule 15.03.2013    source источник
comment
Вы можете выполнить XOR с самим собой, но я не думаю, что это будет быстрее: xor [ebp-28], [ebp-28].   -  person Linuxios    schedule 16.03.2013
comment
Вы не можете выполнить XOR ячейки памяти с самой собой, поскольку инструкция не может иметь двух операндов памяти.   -  person Daniel Kamil Kozar    schedule 16.03.2013
comment
Некоторые инструкции x86 имеют два операнда памяти ....   -  person Carl Norum    schedule 16.03.2013
comment
@CarlNorum: не могли бы вы привести пример?   -  person Daniel Kamil Kozar    schedule 16.03.2013
comment
@Daniel, movs имеет указатели как источника, так и места назначения.   -  person Carl Norum    schedule 16.03.2013
comment
Конечно, но они явно не указаны как операнды для этой инструкции и закодированы непосредственно с ней.   -  person Daniel Kamil Kozar    schedule 16.03.2013
comment
FWIW push - еще одна инструкция памяти.   -  person Igor Skochinsky    schedule 18.03.2013
comment
@DanielKamilKozar Какие инструкции x86 принимают два (или более) операнда памяти?. Да, инструкция может иметь не более одного явного операнда памяти   -  person phuclv    schedule 01.02.2019
comment
Когда вы говорите «отдельная ячейка», вы имеете в виду байт? Или вы имеете в виду dword / qword (где mov потребует imm32)?   -  person Peter Cordes    schedule 02.02.2019
comment
@PeterCordes Я имею в виду слово памяти, которое на 32-битной машине будет 4 байта, а на 64-битной машине - 8 байтами. Но я открыт для ответов, которые обнуляли бы только один байт. В общем, поскольку центральные процессоры построены на манипулировании словами, это ожидаемый предмет вопроса.   -  person Tyler Durden    schedule 03.02.2019
comment
Вы отметили это x86; они построены на основе невыровненных загрузок / хранилищ и отдельных байтов. По-видимому, многие процессоры, отличные от x86, на самом деле выполняют цикл RMW в кеше для обновления байта в слове для байтового хранилища (Существуют ли какие-либо современные / старые процессоры / микроконтроллеры где кешируемое хранилище байтов на самом деле медленнее, чем хранилище слов?), но все современные ISA имеют байтовую адресацию и все имеют архитектурные хранилища байтов. (Может ли современное оборудование x86 не сохранять в памяти ни одного байта?). (кроме ранней Альфы, если вы считаете ее современной).   -  person Peter Cordes    schedule 03.02.2019
comment
@PeterCordes Хорошо, тогда рассмотрим вопрос об обнулении байта памяти. Бросьте мне здесь кость, я не получил слишком разумного ответа на этот вопрос любого типа. Вы бьете дохлую лошадь, а бить лошади нечего.   -  person Tyler Durden    schedule 03.02.2019


Ответы (2)


К сожалению, то, что вы здесь написали, - это единственный способ «напрямую» обнулить ячейку памяти. Конечно, исключающее ИЛИ для регистра с последующим перемещением его в какое-либо место в памяти также будет работать, но я не знаю, будет ли это быстрее.

Если у вас есть регистр, значение которого равно нулю, и вы в этом уверены, то обязательно используйте его. В противном случае просто придерживайтесь mov [ebp-28], 0. Имейте в виду, что mem, imm операнды, как известно, являются одними из самых медленных: если вы профилируете свой код и обнаруживаете, что это узкое место, попробуйте инициализировать регистр нулем в начале вашей функции (или чего-то еще), а затем использовать его повсюду. код как своего рода предопределенная константа.

person Daniel Kamil Kozar    schedule 15.03.2013
comment
Знаете ли вы, является ли это еще и самым коротким путем? На x86 64 mov [r14], 0 - это 7-байтовая инструкция. - person Björn Lindqvist; 05.03.2015
comment
@ Björn На x86-64 xor eax, eax + mov [r14d], rax будет всего 5 байтов. (Вам не нужно выполнять XOR 64-битного регистра rax, потому что все операции с 32-битными регистрами неявно очищают верхнюю половину, и они короче для кодирования.) Это не обязательно может быть быстрее, хотя, чем mov mem, imm. Но, как говорит Дэниел, было бы очевидным, огромным выигрышем, если бы у вас было какое-либо другое использование значения 0 в той же функции, тем более что на x86-64 у вас практически всегда есть регистры в пространстве. Решение немного сложнее на x86-32, где вы бы отказались от ценного регистра в качестве нулевого регистра. - person Cody Gray; 16.12.2016
comment
Интересный факт: процессоры Intel не могут объединить инструкции с режимом относительной адресации RIP и немедленным, поэтому mov dword [rel label], 0 декодируется как инструкция с двумя мопами. Так что для статических данных на x86-64 это чистая победа - сначала xor обнулить регистр, если вы настраиваете процессоры Intel. - person Peter Cordes; 02.02.2019

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

По сути, запись отправляется прямо в память, а не наоборот. Поскольку ЦП взаимодействует с памятью фрагментами размером с строку кэша, то, что происходит под прикрытием, заключается в том, что строка кэша, содержащая запись, отправляется вместе с маской, указывающей, какие байты фактически обновляются. Либо в контроллере памяти, либо в кэше L3, либо в самой памяти записываемые байты объединяются с байтами, которые следует оставить в покое.

person BeeOnRope    schedule 02.02.2019