Почему инструкции INC и DEC * не * влияют на флаг переноса (CF)?
Почему инструкция x86 INC
(приращение) и DEC
(декремент) не влияет на CF
(нести флаг) во FLAGSREGISTER?
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: Кажется, что проблема с остановкой решается лучше на современных x86. Смотрите инструкцию INC против ADD 1: это имеет значение?
Вопрос о том, почему знак, когда у вас установлен нулевой флаг с помощью 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`
Как уже пояснила Ира Бакстер, флаг Carry используется во многих алгоритмах - не только для арифметики с множественной точностью, но и для, скажем, обработки растровых изображений в эпоху монохромных /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-х годов, когда транзисторов было мало. Отказ в вычислении флага четности для какой-то конкретной инструкции не имел бы никакого смысла, а лишь увеличивал сложность ЦП.
Инструкции inc и dec обычно используются для поддержания итерации или числа циклов. Используя 32 бита, число итераций может достигать 4 294 967 295. Это число достаточно велико для большинства приложений. Что если нам нужен счет, который больше этого? Должны ли мы использовать add вместо inc? Это приводит ко второй и основной причине.
Условие, обнаруженное с помощью флага переноса, также может быть обнаружено с помощью флага нуля. Зачем? Потому что inc и dec изменяют число только на 1. Например, предположим, что регистр ECX достиг своего максимального значения 4 294 967 295 (FFFFFFFFH). Если мы тогда выполним
inc ECX
мы обычно ожидаем, что флаг переноса будет установлен в 1. Однако мы можем обнаружить это условие, отметив, что ECX = 0, что устанавливает флаг нуля. Таким образом, установка флага переноса действительно избыточна для этих инструкций.
Потому что нет необходимости влиять. Этого вполне достаточно, чтобы проверить нулевой флаг. Таким образом, после инструкций inc и dec флаг переноса остается тем же, и в некоторых случаях это полезно.