Здравствуйте, Евгений Музыченко, Вы писали:
N>>Решили, что ситуация некорректности операции деления не заслуживает того, чтобы (по крайней мере в базовом ISA) требовать для этого механизм исключений. ЕМ>Если вопрос в том, чтобы вовсе не иметь в реализации механизма исключений, то это вполне разумно. Но тогда разумно ввести соответствующий флаг состояния, по аналогии с переполнением, а не возвращать результат, который, не будучи специально проверен, почти гарантированно наделает бед. Когда такое решение приходит в одну больную голову, это еще можно понять, но когда оно принимается коллегиально, это уже что-то запредельное.
Что вы решили назвать тут флагом состояния?
Вот, например, самая первая операция, которую рассматривают — сложение. Пусть у нас байтовые параметры. Сложив 0x01 и 0xFF, мы получаем 0x00. Но в знаковой интерпретации это нормально, а в беззнаковой это переполнение. Мы должны детектировать это переполнение? Если да, как выглядит этот "флаг состояния"?
Архитектура типа RISC-V намеренно лишена аналога Flags в x86. Даже не как в ARM, где у большинства команд этой группы можно управлять, есть там флаги или нет. Не знаю, насколько правильно в самом глобальном смысле это решение само по себе. Но если оно сделано, то явная проверка требуется не только на деление. Сложение, вычитание, умножение — они все требуют проверок на валидность результата, не был ли он усечён (после чего об его корректности вообще нет смысла говорить, лучше считать тупо мусором). В чём особенность тут одного деления по сравнению с остальными?
Пусть у нас теперь есть Flags в варианте, например, как в x86. Все операции ставят флаги. Мы можем добавлять JO или INTO после команды. Мы можем добавлять JC. Вопрос: почему нет парной к ней INTC?
(Да, я буду регулярно сравнивать с x86. Это "а у вас негров линчуют", я заранее согласен.)
Есть один вариант решения: флагов нет, ставьте явные проверки по диапазонам и конкретным значениям, где нужно. Есть другой: флаги есть, можно реагировать на них. Тут уже вопрос, кто и что как ставит. Я бы не против, если б SDIV ставила OF (как бы они ни звались) в случаях деления на 0 или MIN/-1. Но вводить ещё и фолт для одного-единственного случая — точно явный и неуместный перекос. Когда это сделали в S/360, там было понятно — откровенно пионерная архитектура. Когда это сделали в 8086 через 14 лет — зачем это было? Неужели не было уже понятно по опыту развития, что в этом нет смысла?
Кстати, я ни в одной архитектуре кроме POWER не видел "накопительного" флага переполнения, и то там есть такой только для знакового. А обычные надо проверять после каждой операции.
ЕМ>Если же механизм исключений имеется, но решено отказаться от возбуждения исключения, то это непонятно вообще.
Механизм появляется вместе с более высокими уровнями реализации (в RISC-V). Но его принудительная ориентация на обработку в супервизоре избыточна.
N>>Если команда не делает исключения, то надо вернуть какое-то осмысленное значение в качестве частного. Варианты — ближайшее к бесконечности с нужной стороны (лучше всего), просто ближайшее к бесконечности, ноль, что-то иное.
ЕМ>Значение, ближайшее к бесконечности, можно считать осмысленным только для деления с плавающей точкой. Для деления с фиксированной оно, наоборот, абсурдно.
И опять же. Сложили 0x01 и 0xFF в беззнаковом контексте, получили 0 вместо 0x100. Не заметили, пошли дальше, нарвались на что-то и приветъ. Будем трапаться на таком или нет? Я согласен только на универсальный подход, потому что в упор не вижу, чем деление тут должно быть таким особенным.
N>>Если бы деление на ноль вызывало исключение, то для внедрителей языков была бы дополнительная забота взаимодействия со сложным механизмом (traps) вместо простого (одна проверочная команда там, где это нужно). ЕМ>И какова вероятность того, что в языке, реализованном для архитектуры, мало-мальски сложной (имеющей тот же диспетчер памяти), вообще не будут поддерживаться механизмы исключений?
Да вообще-то на таком уровне ровно 100%. В C нет никаких исключений. Если где-то вы видите, например, обработчик SIGFPE (в который по POSIX мапится деление на 0, если трапается), то в нём всё равно нельзя без платформенно-специфичных средств вернуться на ту же команду. Максимум это через siglongjmp() вернуться на какую-то заранее придуманную контрольную точку. Если речь про Windows, то SEH это тоже не элемент языка, а расширение для конкретной платформы.
ЕМ>Если уж они решили одновременно и упростить, и унифицировать, и оставить возможность масштабирования, то единственно правильное решение — это устанавливать флаг состояния. При наличии механизма исключений можно было бы добавить возбуждение исключения, как и для переполнения при умножении.
Да, такое определено в IEEE754. Там накопительные флаги и возможность управления ими. А теперь покажите мне такое в x86 или SystemZ (где деление на 0 трапается) такие накопительные флаги?
N>>А какая связь? Сам по себе механизм защиты памяти уже системный и требует настройки. ЕМ>Связь такая, что у программы должна быть возможность получать информацию о нештатных ситуациях при ее выполнении. Когда процессор эту информацию имеет, но не отдает, либо отдает в неадекватном виде, это требует экстраординарных оснований. Такие основания есть?
Отлично, жду ваших оснований для отсутствия накопительных флагов переполнения в x86.
ЕМ>И что конструктивного я мог бы сказать по поводу отсутствия в языках даже самых простых в реализации средств контроля исполнения? Я действительно не знаю, почему в индустрии преобладает стремление внедрять свистоперделки, порой достаточно дорогие в реализации, но упорно избегать внедрения дешевых и эффективных средств.
В языках-то оно есть. Возьмите какую-нибудь Ada и там всё будет под полным контролем.
N>>всё, что вы хотите, это чтобы Чен явно сказал "это была наша ошибка"? И если бы он сказал, вы бы вообще не подняли тему? ЕМ>Да, именно так. Он высказался в стиле "у нас все было правильно, просто никто не ожидал".
Не вижу в его словах такого акцента.
N>>Тогда это как минимум оффтопик для данного подфорума. ЕМ>Это был лишь очередной пример проблемы, к которой привел произвольный выбор фиксированной константы.
Лучше бы вспомнили историю ATA геометрий — она красочнее. В общем же случае я думаю, что каждое расширение какого-то реального параметра в 2-3 раза приводит к наступанию на очередной предел.
EM> И ведь того, что выбор константы в 2 Гб тоже был неудачным, они тоже не признают.
Он был 99.99% удачен. Остальных давно ждал 64-битный режим. На это я уже отвечал.
N>>Ни у кого нет бесконечного количества ресурсов на разработку и учёт всего.
ЕМ>Да ладно бы такая ошибка была в сколько-нибудь объемном коде, с неочевидными зависимостями, которые трудно проследить в уме. Но в достаточно компактном коде загрузчика, который заполняет массив фиксированного размера, отсутствие адекватных действий при переполнении должно было насторожить.
Тогда на всём экономили.
Вон загрузчик MS-DOS где-то аж до версии 5 должен был получать io.sys первым в корневом каталоге, иначе беда. А всё потому, что решили, что нефиг в FAT даже на винче выдать десяток секторов на более умный промежуточный читатель FS. В котором из FAT это стало обязательным? Чуть ли не в 32м.
Про саму проблему трёх областей видимости (20, 32 и 64 бита адреса) уже и не вспоминаю, там и сейчас есть где плясать часами на костях.
N>>вы ввели тут уже сильно позже исходного сообщения какую-то необходимость извиняться ЕМ>Не извиняться, а признавать свои ошибки.
Этому вообще весь блог посвящён в целом. "Old new thing" — о древностях, замшелостях и откуда они такие растут. Каждая из них это какая-то ошибка, отсталость, влияние древнего ограничения или просто недосмотр.