Здравствуйте, Евгений Музыченко, Вы писали:
N>>Что вы решили назвать тут флагом состояния?
ЕМ>Классический флаг состояния процессора, используемый с незапамятных времен.
Нет такого общего понятия. Есть много разных флагов, каждый со своим поведением.
N>>в знаковой интерпретации это нормально, а в беззнаковой это переполнение. Мы должны детектировать это переполнение?
ЕМ>Если у процессора в ходе выполнения программы возникает любая информация, которая с высокой вероятностью будет полезна этой программе, то да. Именно это и делает тот же x86 с флагами CF/OF, детектируя сразу обе ситуации.
Тему с накопительным поведением вы проигнорировали.
N>>Архитектура типа RISC-V намеренно лишена аналога Flags в x86.
ЕМ>И как, этим она существенно выигрывает у архитектур, где флаги есть?
Авторы считают, что отсутствие зависимости по скрытому значению — да, помогает в реализации. И она не одна такая. Вон MIPS ещё как минимум.
А теперь бинго — у x86 то же самое в векторных операциях... потому что не может быть одного флага результата на 4-8-16 разных операций впараллель
N>>Сложение, вычитание, умножение — они все требуют проверок
ЕМ>Именно так. Реализация этих проверок в топологии/микрокоде процессора всегда дешевле, чем в каждой из выполняемых на нем программ.
Ну и где они в x86?
N>>Мы можем добавлять JO или INTO после команды. Мы можем добавлять JC. Вопрос: почему нет парной к ней INTC?
ЕМ>Потому, что перенос очень часто является следствием нормального выполнения, и как-то специально его обрабатывать не требуется,
Нет здесь такой несимметричности.
N>>Есть один вариант решения: флагов нет, ставьте явные проверки по диапазонам и конкретным значениям, где нужно.
ЕМ>Это откровенно убогий вариант, как и возврат из функции единственного результата, некоторые значения которого резервируются под коды ошибок. Оправдывается только в случае крайней экономии ресурсов.
Ну где говорят про экономию ресурсов, а где про резкое облегчение дизайна за счёт отсутствия единого регистра флагов и за счёт этого лучшую параллельность.
Заметьте, Intel в своём проекте APX намеревается сделать то же самое.
N>>Я бы не против, если б SDIV ставила OF (как бы они ни звались) в случаях деления на 0 или MIN/-1.
ЕМ>Это было бы следуюшим по разумности вариантом при отказе от исключения.
Как раз более разумно, чем исключение
N>>вводить ещё и фолт для одного-единственного случая — точно явный и неуместный перекос.
ЕМ>Почему, если механизм исключений уже поддерживается аппаратурой?
EM> Порождать исключения для арифметических переполнений нет смысла, поскольку они очень часто возникают в совершенно нормальных, запланированных ситуациях.
Кажется, единственный вариант, при котором это возможно, это арифметика "по модулю". Назвать такое "очень часто" — это слишком сильная натяжка. От общего количества разных операций такого минимум и сконцентрированы они в некоторых совершенно конкретных областях: длинная арифметика, операции с кольцевыми счётчиками вроде seqnum в сетевых протоколах. А вот в, не побоюсь, 99% остальных если и кажется, что они есть, то это такие, в которых значение после переполнения проверяется на его выход за пределы ожидаемого множества. Например, в недавней дискуссии о роли беззнаковых — переход 0 -> ~0. А если не проверяется, а переполнение возможно, то код просто некорректен.
Уточню: я имею в виду вариант, когда тип значения обозначен. CF=1 при беззнаковом или OF=1 при знаковом.
EM> А вот в какой нормальной, запланированной ситуации могло бы возникнуть деление на нуль, результат которого можно было бы далее использовать без проверки?
Раз мы знаем, что "нормальных, запланированных" ситуаций с переполнениями почти нет, то уже нет тут никаких особых свойств деления. Некорректные входные данные дают некорректный результат, и если он распространяется на дальнейшую работу, то важно то, насколько рано (в идеале — сразу) ситуация поймана и опознана.
ЕМ>Это ж, по сути, то же самое, для чего вводились исключения в C++ — чтобы в ситуации, когда что-то пошло не так, не было риска забыть проверить возвращаемое значение в ситуации, когда не существует заведомо безопасного значения для нештатной ситуации.
Ну и почему на это плюют во всяких x86 для трёх операций из четырёх (это ещё и если не считать сдвиги за арифметику со степенью двойки, тогда окажется, что в 7 из 8)?
N>>Неужели не было уже понятно по опыту развития, что в этом нет смысла?
ЕМ>Тогда и в плюсовых исключениях тоже нет смысла. Не в их неправильном использовании, а в механизме, как твковом.
Передёргиваете. Я ясно сказал, что возможность проверки есть и там, где её применяют, проблема детектируется. Может, чуть заморочно.
ЕМ>>>Если же механизм исключений имеется, но решено отказаться от возбуждения исключения
N>>Механизм появляется вместе с более высокими уровнями реализации (в RISC-V). Но его принудительная ориентация на обработку в супервизоре избыточна.
ЕМ>Если команда деления может присутствовать в архитектуре, не поддерживающей обработку исключений, или возбуждение исключения может быть запрещено, то наиболее разумным решением будет использование флага состояния.
Да. Если он есть.
ЕМ>C — не язык "в себе". В C изначально закладывались на то, что исключения, если они есть в архитектуре, поддерживаются средой исполнения.
Ну предположим.
N>>Если где-то вы видите, например, обработчик SIGFPE (в который по POSIX мапится деление на 0, если трапается), то в нём всё равно нельзя без платформенно-специфичных средств вернуться на ту же команду.
ЕМ>Возможность вернуться и повторить — это уже определенная роскошь. Основной является возможность реагировать на нештатную ситуацию без явных проверок.
Тогда её нет с x86 для всего кроме деления — а там оно нужно сильно чаще, чем для деления.
Ситуацию незамеченного деления на 0 за весь свой опыт я видел только одну, а случаи проблем из-за непойманного переполнения при остальных трёх арифметических операциях — уже десятки.
N>>В языках-то оно есть. Возьмите какую-нибудь Ada и там всё будет под полным контролем.
ЕМ>А какой ценой?
Проверка каждого результата при укладке в целевую переменную, на её границы, плюс операций с базовым размером значения (как int и long в C) на переполнения. Не сильно большая цена за реальную безопасность.
N>>Лучше бы вспомнили историю ATA геометрий — она красочнее.
ЕМ>Там были хоть какие-то объективные основания — разрядности шин, регистров, стоимость тогдашних микросхем и т.п.
Все эти "разрядности" и "стоимости" это фактор ровно того же плана: суммарная цена решения.
N>>В общем же случае я думаю, что каждое расширение какого-то реального параметра в 2-3 раза приводит к наступанию на очередной предел.
ЕМ>Это как раз понятно. Непонятно стремление вводить константы вместо переменных, хотя в основе математики лежала противоположная идея.
Ну вот вы почему-то постановили, что константы разрядности в виде 32 и 64 они оправданны, а остальные — нет. А я могу вспомнить жалобы при переходе на S/360, что 32-битный float был заметно хуже 36-битного по свойствам. Последствия этого убрали только в IEEE754, и то по мнению некоторых недостаточно качественно. Надо было таки оставить разрядности типа 36 и 72?
EM>>>выбор константы в 2 Гб тоже был неудачным
N>>Он был 99.99% удачен. Остальных давно ждал 64-битный режим
ЕМ>Тогда выбор одного гигабайта вместо двух был бы "удачным на 99.95%". А выбор 512 Мб — "на 99.9%". А фишка в том, что увеличение этой вероятности до максимальной не стоило бы практически ничего, но в итоге цена получилась вполне ощутимой.
В том и дело, что увеличение выше 2GB реально стоило — мороки программистам и производительности ядру. Сплошная перекачка данных между буферами.
N>>Тогда на всём экономили.
ЕМ>В загрузчиках MBR/VBR — да. В загрузчике Win95 не было ни малейших причин экономить байты и такты.
Я уже ответил, что считаю, что причина в несогласовании между сотрудниками (отделами), а не в намеренной чрезмерной экономии.