Экзотические архитектуры, о которых заботятся комитеты по стандартам

154

Я знаю, что стандарты C и C ++ оставляют многие аспекты языка, определенные реализацией, просто потому, что если существует архитектура с другими характеристиками, было бы очень трудно или невозможно написать для нее стандартный соответствующий компилятор.

Я знаю, что 40 лет назад у любого компьютера была своя уникальная спецификация. Однако я не знаю ни одной архитектуры, используемой сегодня, где:

  • CHAR_BIT != 8
  • signed это не дополнение к двум (я слышал, у Java были проблемы с этим).
  • Плавающая точка не соответствует IEEE 754 (Правка: я имел в виду «не в двоичном кодировании IEEE 754»).

Причина, по которой я спрашиваю, состоит в том, что я часто объясняю людям, что хорошо, что C ++ не требует никаких других низкоуровневых аспектов, таких как типы фиксированного размера . Это хорошо, потому что в отличие от «других языков» он делает ваш код переносимым при правильном использовании (Edit: потому что он может быть перенесен на большее количество архитектур, не требуя эмуляции низкоуровневых аспектов машины, таких как, например, арифметика двух дополнений в архитектуре знак + величина) , Но мне плохо, что я сам не могу указать на какую-то конкретную архитектуру.

Таким образом, вопрос заключается в следующем: какие архитектуры обладают вышеуказанными свойствами?

† не uint*_tявляются обязательными.

Яков Галка
источник
9
Я думаю, что у вас есть это задом наперед. Если бы C ++ требовал, скажем, дополнения до двух для целых чисел со знаком, это сделало бы код C ++ более переносимым, а не меньше. Вопрос о том, почему комитет по стандартам C ++ не предписывает это, - другой вопрос. Тем более что, несмотря на то, что вы говорите, было бы невозможно написать компилятор для нестандартной архитектуры, вы всегда можете смоделировать 8-битные символы или арифметику с двумя дополнениями, даже если ваша платформа не поддерживает ее напрямую.
Джон
8
@john: тогда это было бы непрактично, поэтому нестандартный компилятор, отвечающий требованиям, генерировал бы более быстрый код, чем соответствующий. И я до сих пор не понимаю, как это делает ваш код более переносимым.
Яков Галка
4
Я уверен, что настоящая причина того, что стандарт таков, не в том, что это какое-то идеальное решение. Но вместо этого это потому, что когда был написан стандарт, многие компиляторы C и C ++ уже существовали, и комитет по стандартам не хотел отклонять существующие компиляторы.
Джон
4
@john: Я сомневаюсь, что «облегчение для авторов компиляторов» является приоритетом при создании стандарта C ++ (если бы это было так, они бы сделали ужасную работу, поскольку C ++ - один из самых сложных для анализа языков, а также другие аспекты язык не совсем облегчает работу разработчиков компиляторов). Производительность, широкая поддержка платформ и обратная совместимость очень важны. И все эти три пострадают, если упомянутое вами ограничение будет добавлено к стандарту.
Сандер Де Дайкер
5
Дело не в компиляторе, а в аппаратном обеспечении. C ++ оставляет некоторые вещи неуказанными, чтобы разрешить прямое использование аппаратных функций. Ваши телефонные приложения в любом случае не будут работать на мэйнфрейме, поэтому нет никакой переносимости, какой бы совместимый код ни был.
Бо Перссон

Ответы:

114

Взгляни на этот

Серверы Unisys ClearPath Dorado

предлагая обратную совместимость для людей, которые еще не перенесли все свое программное обеспечение Univac.

Ключевые моменты:

  • 36-битные слова
  • CHAR_BIT == 9
  • свое дополнение
  • 72-битная не-IEEE с плавающей точкой
  • отдельное адресное пространство для кода и данных
  • слово-имя
  • нет выделенного указателя стека

Не знаю, предлагают ли они компилятор C ++, но могли бы .


И теперь появилась ссылка на недавний выпуск их руководства по Си:

Справочное руководство по программированию компилятора Unisys C

Раздел 4.5 содержит таблицу типов данных с 9, 18, 36 и 72 битами.

размер и диапазон типов данных в компиляторе USC C

Бо Перссон
источник
13
Я думаю, void * должно быть адским для использования в этой архитектуре.
luiscubal
13
@ybungalobill - я считаю, char*и void*должен быть того же размера, и достаточно большим, чтобы вместить любой другой указатель. Остальное до реализации.
Бо Перссон
22
@ybungalobill: На старых компиляторах Win16 обычные указатели были рядом с указателями и содержали только 16-битное смещение, поэтому sizeof(int*) == 2, но дальние указатели также имели 16-битный селектор, так что sizeof(void*) == 4.
Адам Розенфилд
10
Существует или было онлайн руководство для их компилятора C ++. Стоит также отметить, что это всего лишь одна из архитектур мэйнфреймов Unisys: другая - это архитектура с теговой величиной 48 битов со знаком (для которой я нашел только руководство на C, а не на C ++). Что касается остального: я не думаю, что sizeof(int*) != sizeof(char*)здесь: оба 36 бит. Но селектор байтов в char*находится в старших разрядах и игнорируется в int*. (Однако я использовал другие машины, где `sizeof (char *)> sizeof (int *).)
Джеймс Канз
16
@ Adam Rosenfield В 16-битных компиляторах MS / DOS у вас были разные «режимы», и указатели данных не обязательно были того же размера, что и указатели на функции. Но по крайней мере на тех, которые я использовал, все указатели данных (включая void*) всегда имели одинаковый размер. (Конечно, вы не можете преобразовать указатель на функцию void*, поскольку она void*может быть меньше. Но в соответствии со стандартом, вы не можете сделать это и сегодня.)
Джеймс Канз
51

Ни одно из ваших предположений не относится к мэйнфреймам. Для начала, я не знаю мэйнфрейма, который использует IEEE 754: IBM использует базовую 16 с плавающей запятой, а оба мейнфрейма Unisys используют базовую 8. Машины Unisys немного особенные во многих других отношениях: Бо упомянул 2200 архитектура, но архитектура MPS еще более странная: 48-битные слова с тегами. (Является ли слово указателем или нет, зависит от бита в слове.) И числовые представления составлены таким образом, что нет реального различия между плавающей точкой и интегральной арифметикой: с плавающей точкой - основание 8; он не требует нормализации и, в отличие от любой другой плавающей запятой, которую я видел, ставит десятичную дробь справа от мантиссы, а не слева, и использует знаменательную величину для показателя степени (в дополнение к мантиссе). С результатами, что интегральное значение с плавающей запятой имеет (или может иметь) точно такое же битовое представление как целое число со знаком. И нет никаких арифметических инструкций с плавающей запятой: если показатели двух значений равны 0, инструкция выполняет интегральную арифметику, в противном случае она выполняет арифметику с плавающей запятой. (Продолжение философии тегирования в архитектуре.)int может занимать 48 бит, 8 из них должны быть 0, иначе значение не будет рассматриваться как целое число.

Джеймс Канзе
источник
4
Мэйнфреймы IBM (z / Architecture) поддерживают IEE754 с плавающей запятой.
Никита Немкин
1
К вашему сведению этот комментарий в твиттере
Shafik Yaghmour
6
@ Никита - Они делают сейчас . Изначально это было (дорогое) дополнение для поддержки Java.
Бо Перссон
42

Полное соответствие IEEE 754 редко встречается в реализациях с плавающей запятой. И ослабление спецификации в этом отношении позволяет много оптимизаций.

Например, поддержка subnorm отличается между x87 и SSE.

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

Или на x86 строгое соответствие IEEE может потребовать установки определенных флагов или дополнительных передач между регистрами с плавающей запятой и обычной памятью, чтобы заставить его использовать указанный тип с плавающей запятой вместо своих внутренних 80-битных операций с плавающей запятой.

А некоторые платформы вообще не имеют аппаратного обеспечения и поэтому должны эмулировать их в программном обеспечении. И некоторые из требований IEEE 754 могут быть дорогостоящими для реализации в программном обеспечении. В частности, могут быть проблемы с правилами округления.

Мой вывод заключается в том, что вам не нужны экзотические архитектуры для того, чтобы попасть в ситуации, когда вы не всегда хотите гарантировать строгое соответствие IEEE. По этой причине было мало языков программирования, гарантирующих строгое соответствие IEEE.

CodesInChaos
источник
7
Другой «экзотический» набор аппаратного обеспечения - это мэйнфреймы IBM, где формат с плавающей запятой предшествует стандарту IEEE. В отличие от Java, C ++ все еще может использовать существующее оборудование.
Бо Перссон
5
IEEE 754 не полностью поддерживается графическими процессорами.
Керем
3
Отсутствие строгого соответствия стандарту IEEE 754 беспокоит некоторых, но я не думаю, что оно входит в сферу проблем, которые действительно волнуют ФП.
Всезнающий
3
@Matthieu Так как это также помечено как «C», я должен упомянуть C-анализатор, который может сообщить вам все значения, которые ваша программа может принимать с 80-битными регистрами с плавающей запятой, разлитыми в память по прихоти компилятора C. blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Паскаль Куок
2
@MatthieuM .: Жаль, что ISO / ANSI не позволяли переменным параметрам указывать минимальный / максимальный размер для аргументов с плавающей точкой и целых чисел; если бы они имели, 80-разрядный long doubleмог бы быть полезным и долгоживущим типом, поскольку единственной реальной проблемой было то, что он плохо работает printf. Тот факт, что расширенный double хранит ведущий 1, явно ускоряет вычисления в системах без FPU, а также устраняет необходимость в специальной обработке денормалов в любом контексте, кроме преобразований в / из других типов. Жаль, что С все printfиспортил.
суперкат
40

Я нашел эту ссылку, где перечислены некоторые системы, где CHAR_BIT != 8. Они включают

некоторые TI DSP имеют CHAR_BIT == 16

Чип BlueCore-5 (Bluetooth-чип от Cambridge Silicon Radio), который имеет CHAR_BIT == 16.

И, конечно же, возникает вопрос о переполнении стека: на каких платформах есть что-то кроме 8-битного символа

Что касается систем, отличных от двух, есть интересное чтение на comp.lang.c ++. Moderated . Подводя итог: есть платформы, имеющие свое дополнение или знак и представление величины.

DCN
источник
5
Аналоговые устройства 32-битный SHARC DSP имеет CHAR_BIT=32, и Texas Instruments DSP от TMS32F28xx имеет CHAR_BIT=16. GCC 3.2 для PDP-10 имеет CHAR_BIT=9. Я думаю, у S / 360 тоже может быть не 8-битный символ.
osgx
1
Я все еще хотел бы привести пример архитектуры «non two'splement». Тем более что CHAR_BITSэто частичный дубликат.
Яков Галка
TSP DSP имеют 16-битные символы только потому, что разработчики выбрали его (было бы немного больше работы, чтобы заставить его работать правильно, но не до абсурда - IIRC - возможно, просто некоторые "дыры" в скаффолдинге codegen в базовом компиляторе) , Так что это не какая-то глубокая архитектурная причина. C-код работает на абстрактной машине. Если все, что у вас есть, это 16-битные INT, сохраните по два символа в каждом и добавьте слияние чтения-изменения-записи в оптимизатор глазка (как минимум). Конечно, это больше работы, но просто посмотрите на то, сколько работы для каждого приходится иметь дело с такими странными типами в местах, где они никогда не появятся. Тьфу.
Восстановить Монику
24

Я уверен, что системы 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.

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

Кит Томпсон
источник
6
В заключение следует отметить, что чрезмерно строгие стандарты препятствуют инновациям. Когда мы получим квантовые (или органические) компьютеры с тройными состояниями, арифметические требования по модулю для unsignedцелочисленных типов будут основной болью, в то время как знаковая арифметика будет в порядке.
Бен Фойгт
@BenVoigt Почему эта беззнаковая арифметика - боль? Разве сумматоры по модулю 3 ^ n на этих компьютерах невозможны?
phuclv
2
@ LưuVĩnhPhúc: В том-то и дело, что с аппаратными операциями, выполняемыми по модулю 3 ** n, предоставление C ++ беззнаковых типов, чьи операции определены по модулю 2 ** n, будет затруднено.
Бен Фойгт
2
Мне известен один VAX 11/780, который все еще используется в качестве хоста для кросс-компилятора, предназначенного для специализированной встроенной системы с проприетарной архитектурой. Чтобы выдержать этот конкретный VAX, хранители обращались в музеи за запчастями.
Питер
2
@Keith - технически, единственным препятствием является процесс предоставления доказательств, которые будут соответствовать нормативным требованиям, поскольку целевая встроенная система имеет высокую критичность. Однако существует множество нетехнических препятствий (организационная политика и т. Д.), Которые на сегодняшний день являются непреодолимыми. В настоящее время проще навести порядок в музеях, чем обновлять хост.
Питер
16

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ведьма также отключает сохранение знака для нулей).

ivaigult
источник
3
проголосовал за простое указание OP взглянуть на источник популярного компилятора; это определение RFTM в данном случае, поэтому люди должны смотреть в первую очередь.
underscore_d
9

До недавнего времени двоичное представление IEEE 754 было необычным для графических процессоров, см. Паранойя с плавающей запятой для графических процессоров .

РЕДАКТИРОВАТЬ: в комментариях был поднят вопрос, относится ли с плавающей запятой GPU к обычному компьютерному программированию, не связанному с графикой. Да, черт возьми! Самые высокопроизводительные вычисления, производимые сегодня, выполняются на графических процессорах; список включает AI, интеллектуальный анализ данных, нейронные сети, физическое моделирование, прогноз погоды и многое другое. Одна из ссылок в комментариях показывает почему: преимущество графических процессоров с плавающей запятой на порядок .

Я хотел бы добавить еще одну вещь, которая более актуальна для вопроса OP: что люди делали 10-15 лет назад, когда плавающая точка GPU не была IEEE, и когда не было таких API, как сегодняшние OpenCL или CUDA, для программирования GPU? Хотите верьте, хотите нет, но первые пионеры вычислений на GPU сумели программировать GPU без API, чтобы сделать это ! Я встретил одного из них в моей компании. Вот что он сделал: он кодировал данные, необходимые для вычисления, в виде изображения с пикселями, представляющими значения, над которыми он работал, а затем использовал OpenGL для выполнения необходимых операций (таких как «размытие по Гауссу» для представления свертки с нормальным распределением). и т. д.) и декодировал полученное изображение обратно в массив результатов. И это все же было быстрее, чем при использовании процессора!

Именно это побудило NVidia наконец-то сделать свои двоичные данные внутренними, совместимыми с IEEE и представить API, ориентированный на вычисления, а не на манипуляции с изображениями.

Майкл
источник
Насколько актуальны графические процессоры? (а) Эта страница выглядит очень устаревшей. (b) До сегодняшнего дня вы не можете программировать графические процессоры на C: потому что C поддерживает такие вещи, как рекурсивные функции, которые, насколько мне известно, не поддерживаются графическими процессорами. Так что вы даже не можете написать компилятор, если хотите.
Яков Галка
1
@ybungalobill, разгрузка повторяющихся работ в GPU в настоящее время является предпочтительным методом для крупномасштабных вычислений . На самом деле, я сейчас разрабатываю один на C ++. К счастью, мы работаем только с графическими процессорами NVidia CUDA, которые имеют совместимое с IEEE 754 двоичное представление чисел с плавающей точкой.
Майкл,
Я не говорю, что GPU не используются для GP-вычислений. Я сказал, что вы не программируете ядра на C, несмотря на сходство синтаксиса. Вы можете выполнить int f(int n) { return n <= 1 ? 1 : n * f(n-1); }в CUDA? Если нет, то графические процессоры не имеют отношения к этому вопросу (который касается комитетов C и C ++).
Яков Галка
6
@ybungalobill: несколько ответов на это. Во-первых, CUDA поддерживает C, C ++ и Fortran . См. Ту же ссылку для получения огромного преимущества производительности 2048-потоковых графических процессоров по сравнению с обычным 8-поточным процессором. Во-вторых, правда, поддерживаются только подмножества (хотя и большие) этих языков, включая отсутствие поддержки соответствующей рекурсии модели программирования CUDA (называемой «динамический параллелизм») до CUDA 5.0. В-третьих, рекурсии обычно могут быть заменены циклами, которые в любом случае необходимы для многопоточной работы.
Майкл