1 ответ:
TL; DR резюме:
xor same, same- это лучший выбор для всех процессоров. Никакой другой метод не имеет никакого преимущества перед ним, и он имеет по крайней мере некоторое преимущество перед любым другим методом. Это официально рекомендовано Intel и AMD. В 64-битном режиме, по-прежнему использоватьxor r32, r32, потому что написание 32-битных reg нулей верхний 32.xor r64, r64это пустая трата байта, потому что ему нужен префикс REX.обнуление векторного регистра обычно лучше всего делать с помощью
pxor xmm, xmm. Это обычно то, что делает gcc (даже перед использованием с инструкциями FP).
xorps xmm, xmmможет иметь смысл. Это на один байт короче, чемpxor, аxorpsтребуется порт выполнения 5 на Intel Nehalem, в то время какpxorможет работать на любом порту (0/1/5). (Задержка задержки обхода Nehalem 2c между integer и FP обычно не имеет значения, потому что выполнение вне порядка обычно может скрыть его в начале новой цепочки зависимостей).на SnB-семейство микроархитектур, ни один вкус XOR-обнуления даже не нуждается в порту выполнения. На AMD и pre-Nehalem P6 / Core2 Intel,
xorpsиpxorобрабатываются таким же образом (как векторных целочисленных инструкций).используя версию AVX векторной инструкции 128b нули в верхней части reg, так что
vpxor xmm, xmm, xmmхороший выбор для обнуления YMM(AVX1/AVX2) или ZMM (AVX512), или любого будущего векторного расширения.vpxor ymm, ymm, ymmне принимает никаких дополнительных байтов для кодирования, хотя и работает так же. В AVX512 ЗММ обнуление потребует дополнительных байтов (для префикса EVEX), поэтому обнуление XMM или YMM должно быть предпочтительным.
некоторые процессоры признать
sub same,sameкак обнуление идиомы, какxor, а все процессоры, которые распознают любые обнуляющие идиомы, распознаютxor. Просто используйтеxorпоэтому вам не нужно беспокоиться о том, какой процессор распознает, какая идиома обнуления.
xor(будучи признанной идиомой обнуления, в отличие отmov reg, 0) имеет некоторые очевидные и некоторые тонкие преимущества (сводный список, затем я буду расширять их):
- меньший размер кода, чем
mov reg,0. (Все Процессоры)- избегает штрафов частичного регистра для более позднего кода. (Intel P6-family и SnB-family).
- не использует блок исполнения, сохраняя силу и освобождая вверх по ресурсам исполнения. (Intel SnB-family)
- меньший uop (без непосредственных данных) оставляет место в кэш-строке uop для соседних инструкций, чтобы заимствовать, если это необходимо. (Интел СНБ-семья).
- не использует записи в файле физического регистра. (Intel SnB-family (и P4) по крайней мере, возможно, AMD, так как они используют аналогичный дизайн PRF вместо того, чтобы сохранять состояние регистра в ROB, как микроархитектуры Intel P6-family.)
меньший размер машинного кода (2 байта вместо 5) всегда является преимуществом: более высокая плотность кода приводит к меньшему количеству пропусков команд-кэша и лучше инструкция извлекает и потенциально декодирует полосу пропускания.
пользу не используя исполнительную единицу для xor на Микроархитектурах семейства Intel SnB-это незначительно, но экономит электроэнергию. Это, скорее всего, будет иметь значение на SnB или IvB, которые имеют только 3 порта выполнения ALU. Haswell и более поздние версии имеют 4 порта выполнения, которые могут обрабатывать целочисленные инструкции ALU, включая
mov r32, imm32, поэтому при идеальном принятии решений планировщиком (что на практике не происходит), HSW может все еще поддерживайте 4 uops в часы, даже когда им всем нужны порты выполнения.посмотреть мой ответ на другой вопрос об обнулении регистров для более подробной информации.
сообщение в блоге Брюса Доусона что Майкл Петч связал (в комментарии к вопросу) указывает на то, что
xorобрабатывается на этапе register-rename без необходимости в единице выполнения (ноль uops в несвязанном домене), но пропустил тот факт, что это все еще один uop в домен слит. Современные процессоры Intel могут выдавать и выводить на пенсию 4 uops с плавленым доменом за часы. Вот откуда берутся 4 нуля на тактовый лимит. Повышенная сложность аппаратного переименования регистра является лишь одной из причин ограничения ширины конструкции до 4. (Брюс написал несколько очень отличных сообщений в блоге, таких как его серия на FP math и x87 / SSE / вопросы округления, что я очень рекомендую).
на бульдозере AMD-семья Процессоры,
mov immediateработает на тех же самых целочисленных портах выполнения EX0/EX1, что иxor.mov reg,regможет также работать на AGU0 / 1, но это только для копирования регистра, а не для настройки из непосредственных. Так что AFAIK, на AMD единственное преимуществоxorovermovкороче кодирования. Это также может сэкономить физические ресурсы регистра, но я не видел никаких тестов.
распознаются обнуляющие идиомы избегайте частичной регистрации штрафов на процессорах Intel, которые переименовывают частичные регистры отдельно от полных регистров (семейства P6 и SnB).
xorбудет пометьте регистр как имеющий обнуленные верхние части, так чтоxor eax, eax/inc al/inc eaxуклоняется от обычного частичного регистра наказание, которое предварительно Ивб процессоры. Даже безxor, IvB нуждается только в слиянии uop, когда высокие 8 бит (AH) изменяются, а затем весь регистр считывается, и Хасвелл даже удаляет это.из руководства микроархива Агнера Фога, pg 98 (раздел Pentium M, на который ссылаются более поздние разделы, включая SnB):
процессор распознает операция "исключающее ИЛИ" регистра с самим собой, как установка его к нулю. Специальный тег в регистре запоминает, что высокая часть регистр равен нулю, так что EAX = AL. Этот тег запоминается даже в цикле:
; Example 7.9. Partial register problem avoided in loop xor eax, eax mov ecx, 100 LL: mov al, [esi] mov [edi], eax ; No extra uop inc esi add edi, 4 dec ecx jnz LL(из pg82): процессор запоминает, что верхние 24 бита EAX равны нулю до тех пор, пока вы не получите прерывания, неправильного предсказания или другое событие сериализации.
pg82 этого руководства также подтверждает, что
mov reg, 0и не распознается как обнуляющая идиома, по крайней мере, на ранних проектах P6, таких как PIII или PM. Я был бы очень удивлен, если бы они потратили транзисторы на обнаружение его на более поздних процессорах.
xorкомплектов, что означает, что вы должны быть осторожны при проверке условия. Так какsetccк сожалению, доступен только с 8 бит пункт назначения, вы обычно должны заботиться, чтобы избежать частичной регистрации штрафов.было бы неплохо, если бы x86-64 перепрофилировал один из удаленных опкодов (например, AAM) для 16/32/64 бит
setcc r/m, с предикатом, закодированным в 3-битном поле исходного регистра поля r/m (так, как некоторые другие инструкции с одним операндом используют их в качестве битов кода операции). Но они этого не сделали, и это все равно не помогло бы x86-32.в идеале, вы должны использовать
xor/ установите флаги /setcc/ Читать полный регистр:... call some_func xor ecx,ecx ; zero *before* the test test eax,eax setnz cl ; cl = (some_func() != 0) add ebx, ecx ; no partial-register penalty hereэто имеет оптимальную производительность на всех процессорах (без остановок, слияния uops или ложных зависимостей).
все сложнее, когда вы не хотите xor перед инструкцией по установке флага. например, вы хотите ветвиться на одном условии, а затем setcc на другом условии из тех же флагов. например,
cmp/jle,sete, и у вас либо нет запасного регистра, либо вы хотите сохранитьxorиз не принятого пути кода вообще.нет распознанных идиом обнуления, которые не влияют на флаги, поэтому лучший выбор зависит от целевой микроархитектуры. В Core2 вставка объединяющего uop может вызвать остановку цикла 2 или 3. Это, кажется, дешевле на SnB, но я не тратил много времени, пытаясь измерить. Используя
mov reg, 0/setccбудет иметь значительный штраф на старых процессорах Intel, и все еще будет несколько хуже на новых Intel.используя
setcc/movzx r32, r8вероятно, лучшая альтернатива для семей Intel P6 & SnB, если вы не можете xor-zero опередить инструкцию по установке флага. Это должно быть лучше, чем повторять тест после обнуления xor. (Даже не думайтеsahf/lahfилиpushf/popf). IvB может устранитьmovzx r32, r8(т. е. обрабатывать его с переименованием регистра без единицы выполнения или задержки, как XOR-обнуление). Haswell и позже только устранить регулярныеmovинструкцииmovzxпринимает казнь блок и имеет ненулевую задержку, делая тест/setcc/movzxхужеxor/проверки/setcc, но все равно по крайней мере так хорошо, как тест/mov r,0/setcc(и гораздо лучше на старых процессорах).используя
setcc/movzxбез пристрелки-первых, это плохо на AMD/Р4/микроархитектуре Silvermont, потому что они не отслеживают депс отдельно для подгрупп регистров. Было бы ложное dep на старом значении регистра. Используяmov reg, 0/setccдля обнуления / разбиения зависимостей, вероятно, лучше всего альтернатива, когдаxor/проверки/setccне вариант.конечно, если вам не нужен
setccвыход должен быть шире, чем 8 бит, вам не нужно ничего обнулять. Однако остерегайтесь ложных зависимостей от процессоров, отличных от P6 / SnB, если вы выбираете регистр, который недавно был частью длинной цепочки зависимостей. (И остерегайтесь вызывать частичную остановку reg или дополнительный uop, если вы вызываете функцию, которая может сохранить / восстановить регистр, который вы используете часть из.)
andс нуля не является специальным случаем как независимое от старого значения на любых процессорах, о которых я знаю, поэтому он не нарушает цепочки зависимостей. Он не имеет никаких преимуществ передxor, но и много недостатков.см.http://agner.org/optimize/ для микроархивной документации, в том числе для которой обнуление идиом распознается как разрыв зависимостей (например,
sub same,sameнаходится на некоторых, но не на всех процессорах, в то время какxor same,sameэто прям по всем.)movразрывает цепочку зависимостей от старого значения регистра (независимо от исходного значения, нулевого или нет, потому что такmovработает).xorтолько разрывает цепочки зависимостей в специальном случае, когда src и dest являются одним и тем же регистром, поэтомуmovв список специально признал зависимость-выключатели. (Кроме того, потому что он не распознается как обнуляющая идиома, с другими преимуществами, которые нести.)интересно, что самый старый дизайн P6 (PPro) не узнать
xor-обнуление в качестве прерывателя зависимостей, только как идиома обнуления для целей избежания частичных регистров, поэтому в некоторых случаях стоило использовать и. (См. Пример палочек agner туман 6.17. в его microarch в формате PDF. Он утверждает, что это также относится к P2, P3 и даже (рано?) ПМ, но я к этому отношусь скептически. комментарий к связанному сообщению в блоге говорит он был только PPro, который имел этот надзор. Кажется действительно маловероятным, что несколько поколений семейства P6 существовали без признания XOR-обнуления в качестве выключателя dep.)
если это действительно делает ваш код лучше и сохраняет инструкции, то конечно, ноль с
movчтобы не касаться флагов, пока вы не вводите проблему производительности, отличную от размера кода. Избегая clobbering флаги является единственной разумной причиной для не использованияxor, хотя.
Comments