Экзотические архитектуры, о которых заботятся комитеты по стандартам
Я знаю, что стандарты C и C++ оставляют многие аспекты языка, определяемые реализацией, просто потому, что если существует архитектура с другими характеристиками, было бы очень трудно или невозможно написать стандартный соответствующий компилятор.
Я знаю, что 40 лет назад у любого компьютера была своя уникальная спецификация. Однако я не знаю ни одной архитектуры, используемой сегодня, где:
CHAR_BIT != 8
signed
это не дополнение к двум (я слышал, у Java были проблемы с этим).- Плавающая точка не соответствует IEEE 754 (Правка: я имел в виду "не в двоичном кодировании IEEE 754").
Причина, по которой я спрашиваю, состоит в том, что я часто объясняю людям, что хорошо, что C++ не требует никаких других низкоуровневых аспектов, таких как типы фиксированного размера†. Это хорошо, потому что, в отличие от "других языков", он делает ваш код переносимым при правильном использовании (Edit: потому что он может быть перенесен на большее количество архитектур, не требуя эмуляции низкоуровневых аспектов машины, таких как, например, арифметика двух дополнений в архитектуре знак + величина), Но мне плохо, что я сам не могу указать на какую-то конкретную архитектуру.
Таким образом, вопрос заключается в следующем: какие архитектуры обладают вышеуказанными свойствами?
† uint*_t
с не являются обязательными.
7 ответов
Взгляни на этот
Серверы Unisys ClearPath Dorado
предлагая обратную совместимость для людей, которые еще не перенесли все свое программное обеспечение Univac.
Ключевые моменты:
- 36-битные слова
CHAR_BIT == 9
- свое дополнение
- 72-битная не-IEEE с плавающей точкой
- отдельное адресное пространство для кода и данных
- слово-имя
- нет выделенного указателя стека
Не знаю, предлагают ли они компилятор C++, но могли бы.
И теперь появилась ссылка на недавний выпуск их руководства по Си:
Справочное руководство по программированию компилятора Unisys C
Раздел 4.5 содержит таблицу типов данных с 9, 18, 36 и 72 битами.
Ни одно из ваших предположений не относится к мэйнфреймам. Для начала, я не знаю мэйнфрейма, который использует IEEE 754: IBM использует базовую 16 с плавающей запятой, а оба мейнфрейма Unisys используют базовую 8. Машины Unisys немного особенные во многих других отношениях: Бо упомянул 2200 архитектура, но архитектура MPS еще более странная: 48-битные слова с тегами.
(Является ли слово указателем или нет, зависит от бита в слове.) И числовые представления составлены таким образом, что нет реального различия между плавающей точкой и целочисленной арифметикой: с плавающей точкой - основание 8; он не требует нормализации и, в отличие от любой другой плавающей запятой, которую я видел, ставит десятичную дробь справа от мантиссы, а не слева, и использует знаменательную величину для показателя степени (в дополнение к мантиссе). С результатами, что интегральное значение с плавающей запятой имеет (или может иметь) точно такое же битовое представление, что и целое число со знаком. И нет никаких арифметических инструкций с плавающей запятой: если показатели двух значений равны 0, инструкция выполняет интегральную арифметику, в противном случае она выполняет арифметику с плавающей запятой.
(Продолжение философии тегирования в архитектуре.) Что означает, что пока int
может занимать 48 бит, 8 из них должны быть 0, иначе значение не будет рассматриваться как целое число.
Я нашел эту ссылку со списком некоторых систем, где CHAR_BIT != 8
, Они включают
некоторые TI DSP имеют
CHAR_BIT == 16
Чип BlueCore-5 (Bluetooth-чип от Cambridge Silicon Radio), который имеет
CHAR_BIT == 16
,
И, конечно же, возникает вопрос о переполнении стека: на каких платформах есть что-то кроме 8-битных символов
Что касается систем, не являющихся дополнениями к двум, есть интересное чтение на модерируемом comp.lang.C++. Подводя итог: есть платформы, имеющие свое дополнение или знак и представление величины.
Полное соответствие IEEE 754 редко встречается в реализациях с плавающей запятой. И ослабление спецификации в этом отношении позволяет много оптимизаций.
Например, поддержка subnorm отличается между x87 и SSE.
Оптимизации, такие как объединение умножения и сложения, которые были отдельными в исходном коде, также немного изменяют результаты, но это хорошая оптимизация для некоторых архитектур.
Или на x86 строгое соответствие IEEE может потребовать установки определенных флагов или дополнительных передач между регистрами с плавающей запятой и обычной памятью, чтобы заставить его использовать указанный тип с плавающей запятой вместо своих внутренних 80-битных операций с плавающей запятой.
А некоторые платформы вообще не имеют аппаратного обеспечения и поэтому должны эмулировать их в программном обеспечении. А некоторые требования IEEE 754 могут быть дорогостоящими для реализации в программном обеспечении. В частности, могут быть проблемы с правилами округления.
Мой вывод заключается в том, что вам не нужны экзотические архитектуры, чтобы попасть в ситуации, когда вы не всегда хотите гарантировать строгое соответствие IEEE. По этой причине было мало языков программирования, гарантирующих строгое соответствие IEEE.
Я уверен, что системы VAX все еще используются. Они не поддерживают IEEE с плавающей точкой; они используют свои собственные форматы. Alpha поддерживает форматы с плавающей точкой VAX и IEEE.
Векторные машины Cray, такие как T90, также имеют свой собственный формат с плавающей запятой, хотя в более новых системах Cray используется IEEE. (T90, который я использовал, был выведен из эксплуатации несколько лет назад; я не знаю, находятся ли еще в активном использовании.)
T90 также имел / имеет некоторые интересные представления для указателей и целых чисел. Собственный адрес может указывать только на 64-битное слово. Компиляторы C и C++ имели CHAR_BIT==8 (необходимо, потому что он запускал Unicos, разновидность Unix и должен был взаимодействовать с другими системами), но собственный адрес мог указывать только на 64-битное слово. Все операции на уровне байтов были синтезированы компилятором, и void*
или же char*
хранится смещение байта в старших 3 битах слова. И я думаю, что у некоторых целочисленных типов были биты заполнения.
Мэйнфреймы IBM являются еще одним примером.
С другой стороны, эти конкретные системы не обязательно должны исключать изменения в языковом стандарте. Cray не проявил особого интереса к обновлению своего компилятора C до C99; предположительно то же самое применимо к компилятору C++. Возможно, было бы разумно ужесточить требования к размещенным реализациям, таким как требование CHAR_BIT==8, с плавающей запятой формата IEEE, если не полная семантика, и дополнение 2 без дополнительных битов для целых чисел со знаком. Старые системы могли продолжать поддерживать более ранние языковые стандарты (C90 не умер, когда вышел C99), и требования могли быть более свободными для автономных реализаций (встроенных систем), таких как DSP.
С другой стороны, у будущих систем могут быть веские причины делать то, что сегодня считается экзотикой.
CHAR_BITS
Согласно исходному коду gcc:
CHAR_BIT
является 16
биты для 1750a, архитектуры dsp16xx.CHAR_BIT
является 24
биты для архитектуры dsp56k.CHAR_BIT
является 32
биты для архитектуры c4x.
Вы можете легко найти больше, выполнив:
find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"
или же
find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"
если CHAR_TYPE_SIZE
правильно определен.
Соответствие IEEE 754
Если целевая архитектура не поддерживает инструкции с плавающей запятой, gcc может генерировать программный резерв, который по умолчанию не соответствует стандарту. Более чем, специальные опции (например, -funsafe-math-optimizations
Ведьма также отключает сохранение знака для нулей).
До недавнего времени двоичное представление IEEE 754 было необычным для графических процессоров, см. Паранойя с плавающей запятой для графических процессоров.
РЕДАКТИРОВАТЬ: вопрос был поднят в комментариях, относится ли с плавающей запятой GPU к обычному компьютерному программированию, не связанному с графикой. Да, черт возьми! Самые высокопроизводительные вычисления, производимые сегодня, выполняются на графических процессорах; список включает AI, интеллектуальный анализ данных, нейронные сети, физическое моделирование, прогноз погоды и многое другое. Одна из ссылок в комментариях показывает почему: преимущество графических процессоров с плавающей запятой на порядок.
Я хотел бы добавить еще одну вещь, которая более актуальна для вопроса OP: что делали люди 10-15 лет назад, когда плавающая точка GPU не была IEEE и когда не было API, такого как OpenCL или CUDA для программирования GPU? Хотите верьте, хотите нет, но первые пионеры вычислений на GPU смогли программировать GPU без API для этого! Я встретил одного из них в моей компании. Вот что он сделал: он кодировал данные, необходимые для вычисления, в виде изображения с пикселями, представляющими значения, над которыми он работал, затем использовал OpenGL для выполнения необходимых операций (таких как "размытие по Гауссу", чтобы представить свертку с нормальным распределением). и т. д.) и декодировал полученное изображение обратно в массив результатов. И это все еще было быстрее, чем при использовании процессора!
Именно это побудило NVidia наконец-то сделать свои двоичные данные внутренними, совместимыми с IEEE и представить API, ориентированный на вычисления, а не на манипуляции с изображениями.