Pull to refresh
48
0
Valentin Nechayev @netch80

Программист (backend/сети)

Send message

Собственно, поэтому на современных процах с флагами 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 временных регистра.

Так что если вы пишете "обычный" безалаберный код - то ему будет легче на машине без флагов, по описанному выше. А вот если параноить на каждую операцию - может оказаться, что лучше с флагами.

Длинная арифметика считается на таких платформах сейчас дорогим образом - где-то так:

unsigned carry = 0;
for (i = 0; i < N; ++i) {
  // limb_t беззнаковый, знак хранится отдельно, суммирование с усечением
  limb_t tmp1 = a[i] + b[i];
  unsigned carry1 = tmp1 < a[i];
  limb_t lsum = tmp1 + carry;
  unsigned carry2 = lsum < tmp1;
  out[i] = lsum;
  carry = carry1 | carry2;
}

Просто, прямолинейно... но дорого. 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 давали возможность строить арифметику двойной длины, но не многократной. Для многократной приходилось костылить с ручным сбором флагов переноса. Если бы сделали двухадресные аналоги на регистрах, было бы сильно удобнее.

Нет логических (беззнаковых) сдвигов, изволь маскировать сам.

Ляпов системного уровня ещё больше, но это уже не вопрос напрямую системы команд.

В целом, конечно, оказался потрясающий положительный пример:

  1. 8-битный (вместо 6-битного прежних моделей) компьютер в мини-сегменте;

  2. NZVC стали стандартом;

  3. ввод-вывод через адресное пространство - тоже стало стандартом.

Остальное как-то менее важно, но тоже неплохо. Описанные выше недостатки - вполне можно списать на проблемы первопроходца, плюс сложный старт проекта (как и с S/360, он был слишком революционным, и выигрыш был понят далеко не сразу).

PS: Эсперанто тоже не надо переоценивать. Польско-итальянский суржик, в котором хороша только нормализация с минимизацией исключений. Но увы, как и в IT - выстреливает (хоть как-то) первое минимально подходящее.

Я видел оба варианта: и где наследование нафиг не сдалось, и где без него можно было сразу вешаться. Причём домен в принципе один и тот же, но разные подсистемы / компоненты.

Предвзятость - да, безусловно согласен.

По мнению этих голов, вероятно, да. Но зачем на них ориентироваться?

EEP 76: Priority Messages - в Erlang/OTP 28.0. Криво и неполно, но лёд начал крошиться. Поздравляем с опозданием на 15-20 лет по сравнению с тем, когда это действительно надо было сделать. До полноценной реализации ждать ещё примерно столько же?

CHESS выглядит прикольно. Иногда приходилось делать такие тесты, но очень несистематически и локально. Правда, боюсь, что если рандомизировать всё, то половина будет вылетов во всяких rtld и libc, а их лечить обычно не дело разработчика целевого приложения;\

Лицо с высшим техническим образованием

По совковому словарю - да, может быть. Именно таких "инженеров" тогда и выпускали миллионами. Это из той же оперы, что "Нет, тётя Роза - старший экономист!"

А вот автор статьи, конечно, слегка идеалистичен, но пытается вернуться к истокам. "Инженер (от лат. – хитроумный, остроумный, изобретательный) –создатель некоторых военных машин во втором веке, а впоследствии – творец всяких хитроумных устройств" (источник). И мне его позиция всяко ближе.

Нэймспейсы не особо относятся к ООП. Вполне можно их реализовать без ООП.

Я и не говорил такого. Я говорил о том, что полезно перетащить из C++. Хотя сейчас скажу, что неймспейсы таки косвенно имеют отношение к ООП: как и класс, это средство структурирования.

Приватные поля элементарно решаются без ООП, путем определения методов доступа в том-же модуле, где определена структура.

А как данные привязать к каждому конкретному объекту?

Это альтернатива, известная изначально, но пригодная далеко не всегда. "Перешли" - некорректный термин.

Потрясающий пример как не надо делать. Начиная с того, как не задетекчен случай полного вырождения в вычисление самим компилятором, с отсутствия вариаций по опциям компиляции... Впрочем, автор всегда отличался... мнэээ... оригинальным мышлением и пониженной самокритичностью, так что я не удивлён.

Не обязаны. Можно написать пачку статических процедур, сложить их всех в один класс, вызывать из статического main(), а максимум данных собрать в примитивные типы и их массивы.

Но результат будет однозначно неудобен.

Аргументация вывернута с ног на голову, именно из-за того, что 68k не стал ширпотребом, он и оставался дорогим, а не наоборот.

Вы переоцениваете вклад больших партий. Есть объективная цена производства - та самая, которая по расширенному закону Мура падала экспоненциально - и она не давала слишком быстрых результатов.

Интересно, сколько бы стоил 80286, если ибеме не выбрало бы себе 8088 чуть пораньше? Я думаю -- бесконечность, т.е. до него вообще не дошло бы.

Хороший вопрос. Возможно, Intel бы умер или ушёл чисто в производство памяти. Что именно IBM дала жизнь линии x86 - не вижу причин спорить с этим.

Но то, что я говорю - что x86 не был настолько плох на общем фоне, а m68k, например, соответственно не настолько лучше остальных, чтобы его проигрыш создал трагедию.

Как интересно получается: в том, что loop только с cx, сдвиги только с cl и умножения-деления только с dx/ax -- люди не путались, а в абсолютно равноправных 8+8 регистрах путались.

Да. Это не мой тезис. Я тоже немного удивлён. Но если такое приписывают создателю PDP-11, наверно, это соответствует общему пониманию в те времена.

Напоминаю, что вокруг - в среднем и нижнем ценовом сегменте - были чуть ли не тотально архитектуры на один аккумулятор, потому что иначе было дорого. S/360 с её почти равноправными регистрами, кроме старших моделей, стоивших миллионы, была сделана на микропрограммных автоматах, и равноправность регистров эмулировалась на микропрограммном уровне. На этом фоне уже 8 честных регистров PDP-11 (хоть, опять же, напрямую использованных в АЛУ только в старших моделях) было прогрессом.

За 10 лет после этого (считаем до 1979-1981) упаковка в формат микропроцессора только усилила давку по ресурсам. 8008, 8048, 8080, 6502 - один аккумулятор. 6800 - два почти равноправных аккумулятора - это нечто особенное, так больше никто не делал. Чуть более высокий сегмент, PDPшки все кроме 11-й - тоже один аккумулятор во главе. Граница до честных почти равноправных регистров как в PDP-11, S/360, S/370 - это было очень существенно.

Насколько этот стиль влиял на всех - не мне судить, я тогда только в детский сад ходил. Но если вокруг были почти везде одноадресный мир - это не могло не влиять.

Тут бы послушать более детально воспоминания тех, кто всё это проектировал.

И компиляторы наверное ВООБЩЕ не занимались распределением регистров, фигачили всё через один? (хотя для 8086 -- охотно поверю).

Занимались, но очень плохо по сравнению с нынешним уровнем. Сейчас только толковый спец в тонкостях архитектуры сможет систематически обгонять компилятор по качеству кода. Тогда - мог любой, кто знал ассемблер, и вопрос был только в объёме работы.

Но 8086 у нас офигенно ортогональный при этом. Выглядит как попытки манипуляции.

Ваши приписки про "офигенно ортогональный" и домыслы про манипуляцию прошу оставить при себе.

Конечно индиректные адресации в 68020+ чуть усложнили декодинг, но во1 в любом коде (уж я-то видел кучи кода под 68к) они используются редко

И что, от этого их свалили бы на микрокоманды, а остальное - на полноценный автомат? Я конечно не спец по OoO, но мне кажется, что это было бы сильно сложно. А поддерживать всю эту хрень таки надо было бы.

Итого -- проблема техническая, причём не требующая хай-перфоманс решения любой ценой.

А вот тут я сильно не уверен. Полноценный OoO на старте был чудовищно дорог в разработке. Intel вытянул его, по слухам, только с государственной помощью, получив заказ на 4e8$$ "за красивые глаза". И это при том, что меньше всяких индиректных, автодекрементных и прочих адресаций. С ними шансы вытянуть разработку, мне кажется, нулевые. Опять же, есть поле для раскопок.

Откуда кстати сразу можно сделать вывод, что уровень инженеров, выдумывавших ibm pc был настолько низок. что они ниасилили бы даже 8255 подключить к 68000.

Уровень у них был как раз очень хорошим. Задачу вложить в минимум аппаратных средств всё что нужно они отработали почти идеально. Лучше них только Возняк был с Apple II, там вообще шедевры инженерного строения.

Рассказы про "больше периферии под 8086" явно не соответствуют историческим фактам. А вот то, что 68000 в 1979 только анонсировался, в 1981 начали производить (а первые версии всегда проблемны), а вот для 8088 был к моменту опытных прототипов IBM PC уже второй источник от AMD - вот это то, что как раз повлияло.

Ну так напишите побольше. И чего-нибудь сложное, где регистров перестанет хватать. Или где массивчики за 64к вылезут.

Опять же, тут надо сравнивать с 386 - где нет проблем с переходом за 64KB. Хотя в huge режиме в 8086 их тоже не очень было:)

"Сложное, где регистров перестаёт хватать" - таких задач было достаточно мало. Опять же напоминаю про качество компиляторов.

Угу, спасибо за поправку.

а если это уже обжитая улица, которую решили пересечь новой дорогой?

В смысле, от этого сквозной проезд потерялся? Это не должно влиять.

Наверное имелось ввиду, что адресация не стала 32-битной? Ну так и не должна, процессор то 16-битный.

Здесь нет однозначной связи. System/360 Model 30 имела 8-битное АЛУ, шины вокруг него, исполняла всё однобайтными порциями. При этом у неё был полный набор 32-битных операций арифметики, и 24-битный адрес (когда младшие модели продавались с 4KB памяти и это уже стоило чудовищных денег, это было реально дофига). Позже, Z80 имел 4-битное АЛУ, но работал в основных командах с 8-битными данными, в части с 16-битными.

А вот то, что одним сегментом нельзя было адресовать больше 64KB, и вообще сегментация защищённого режима в 80286 - который был урезанной версией выбредка кого-то из отцов Intel, пытавшимся ещё что-то получить от мёртворожденного iAPX432 - это тут более существенно. В плюс Мотороле то, что они сразу попытались использовать плоский режим, без этих извращений - и тут не было потерь в скорости.

Однако по сравнению с 8086 и 8088 количество адресных линий возросло с 20 до 24

Только из-за ограничений стиля это было сильно неудобно. Полноценное использование началось уже с 386.

Ага, давайте сравнивать 68000 из 1979 с 80386 из 1985

Нет, ниже было в подробностях - сравнивать нужно диапазон 68010 - 68030.

Хотя вы можете сравнить и 8086 с 68000, конечно. 68000 на три года позже (реальные продажи - 1981), так что к IBM PC он катастрофически опоздал.

То есть выяснили, что страничное MMU в 68k появилось за 3 года до 386.

А в S/370 оно появилось на ≈10 лет раньше, и что?
А сколько стоило то MMU, вы таки посмотрели? Ещё удвоить цену процессора? Соответственно, сильное сокращение рынка. Аналогичный пример был с 8087, пока в 386-е не начали вкладывать FPU блок - его ставили только в специализированные машины.

А давайте ещё регистры посчитаем. 8 штук D и 7 штук (не считая стека) A. А в х86 ВСЕГО 7 регистров. Или это не считается?

С количеством регистров - я безусловно согласен, их в 2 раза больше (или 2.5, как считать). Вопрос в том, насколько это влияло на удобство работы кода - в те-то времена. Когда разрабатывалась PDP-11, например, в ней не захотели делать больше 8 регистров, потому что люди путались в таком количестве. Компиляторы стали заметно продвинутее только где-то с середины 1990х, потому что начала разрабатываться теория в современном виде, до этого они были совершенно топорными. Это требует серьёзного рассмотрения, была ли польза с тех 16 (15, неважно).

А вот то, что сейчас ностальгически вспоминается то, чего не было - якобы полная ортогональность - это факт бесспорный.

Тогда становится неясно зачем амд добавило r8..r15 регистры, наверное дураки были

Когда именно AMD их добавила? Это было на 10 лет позже. Для индустрии в те времена это чудовищный промежуток, поменялось практически всё. Про компиляторы я уже говорил, см. выше. Уже набрался опыт и с RISC-процессорами сразу нескольких архитектур, и SSA начали вводить. А вот на 1979 такое было критически мало где, я с ходу только S/370 вспомнил.

Насколько я помню, в 68060 команды не могли продолжаться, только заново переисполняться. Ну и в x86 можно найти ужасы, типа rep movsb. И ничего -- живут как-то, на "микрокоде" дешифруют и исполняют. Так что это плохой аргумент -- технические проблемы вполне решаемые для OoO.

То, что я говорю, это не техническая проблема, после того, как зафиксировали то, чего фиксировать не надо было.

68060 вышел в 1994, это уже был закат. Тут надо уточнить историю, возможно, они ввели несовместимое изменение, но уже опоздали. Факт то, что мозговой заклин на супер-CISC, когда его времена давно ушли, мог - и скорее всего он в первую очередь и погубил - не только m68k, но и другие архитектуры той разработки - в первую очередь VAX.

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

Мало. Считайте, один. Но на объективность это не влияет. У меня нет никакой повышенной любви к архитектуре x86 - можете погуглить, какими словами я её ругаю. Но то, что из-за меньшего количества CISC-like наворотов она оказалась более подготовленной к повороту в сторону OoO и RISC - чисто объективный факт, не признавать его нельзя.

Information

Rating
7,099-th
Location
Киев, Киевская обл., Украина
Date of birth
Registered
Activity