Такое ощущение что никто считать не умеет.Все затраты известны бери и считай и делай выводы.
Статья скорее о том, что в нынешнее время многие из ЛПР вообще не знают (или давно забыли), что облакам есть альтернативы. Им надо напоминать, и регулярно.
С другой стороны, надо показывать и промежуточные варианты. Закупка наперёд снижает затраты, выделенные (dedicated) хосты - аналогично, но держать их на чужом ДЦ с техподдержкой от этого ДЦ может быть удобнее, чем самому заботиться о всех технических деталях.
А если взять сразу много и со скидкой, то может и облако будет дешевле.
Дешевле - вряд ли, сравнимо - да, но отсутствие головной боли тоже чего-то стоит.
Если смотреть в среднем по коду - не очень. Во всяком случае, чтобы что-то решалось на PDP-11 влёгкую, а на x86 в разы (минимум в три) сложнее - такого нигде нет.
Intel же в это время iAPX 432 разрабатывал, 386-й был лишь как затычка, чтобы рынок не потерять.
Насколько говорят основные доступные публично источники, это справедливо для 286, а не 386. 386 был начат теми, кто не верил в 432, а переведен в общий проект и сделан уже позже, когда всем стало понятно, что 432 сдох.
В любых процессорах\микроконтроллерах при наращивании разрядности будет в итоге абсолютно также
Нет, им не требуется модификация аргумента.
А на практике для большинства целочисленной арифметики в реальных программах за глаза хватает и 32-бит.
Стиль x86 дал возможность делать и короткие вычисления на двойных словах, и длинные без ограничения и извращений, одним и тем же средством, за линейное время.
Подозреваю, что о полуавтоматическом портировании ассемблерного кода с 8086 тоже думали.
Это ничем не ограничивает смену кодировки. Уже в 32 битах, например, команды IN, INS, OUT, OUTS, все прочие строковые (MOVS, SCAS...), HLT, CMC, PUSHA, POPA, BOUND, CBW, CWD, ENTER, LEAVE, INTO, CLI, STI, CLD, STD можно было сделать двух-, а некоторые даже трёхбайтовыми, хуже бы от этого не было. XLAT вообще можно было убрать уже тогда. Всё это освободило бы огромную группу кодов верхнего уровня. И это список не полный. В освободившиеся можно было бы вложить не только всякие SIMD, как началось в 90-х, но, например, варианты на 16 регистров, когда припекло бы. И тут не надо было бы даже удваивать декодер - и так есть различия в поведении одинаковых кодов, а небольшое количество исключений его бы не раздуло.
С 32->64 примерно то же самое.
Именно - второй повод сделать такую же замену был точно так же протерян.
А вот установку флага Z в MOV можно использовать для выхода из цикла копирования строк
Если нулевой байт - да. Но сами по себе NUL-terminated строки это специфический подход.
В любом случае, заметьте, все архитектуры, зачатые уже начиная с середины 70-х и не находящихся под явным влиянием PDP-11 (как VAX или M68k), MOV не меняет никакие флаги. Ну и дальше простановка флагов сокращается (в ARM её уже можно отменять для большинства команд). Не думаю, что столько умных людей сделали ошибку:)
Я не полностью процитировал:
Ну вот я про ручной сбор флагов переноса писал здесь, код на C и ссылка на код для MIPS. Что мешало сделать двухаргументную ADC, пусть даже только на регистрах?
Дле первого свдига - сброс бита переноса и циклический сдвиг (через бит переноса) вправо. Продолжение просто арифметическими сдвигами.
Именно, костыли. Или вот такое делаете, или после более быстрого ASH[C] маскируете.
80386 - наиболее вероятно, не хватило ресурсов. Это таки была разработка очень сложного вида, тогда это было где-то первым в мире. Ну и у разработчиков не было достаточного осознания, насколько наперёд их решения будут влиять, и как сложно их будет корректировать.
Ну а AMD строил свою amd64 реально в состоянии полной нищеты. То, что оно выстрелило - чудо, но проблемы создания перешли в легаси.
И это оказалось неплохо, потому что сильно упростило построение микроопераций при out-of-order. Уже с наворотами PDP-11 и VAX это сложнее, а с тем, что навернули в m68k - вчетверне. Лучше бы ещё меньше (см. SystemZ, где в основном блоке операций есть источники в памяти, но не приёмники), но и так уже было легче.
Надо просто уметь использовать особенности архитектуры. В данном случае можно можно при необходимости экономить на команде TST
Этого я не понял. Как на ней можно экономить и что это даст, например, для флага carry?
А зачем флаг переноса сбрасывать?
Кто его сбрасывал, вы о чём?
Нет только логического сдвига вправо.
И это уже само по себе существенно, потому что если он нужен, маску вычислять достаточно гиморно. Насколько я знаю, легче получить знаковый сдвиг из беззнакового, чем наоборот. Ну а при пошаговом сдвиге - особенно.
инструкции фиксированного размера легко раздекодировать параллельно, так что это не тормозит пайплайн
Да, но есть недостаток - полученное не масштабируется. Что будет, если (когда) у ARM закончатся опкоды?
Я тут вообще подумал, что имело бы смысл отличать код начала от кода продолжения. Например, группы по 4 байта, в не-первой всегда 4 старших бита 1111. Некоторое усложнение кодирования параметров, но зато возможности для расширения будут неограничены, и выборка команд - увидел 1111 - ага, отсюда не декодируем. Уверен, что не я первый придумал эту идею, так что больше интересно, почему нигде ещё не реализовано;\
А если в кодировке оставить один dst, но писать при этом ещё и в регистр dst +1 (и возможно в следующие) ?
Эээ... ну можно, да. (И на уровне ассемблера форсировать его явное указание, чтобы сократить ошибки.)
Но тут есть две другие проблемы. Одна сохраняется - такая команда будет требовать большей ширины шины между АЛУ и блоком регистров, или же больше тактов, чтобы по существующей шине писать ещё один регистр. Другая - что в алгоритм распределения регистров в компиляторе придётся добавлять костыль для пары регистров. Они такое сильно не любят. Есть архитектуры, где пары регистров традиционно есть (SystemZ, PDP-11, VAX), было в SIMD для ARM/32, где сделали сложную иерархию (D0=S0+S1, D1=S2+S3, Q0=D0+D1, и так далее), но для ARM/64 это повторять не стали.
Алгоритмы распределения регистров это и так сплошной закат солнца вручную, задача NP-полная, все существующие реализации что-то крутят частично. Совсем равных регистров нет, даже если сама ISA считает их одинаковыми, то конвенция вызова это ломает (есть callee-saved, есть аргументы и результаты, есть scratch - минимум 3 группы). Стопка диссеров, защищённых на локальных оптимизациях этой задачи, и статей помельче, наверно, уже скоро дорастёт до Эйфелевой башни. Люди, которые этим занимаются, ой как не оценят идею добавлять им головной боли. Да и зачем? Если есть один чётко определённый ни под что больше не занятый регистр с не сильно плотным использованием, пытаться это вынести в общие - как-то мало смысла...
У ДВК более совершенные , с точки зрения режимов адресации, машинные инструкции.
По поводу "более совершенных", включая режимы адресации, уже высказался.
Плюс код гарантированно выровнен на границу слова: размер любой инструкции кратен 2-м байтам, что сокращает количество нужных циклов чтения кода из памяти.
Стало иметь меньшее значение, когда началось массовое кэширование DRAM.
Все регистры общего назначения R0-R5 можно использовать в коде для любых вычислений
Для вычислений (таких же add, sub, and, or...) - можно и в x86. И с примерно такими же ограничениями. Например, для DIV нужна конкретная пара регистров (ok, в PDP-11 - три таких пары), а не вообще любые. Что ещё? Ширина сдвига в CL? Так в PDP-11 большинства тех сдвигов нет, а что есть - на 1 бит.
и ещё с автоинкрементом:
Ну да, экономия на размере кода для типового применения. Но не на скорости обработки, тут уже сильно зависит от реализации процессора. Заметим, ARM сделал это ещё гибче - и по возможности быстрее, сохраняя принцип "все вычисления - только с регистрами".
Собственно, поэтому на современных процах с флагами compare+branch обычно фьюзится в одну микроинструкцию, эквивалентную бранчу от MIPS/RISC V.
На моделях уровня от лаптопа или толстого embedded - да, наверняка хотя бы частично сделано.
Это уже не так просто, нужна логика для тракинга зависимостей между инструкциями по отдельным битам
Если таких команд очень мало от общего числа, то логику можно упростить до трекинга полного комплекта флагов. Особенно если не делать, как в старых архитектурах, вредных правил типа "эта команда вон тот флаг не меняет".
ну и операционка должна детектить такое расширение и сохранять/восстанавливать дополнительный регистр, как с векторами
Пишется в полдня с перекурами.
Проще в этих adc/sbc задействовать дополнительный обычный регистр для флага переноса.
Не всегда. Расширить формат команды может быть сложнее и вреднее на будущее, чем иметь служебный регистр. В RISC-V видно по развитию и по заявлениям авторов, как они руками и ногами отбиваются от подобных вариантов, стараясь ужиматься в традиционные трёхадресные форматы. Для fused multiply-add они согласились на 3 входных значения, а для conditional select уже нет - мол, используйте последовательность czero.nez + czero.eqz + or.
Похоже, из за того, что unsigned overflow - UB
Да.
но как тогда этот код на переносимом C/C++ написать
Начиная с C23 есть такое. В C++23 не вошло, но скорее всего будет в 26-м.
До этого переносимого везде варианта не было. Для GCC и Clang были overflow builtins (собственно, возможности C23 это они же), соответственно в Unix мире этим давно пользовались. Хотя напрямую неудобно, лучше через библиотеки. Сложение с ним на godbolt превращается в add + jo, это как раз максимум ужатия.
(Обратите внимание, что у обоих комплектов типы аргументов могут быть все разные. Это полезно для, например, операции сужения диапазона с проверкой. Это неочевидно, я не замечал, пока меня ныне забаненный khim@ не ткнул носом. (Без него тут скучнее.))
Ну и можно было для них же отдельные куски кода компилировать с -fwrapv для реализации такой защиты. Дороже и криво, но работает.
Про обратную соместимость с x86 в то время понятно, но что им мешало более адекватно сделать расширение в IA-32?
А я не понял вопрос. IA-32 это и есть 32-битный + 16-битный x86, что значит "расширение в IA-32"? Вы спрашиваете про изменения при переходах 16->32 или 32->64?
Кстати, что вы думаете про отказ от флагов вообще, как в MIPS или RISC V?
Как обычно, надо смотреть на компиляторы, поскольку 99.99+% кода генерится ими. Я как-то задумался над этим и посмотрел, как выглядит сгенерированный код для ARM/64. Подавляющее большинство случаев (опять же, навскидку, 99% и больше) условных действий по флагам идут сразу после сравнений, следующей командой. "S"-варианты команд (которые ставят флаги) редки и используются почти полностью для немедленного последующего условного перехода; остальные тотально без модификации флагов.
Поэтому действия в стиле RISC-V (как минимум), где или b${cond} r1, r2, или slt[i][u] r1, r2 - лучше туда ложатся. Не все действия у него (и у MIPS) ложатся на одну команду, некоторые - на две (например, bool f=x==y; ложится в sub или xor с последующим sltiu), но и с флагами получаются минимум две (сравнение и затем или переход, или запись в регистр).
Так что для современной компиляторной мысли - основного набора действий - безфлаговый вариант явно роднее. Но это не обязательно хорошо, см. ниже.
А ещё интересен пример SystemZ - там изначально флаговая система, но в развитии добавили пачку безфлаговых команд со сравнением регистров и немедленным переходом по условию. Значит, полезно. (Хотя основная масса остаётся по флагам.)
Я из проблем навскидку вижу только усложнение длинной арифметики, но в принципе тоже решаемо на микроархитектурном уровне.
Проблем таки больше. Если вы пишете a+b (оба со знаком) и согласны с надеждой компилятора, что переполнения не будет (на чём он оптимизирует код, иногда слишком неожиданно), то вам обычное add без флагов - оптимум (для MIPS это addu). А вот если хочется детектировать переполнение - то уже усложнение. В доке RISC-V описано, грубо говоря, детект как (wrapping_add(a,b) < a) == (b >= 0). Это 3 лишних команды и 2 временных регистра.
Так что если вы пишете "обычный" безалаберный код - то ему будет легче на машине без флагов, по описанному выше. А вот если параноить на каждую операцию - может оказаться, что лучше с флагами.
Длинная арифметика считается на таких платформах сейчас дорогим образом - где-то так:
Просто, прямолинейно... но дорого. 6 операций вместо одной. Пример можно посмотреть тут.
Вот тут как раз было бы полезно иметь расширение (которое будет присутствовать, грубо говоря, для лаптопов и выше) с adc, sbc, mul, div (без исключения, но с установкой флагов при проблемах), условными переходами, установкой регистра по условию; может, чем-то ещё. Ну и самим регистром флагов, просто ещё одним служебным.
Но в RISC-V сейчас, судя по спеке, есть туева хуча всего, но не такое. Видимо, на этих процессорах ещё не планировалась длинная арифметика (хм, криптография должна была успеть...)
Суммируя: я за параллельное существование обоих вариантов с предпочтением безфлаговому и ориентацией флагового варианта на особые нужды.
Вот странно. У вас "ой спорно", а у толпы олдов-фанатов пдп-11 не спорно...
Я тоже вполне олд уже и познакомился с клонами PDP-11 ещё в школе. Тогда - был практически фанатом. Позже - остыл, когда увидел множество вариантов для сравнения и проанализировал причины и последствия всех решений.
"Полутораадресные", если имеется в виду, что не больше одного операнда в памяти, это и в x86, кроме извращений вроде MOVS. Или в S/360 в основной группе, где приёмник вообще только регистр. 68k тут не уникален.
и огромный косяк с ADC/SBC, который аж не поправили, а повторили в ваксе.
Угу:(
Не знаю почему это "диверсия", и откуда вы взяли что в 68к этого нет (как раз очень есть).
Да, с m68k слегка промахнулся по памяти. Но заметьте MOVE ставит флаги, а MOVEA - уже нет. "Неаккуратненько" (ц).
А диверсия - потому что копирование достаточно часто оказывается универсальным действием на обе ветки развилки, или в цикле какого-то сложного действия, а если оно само портит флаги, то это сильно усложняет кодирование.
присмотритесь к арму или power, может и там оно окажется (опциональным для каждого опкода).
Нет. В ARM (обеих разрядностей) LDR, STR флаги не ставят никогда. Уже загруженное значение можно проверить через TST. Большинство других операций также имеют варианты с установкой флаги и без, причём в ARM/64 многие оставлены только в варианте без флагов (кому нужно - проверит выходной регистр). Разумеется, можно намеренно совместить с копированием - когда это вообще возможно - как например "ands x1, x2, x2". Но зачем?
В POWER то же самое, load-store ничего с флагами не делают, и для большинства целевых команд есть варианты с изменением флагов и без.
Да, система команд PDP-11 прекрасна. Как эсперанто.
Про прекрасность - ой спорно.
Пространства кодов для универсальных двухадресных команд не хватило. Даже байтовые варианты ADD и SUB не влезли. XOR, MUL, DIV, ASH(C) уже получили ограничения: часть аргументов только в регистрах. Двухадресными, по сути, остался тот минимум, который нужен для "управляющей" роли процессора.
5-й режим адресации (косвенный преавтодекрементный) нафиг никому не сдался, был пригоден только для гэгов. 3-й режим (косвенный поставтоинкрементный) в 99% кода использовался только с PC. В VAX переделали набор режимов, 5-й убили, остальные частично ограничили.
Установка флагов командами MOV, CLR, COM - диверсия, которую практически все позднейшие архитектуры, имеющие флаги условий, устранили. X86, ARM, SPARC, M68k, POWER - нигде такого нет.
Одноадресные ADC, SBC давали возможность строить арифметику двойной длины, но не многократной. Для многократной приходилось костылить с ручным сбором флагов переноса. Если бы сделали двухадресные аналоги на регистрах, было бы сильно удобнее.
Нет логических (беззнаковых) сдвигов, изволь маскировать сам.
Ляпов системного уровня ещё больше, но это уже не вопрос напрямую системы команд.
В целом, конечно, оказался потрясающий положительный пример:
8-битный (вместо 6-битного прежних моделей) компьютер в мини-сегменте;
NZVC стали стандартом;
ввод-вывод через адресное пространство - тоже стало стандартом.
Остальное как-то менее важно, но тоже неплохо. Описанные выше недостатки - вполне можно списать на проблемы первопроходца, плюс сложный старт проекта (как и с S/360, он был слишком революционным, и выигрыш был понят далеко не сразу).
PS: Эсперанто тоже не надо переоценивать. Польско-итальянский суржик, в котором хороша только нормализация с минимизацией исключений. Но увы, как и в IT - выстреливает (хоть как-то) первое минимально подходящее.
Я видел оба варианта: и где наследование нафиг не сдалось, и где без него можно было сразу вешаться. Причём домен в принципе один и тот же, но разные подсистемы / компоненты.
Статья скорее о том, что в нынешнее время многие из ЛПР вообще не знают (или давно забыли), что облакам есть альтернативы. Им надо напоминать, и регулярно.
С другой стороны, надо показывать и промежуточные варианты. Закупка наперёд снижает затраты, выделенные (dedicated) хосты - аналогично, но держать их на чужом ДЦ с техподдержкой от этого ДЦ может быть удобнее, чем самому заботиться о всех технических деталях.
Дешевле - вряд ли, сравнимо - да, но отсутствие головной боли тоже чего-то стоит.
Если смотреть в среднем по коду - не очень. Во всяком случае, чтобы что-то решалось на PDP-11 влёгкую, а на x86 в разы (минимум в три) сложнее - такого нигде нет.
Насколько говорят основные доступные публично источники, это справедливо для 286, а не 386. 386 был начат теми, кто не верил в 432, а переведен в общий проект и сделан уже позже, когда всем стало понятно, что 432 сдох.
Я именно так и догадался.
Нет, им не требуется модификация аргумента.
Стиль x86 дал возможность делать и короткие вычисления на двойных словах, и длинные без ограничения и извращений, одним и тем же средством, за линейное время.
Вы ж сами написали -
adc b1
,adc b2
...Вот именно, никаких регистров не хватит.
И O(N^2) для сложения - это таки диверсия.
Адище O(N^2), ещё и с порчей одного аргумента. Вот уж точно при числах длиннее от ≈6 слов применять ту схему, что по моей ссылке.
Но за показ трюка спасибо, сложу в кунсткамеру...
Это ничем не ограничивает смену кодировки. Уже в 32 битах, например, команды IN, INS, OUT, OUTS, все прочие строковые (MOVS, SCAS...), HLT, CMC, PUSHA, POPA, BOUND, CBW, CWD, ENTER, LEAVE, INTO, CLI, STI, CLD, STD можно было сделать двух-, а некоторые даже трёхбайтовыми, хуже бы от этого не было. XLAT вообще можно было убрать уже тогда. Всё это освободило бы огромную группу кодов верхнего уровня. И это список не полный. В освободившиеся можно было бы вложить не только всякие SIMD, как началось в 90-х, но, например, варианты на 16 регистров, когда припекло бы.
И тут не надо было бы даже удваивать декодер - и так есть различия в поведении одинаковых кодов, а небольшое количество исключений его бы не раздуло.
Именно - второй повод сделать такую же замену был точно так же протерян.
Если нулевой байт - да. Но сами по себе NUL-terminated строки это специфический подход.
В любом случае, заметьте, все архитектуры, зачатые уже начиная с середины 70-х и не находящихся под явным влиянием PDP-11 (как VAX или M68k),
MOV
не меняет никакие флаги. Ну и дальше простановка флагов сокращается (в ARM её уже можно отменять для большинства команд). Не думаю, что столько умных людей сделали ошибку:)Ну вот я про ручной сбор флагов переноса писал здесь, код на C и ссылка на код для MIPS. Что мешало сделать двухаргументную ADC, пусть даже только на регистрах?
Именно, костыли. Или вот такое делаете, или после более быстрого ASH[C] маскируете.
80386 - наиболее вероятно, не хватило ресурсов. Это таки была разработка очень сложного вида, тогда это было где-то первым в мире. Ну и у разработчиков не было достаточного осознания, насколько наперёд их решения будут влиять, и как сложно их будет корректировать.
Ну а AMD строил свою amd64 реально в состоянии полной нищеты. То, что оно выстрелило - чудо, но проблемы создания перешли в легаси.
И это оказалось неплохо, потому что сильно упростило построение микроопераций при out-of-order. Уже с наворотами PDP-11 и VAX это сложнее, а с тем, что навернули в m68k - вчетверне. Лучше бы ещё меньше (см. SystemZ, где в основном блоке операций есть источники в памяти, но не приёмники), но и так уже было легче.
Этого я не понял. Как на ней можно экономить и что это даст, например, для флага carry?
Кто его сбрасывал, вы о чём?
И это уже само по себе существенно, потому что если он нужен, маску вычислять достаточно гиморно. Насколько я знаю, легче получить знаковый сдвиг из беззнакового, чем наоборот. Ну а при пошаговом сдвиге - особенно.
Да, но есть недостаток - полученное не масштабируется. Что будет, если (когда) у ARM закончатся опкоды?
Я тут вообще подумал, что имело бы смысл отличать код начала от кода продолжения. Например, группы по 4 байта, в не-первой всегда 4 старших бита 1111. Некоторое усложнение кодирования параметров, но зато возможности для расширения будут неограничены, и выборка команд - увидел 1111 - ага, отсюда не декодируем. Уверен, что не я первый придумал эту идею, так что больше интересно, почему нигде ещё не реализовано;\
Эээ... ну можно, да. (И на уровне ассемблера форсировать его явное указание, чтобы сократить ошибки.)
Но тут есть две другие проблемы. Одна сохраняется - такая команда будет требовать большей ширины шины между АЛУ и блоком регистров, или же больше тактов, чтобы по существующей шине писать ещё один регистр. Другая - что в алгоритм распределения регистров в компиляторе придётся добавлять костыль для пары регистров. Они такое сильно не любят. Есть архитектуры, где пары регистров традиционно есть (SystemZ, PDP-11, VAX), было в SIMD для ARM/32, где сделали сложную иерархию (D0=S0+S1, D1=S2+S3, Q0=D0+D1, и так далее), но для ARM/64 это повторять не стали.
Алгоритмы распределения регистров это и так сплошной закат солнца вручную, задача NP-полная, все существующие реализации что-то крутят частично. Совсем равных регистров нет, даже если сама ISA считает их одинаковыми, то конвенция вызова это ломает (есть callee-saved, есть аргументы и результаты, есть scratch - минимум 3 группы). Стопка диссеров, защищённых на локальных оптимизациях этой задачи, и статей помельче, наверно, уже скоро дорастёт до Эйфелевой башни. Люди, которые этим занимаются, ой как не оценят идею добавлять им головной боли. Да и зачем? Если есть один чётко определённый ни под что больше не занятый регистр с не сильно плотным использованием, пытаться это вынести в общие - как-то мало смысла...
По поводу "более совершенных", включая режимы адресации, уже высказался.
Стало иметь меньшее значение, когда началось массовое кэширование DRAM.
Для вычислений (таких же add, sub, and, or...) - можно и в x86. И с примерно такими же ограничениями. Например, для DIV нужна конкретная пара регистров (ok, в PDP-11 - три таких пары), а не вообще любые. Что ещё? Ширина сдвига в CL? Так в PDP-11 большинства тех сдвигов нет, а что есть - на 1 бит.
Ну да, экономия на размере кода для типового применения. Но не на скорости обработки, тут уже сильно зависит от реализации процессора. Заметим, ARM сделал это ещё гибче - и по возможности быстрее, сохраняя принцип "все вычисления - только с регистрами".
На моделях уровня от лаптопа или толстого embedded - да, наверняка хотя бы частично сделано.
Если таких команд очень мало от общего числа, то логику можно упростить до трекинга полного комплекта флагов. Особенно если не делать, как в старых архитектурах, вредных правил типа "эта команда вон тот флаг не меняет".
Пишется в полдня с перекурами.
Не всегда. Расширить формат команды может быть сложнее и вреднее на будущее, чем иметь служебный регистр. В RISC-V видно по развитию и по заявлениям авторов, как они руками и ногами отбиваются от подобных вариантов, стараясь ужиматься в традиционные трёхадресные форматы. Для fused multiply-add они согласились на 3 входных значения, а для conditional select уже нет - мол, используйте последовательность czero.nez + czero.eqz + or.
Да.
Начиная с C23 есть такое. В C++23 не вошло, но скорее всего будет в 26-м.
До этого переносимого везде варианта не было. Для GCC и Clang были overflow builtins (собственно, возможности C23 это они же), соответственно в Unix мире этим давно пользовались. Хотя напрямую неудобно, лучше через библиотеки. Сложение с ним на godbolt превращается в add + jo, это как раз максимум ужатия.
(Обратите внимание, что у обоих комплектов типы аргументов могут быть все разные. Это полезно для, например, операции сужения диапазона с проверкой. Это неочевидно, я не замечал, пока меня ныне забаненный khim@ не ткнул носом. (Без него тут скучнее.))
Ну и можно было для них же отдельные куски кода компилировать с
-fwrapv
для реализации такой защиты. Дороже и криво, но работает.А я не понял вопрос. IA-32 это и есть 32-битный + 16-битный x86, что значит "расширение в IA-32"? Вы спрашиваете про изменения при переходах 16->32 или 32->64?
Как обычно, надо смотреть на компиляторы, поскольку 99.99+% кода генерится ими. Я как-то задумался над этим и посмотрел, как выглядит сгенерированный код для ARM/64. Подавляющее большинство случаев (опять же, навскидку, 99% и больше) условных действий по флагам идут сразу после сравнений, следующей командой. "S"-варианты команд (которые ставят флаги) редки и используются почти полностью для немедленного последующего условного перехода; остальные тотально без модификации флагов.
Поэтому действия в стиле RISC-V (как минимум), где или
b${cond} r1, r2
, илиslt[i][u] r1, r2
- лучше туда ложатся. Не все действия у него (и у MIPS) ложатся на одну команду, некоторые - на две (например,bool f=x==y;
ложится в sub или xor с последующим sltiu), но и с флагами получаются минимум две (сравнение и затем или переход, или запись в регистр).Так что для современной компиляторной мысли - основного набора действий - безфлаговый вариант явно роднее. Но это не обязательно хорошо, см. ниже.
А ещё интересен пример SystemZ - там изначально флаговая система, но в развитии добавили пачку безфлаговых команд со сравнением регистров и немедленным переходом по условию. Значит, полезно. (Хотя основная масса остаётся по флагам.)
Проблем таки больше. Если вы пишете a+b (оба со знаком) и согласны с надеждой компилятора, что переполнения не будет (на чём он оптимизирует код, иногда слишком неожиданно), то вам обычное add без флагов - оптимум (для MIPS это addu). А вот если хочется детектировать переполнение - то уже усложнение. В доке RISC-V описано, грубо говоря, детект как (wrapping_add(a,b) < a) == (b >= 0). Это 3 лишних команды и 2 временных регистра.
Так что если вы пишете "обычный" безалаберный код - то ему будет легче на машине без флагов, по описанному выше. А вот если параноить на каждую операцию - может оказаться, что лучше с флагами.
Длинная арифметика считается на таких платформах сейчас дорогим образом - где-то так:
Просто, прямолинейно... но дорого. 6 операций вместо одной. Пример можно посмотреть тут.
Вот тут как раз было бы полезно иметь расширение (которое будет присутствовать, грубо говоря, для лаптопов и выше) с adc, sbc, mul, div (без исключения, но с установкой флагов при проблемах), условными переходами, установкой регистра по условию; может, чем-то ещё. Ну и самим регистром флагов, просто ещё одним служебным.
Но в RISC-V сейчас, судя по спеке, есть туева хуча всего, но не такое. Видимо, на этих процессорах ещё не планировалась длинная арифметика (хм, криптография должна была успеть...)
Суммируя: я за параллельное существование обоих вариантов с предпочтением безфлаговому и ориентацией флагового варианта на особые нужды.
Перепроектировать такие вещи это таки объёмная работа.
Вполне возможно, тупо не хватило ресурсов, а рынок гнал что-то сделать.
Я тоже вполне олд уже и познакомился с клонами PDP-11 ещё в школе. Тогда - был практически фанатом. Позже - остыл, когда увидел множество вариантов для сравнения и проанализировал причины и последствия всех решений.
"Полутораадресные", если имеется в виду, что не больше одного операнда в памяти, это и в x86, кроме извращений вроде MOVS. Или в S/360 в основной группе, где приёмник вообще только регистр. 68k тут не уникален.
Угу:(
Да, с m68k слегка промахнулся по памяти. Но заметьте MOVE ставит флаги, а MOVEA - уже нет. "Неаккуратненько" (ц).
А диверсия - потому что копирование достаточно часто оказывается универсальным действием на обе ветки развилки, или в цикле какого-то сложного действия, а если оно само портит флаги, то это сильно усложняет кодирование.
Нет. В ARM (обеих разрядностей) LDR, STR флаги не ставят никогда. Уже загруженное значение можно проверить через TST. Большинство других операций также имеют варианты с установкой флаги и без, причём в ARM/64 многие оставлены только в варианте без флагов (кому нужно - проверит выходной регистр). Разумеется, можно намеренно совместить с копированием - когда это вообще возможно - как например "ands x1, x2, x2". Но зачем?
В POWER то же самое, load-store ничего с флагами не делают, и для большинства целевых команд есть варианты с изменением флагов и без.
Про прекрасность - ой спорно.
Пространства кодов для универсальных двухадресных команд не хватило. Даже байтовые варианты ADD и SUB не влезли. XOR, MUL, DIV, ASH(C) уже получили ограничения: часть аргументов только в регистрах. Двухадресными, по сути, остался тот минимум, который нужен для "управляющей" роли процессора.
5-й режим адресации (косвенный преавтодекрементный) нафиг никому не сдался, был пригоден только для гэгов. 3-й режим (косвенный поставтоинкрементный) в 99% кода использовался только с PC. В VAX переделали набор режимов, 5-й убили, остальные частично ограничили.
Установка флагов командами MOV, CLR, COM - диверсия, которую практически все позднейшие архитектуры, имеющие флаги условий, устранили. X86, ARM, SPARC, M68k, POWER - нигде такого нет.
Одноадресные ADC, SBC давали возможность строить арифметику двойной длины, но не многократной. Для многократной приходилось костылить с ручным сбором флагов переноса. Если бы сделали двухадресные аналоги на регистрах, было бы сильно удобнее.
Нет логических (беззнаковых) сдвигов, изволь маскировать сам.
Ляпов системного уровня ещё больше, но это уже не вопрос напрямую системы команд.
В целом, конечно, оказался потрясающий положительный пример:
8-битный (вместо 6-битного прежних моделей) компьютер в мини-сегменте;
NZVC стали стандартом;
ввод-вывод через адресное пространство - тоже стало стандартом.
Остальное как-то менее важно, но тоже неплохо. Описанные выше недостатки - вполне можно списать на проблемы первопроходца, плюс сложный старт проекта (как и с S/360, он был слишком революционным, и выигрыш был понят далеко не сразу).
PS: Эсперанто тоже не надо переоценивать. Польско-итальянский суржик, в котором хороша только нормализация с минимизацией исключений. Но увы, как и в IT - выстреливает (хоть как-то) первое минимально подходящее.
Я видел оба варианта: и где наследование нафиг не сдалось, и где без него можно было сразу вешаться. Причём домен в принципе один и тот же, но разные подсистемы / компоненты.
Предвзятость - да, безусловно согласен.