Почему инструкции INC и DEC *не* влияют на флаг переноса (CF)?

Почему инструкции x86 INC (приращение) и DEC (уменьшение) не влияют на CF (флаг переноса) в FLAGSREGISTER?


person mohammad mahed    schedule 17.11.2012    source источник
comment
@AndreasBrinck Этот вопрос не о «почему?», И ответы там не отвечают на вопрос о выборе дизайна.   -  person Pascal Cuoq    schedule 18.11.2012
comment
ЭТО НЕ ТОЧНЫЙ ДУБЛИКАТ. Другой вопрос спрашивает, как использовать INC/DEC, и просто отмечает, что перенос не обновляется. Этот вопрос спрашивает почему он не обновляется. Я нахожу тот факт, что несколько человек готовы закрыть вопрос как точный дубликат, когда это не так, указывает на то, что модераторы поспешили. Это бесполезно ИМХО для SO.   -  person Ira Baxter    schedule 18.11.2012
comment
Наполовину связанный: сборка x86: инструкция INC и DEC и флаг переполнения показывает несколько примеров того, как выполняется обновление OF, но не CF. Это не дубликат, с которым этот вопрос был ошибочно связан в какой-то момент.   -  person Peter Cordes    schedule 25.09.2020


Ответы (4)


Чтобы понять, почему вам, вероятно, нужно вспомнить, что нынешние процессоры «x86» с 32- и 64-битными значениями начали свою жизнь как гораздо более ограниченные 8-битные машины, восходящие к Intel 8008. (Я кодировал в этом мире еще в 1973 году, я до сих пор помни (тьфу) это!).

В том мире регистры были драгоценными и маленькими. Вам нужны INC/DEC для различных целей, наиболее распространенной из которых является управление контуром. Многие циклы включали выполнение «арифметики с множественной точностью» (например, 16 бит или больше!). Установив INC/DEC флаг нуля (Z), вы могли бы довольно хорошо использовать их для управления циклами; настаивая на том, чтобы инструкции управления циклом не изменяли флаг переноса (CF), перенос сохраняется между итерациями цикла, и вы можете реализовывать операции с множественной точностью без написания тонны кода для запоминания состояния переноса.

Это работало очень хорошо, как только вы привыкли к уродливому набору инструкций.

На более современных машинах с большими размерами слов вам это не нужно, поэтому INC и DEC могут быть семантически эквивалентны ADD ...,1 и т. д. На самом деле это то, что я использую, когда мне нужен набор переносов: - }

В основном я сейчас держусь подальше от INC и DEC, потому что они выполняют частичное обновление кода условия, и это может вызвать забавные задержки в конвейере, а ADD/SUB этого не происходит. Так что там, где это не имеет значения (в большинстве мест), я использую ADD/SUB, чтобы избежать киосков. Я использую INC/DEC только в тех случаях, когда код не имеет большого значения, например, вписывается в строку кэша, где размер одной или двух инструкций имеет достаточное значение, чтобы иметь значение. Это, вероятно, бессмысленная нано[буквально!]-оптимизация, но я довольно старомоден в своих привычках кодирования.

Мое объяснение говорит нам, почему INC/DEC установили нулевой флаг (Z). У меня нет особенно убедительного объяснения, почему INC/DEC устанавливают знак (и флаг четности).

РЕДАКТИРОВАТЬ Апрель 2016: кажется, что проблема зависания лучше решается на современных x86s. См. инструкцию INC против ADD 1: имеет ли это значение?

person Ira Baxter    schedule 17.11.2012
comment
Установка SF/OF, а также ZF позволяет вам dec / jge выполнять цикл от n до 0, а не от n до 1. (т. е. провал, когда dec производит -1 вместо 0). - person Peter Cordes; 25.04.2018
comment
Обновление: Skylake еще лучше: он обрабатывает CF полностью отдельно от других FLAGS (SPAZO); несколько инструкций, которые требуют ввода от обоих, считывают их как 2 отдельных ввода, поэтому слияние флагов вообще не требуется. (Но cmova и cmovbe все еще 2 моп из-за 4 общих входных данных, в отличие от других инструкций cmov, которым нужно только 3. jcc и setcc всегда 1 моп, даже если им нужно 2 отдельных входа флага). См. ответ @Bee на Что такое частичная остановка флага? - person Peter Cordes; 04.11.2020

Вопрос о том, зачем подписывать, когда у вас есть флаг ноль, установленный inc/dec, лучше всего решать с помощью вопроса: вы бы предпочли обойтись без опции a ?

a) for (n=7;n>=0;n--)   // translates to   `dec + jns`
b) for (n=8;n>0;n--)    // translates to   `dec + jnz`

Как уже пояснил Ира Бакстер, флаг переноса используется во многих алгоритмах -- не только для арифметики с высокой точностью, но и для обработка растровых изображений в эпоху монохромного/cga/EGA: это сдвигает строку шириной 80 пикселей на один пиксель вправо...

        mov cx, 10
begin:  lodsb
        rcr al,1   // this is rotate though carry:
        stosb      // for the algorithm to work, carry must not be destroyed
        LOOP begin //

Но тогда: почему паритет?

Я считаю, что ответ: почему бы и нет. Этот набор инструкций относится к концу 70-х, когда транзисторов было мало. Отказ от вычисления флага четности для какой-то конкретной инструкции не имел бы никакого смысла, а только усложнил бы работу процессора.

person Aki Suihkonen    schedule 24.11.2012
comment
Почему не паритет? Я был бы готов поспорить, что из миллионов инструкций INC/DEC, написанных программистами, только крошечное число фактически использовало результат бита четности. Включение (фактически) бесполезных побочных эффектов в инструкцию просто означает больше документации, больше подобных обсуждений и больше транзисторов в будущих реализациях, чтобы обеспечить обратную совместимость с глупыми результатами. Совет архитекторам: если побочный эффект редко бывает полезен, не делайте этого. - person Ira Baxter; 25.04.2018

  1. Инструкции inc и dec обычно используются для поддержания количества итераций или циклов. При использовании 32 бит количество итераций может достигать 4 294 967 295. Этого числа достаточно для большинства приложений. Что делать, если нам нужно количество больше, чем это? Должны ли мы использовать add вместо inc? Это приводит ко второй и основной причине.

  2. Состояние, обнаруженное флагом переноса, также может быть обнаружено флагом нуля. Почему? Потому что inc и dec изменяют число только на 1. Например, предположим, что регистр ECX достиг своего максимального значения 4 294 967 295 (FFFFFFFFH). Если мы затем выполним

                     inc ECX
    

    обычно мы ожидаем, что флаг переноса будет установлен в 1. Однако мы можем обнаружить это условие, заметив, что ECX = 0, что устанавливает нулевой флаг. Таким образом, установка флага переноса действительно избыточна для этих инструкций.

person Zubair Noor    schedule 08.07.2018
comment
Да для inc, но не для dec. Для dec ZF==0 определяет итерацию до переноса (переход от 0 к 2^32-1). Я сделал тот же комментарий, этот на другой ответ, который также приводил этот аргумент. - person Peter Cordes; 09.07.2018

Потому что не нужно воздействовать. Достаточно проверить флаг Zero. Таким образом, после инструкций inc и dec флаг переноса остается прежним, и в некоторых случаях это полезно.

person GJ.    schedule 17.11.2012
comment
Это верно для inc: перенос идет от 0xFFFF... до 0, так что ZF и CF равны. Но dec переходит от 0 к 0xFFFF..., поэтому ZF устанавливается на декремент перед переносом. Настоящая причина, я думаю, заключается в том, что sub reg,1 доступен, если вам нужен CF, и обычно вам не нужен результат CF. Таким образом, сохранение CF позволяет использовать его в сочетании с ADC, сдвигами, RCL и другими вещами, которые сохраняют что-то в CF. (Конечно, это конструктивное решение было принято для 8086, задолго до того, как проблемы с частичным регистром стали рассматриваться как будущая проблема. В тот момент loop был эффективен, поэтому зацикливание без флажков было легко.) - person Peter Cordes; 17.04.2018