Почему x86 ужасный? Почему это считают нижним по сравнению с другими? [закрытый]

101
задан Axalo 11 September 2017 в 23:48
поделиться

8 ответов

Пара возможных причин:

  1. x86 - это относительно старый ISA (в конце концов, его прародителями были 8086)
  2. x86 значительно эволюционировал несколько раз, но для поддержки требуется оборудование обратная совместимость со старыми двоичными файлами. Например, современное оборудование x86 по-прежнему поддерживает выполнение 16-битного кода изначально. Кроме того, существует несколько моделей адресации памяти, позволяющих более старому коду взаимодействовать с одним и тем же процессором, например, реальный режим, защищенный режим, виртуальный режим 8086 и длинный режим (amd64). Некоторых это может сбивать с толку.
  3. x86 - это машина CISC. В течение долгого времени это означало, что он был медленнее, чем RISC-машины, такие как MIPS или ARM, потому что инструкции имеют взаимозависимость данных и флаги , что затрудняет реализацию большинства форм параллелизма на уровне инструкций. Современные реализации переводят инструкции x86 в RISC-подобные инструкции, называемые « micro-ops », чтобы сделать эти виды оптимизаций практичными для аппаратной реализации.
  4. В чем-то x86 ничем не уступает, просто он другой. Например, ввод / вывод обрабатывается как отображение памяти на подавляющем большинстве архитектур, но не на x86.(Примечание: современные машины x86 обычно имеют ту или иную форму поддержки DMA и взаимодействуют с другим оборудованием через отображение памяти; но ISA по-прежнему имеет инструкции ввода-вывода, такие как IN и OUT )
  5. x86 ISA имеет очень мало архитектурных регистров, которые могут заставить программы проходить через память в оба конца чаще, чем это было бы в противном случае. Дополнительные инструкции, необходимые для этого, занимают ресурсы выполнения, которые можно было бы потратить на полезную работу, хотя эффективная переадресация хранилища поддерживает низкую задержку. Современные реализации с переименованием регистров в большой физический регистровый файл могут поддерживать множество инструкций в полете, но отсутствие архитектурных регистров по-прежнему было значительным недостатком 32-разрядной архитектуры x86. Увеличение числа регистров x86-64 с 8 до 16 целочисленных и векторных регистров является одним из важнейших факторов того, что 64-битный код быстрее 32-битного (наряду с более эффективным ABI с вызовом регистров), а не увеличением ширины каждого регистра. Некоторым может помочь дальнейшее увеличение с 16 до 32 целочисленных регистров, но не в такой степени. (AVX512 действительно увеличивается до 32 векторных регистров, поскольку код с плавающей запятой имеет большую задержку и часто требует больше констант.) ( см. Комментарий )
  6. Ассемблерный код x86 сложен, потому что x86 - сложная архитектура. со многими функциями. Список инструкций для типичной машины MIPS умещается на листе бумаги размером с одну букву.Эквивалентный список для x86 занимает несколько страниц, а инструкции просто делают больше, поэтому вам часто требуется более подробное объяснение того, что они делают, чем может дать листинг. Например, инструкции MOVSB ​​ требуется относительно большой блок кода C для описания того, что она делает:

     if (DF == 0) 
     * (byte *) DI ++ = * (байт *) SI ++; 
    else 
     * (byte *) DI-- = * (byte *) SI -; 
     

    Это одна инструкция, выполняющая загрузку, сохранение и две добавляет или вычитает (управляется вводом флага), каждая из которых будет отдельными инструкциями на RISC-машине.

    Хотя простота MIPS (и подобных архитектур) не обязательно делает их лучше, для обучения введению в класс ассемблера имеет смысл начать с более простого ISA . Некоторые классы сборки учат ультра-упрощенное подмножество x86, называемое y86 , которое упрощено до такой степени, что бесполезно для реального использования (например, без инструкций сдвига), или некоторые учат только базовым инструкциям x86.

  7. В x86 используются коды операций переменной длины, которые усложняют аппаратное обеспечение синтаксического анализа инструкций. В современную эпоху эта стоимость становится исчезающе маленькой, поскольку процессоры становятся все более и более ограниченными пропускной способностью памяти, чем необработанными вычислениями, но многие статьи и мнения о «битве x86» исходят из эпохи, когда эта стоимость была сравнительно намного выше.
    Обновление 2016 г .: Anandtech опубликовал обсуждение размеров кода операции для x64 и AArch64 .

РЕДАКТИРОВАТЬ: Это не должно быть bash x86! участник.У меня не было другого выбора, кроме как нанести некоторый удар, учитывая формулировку вопроса. Но за исключением (1), все это было сделано по уважительным причинам (см. Комментарии). Дизайнеры Intel не глупы - они хотели чего-то добиться с помощью своей архитектуры, и это лишь некоторые из налогов, которые им пришлось заплатить, чтобы воплотить эти вещи в жизнь.

89
ответ дан 24 November 2019 в 04:42
поделиться

Я не эксперт, но кажется, что Многие функции, которые не нравятся людям, могут быть причиной того, что он хорошо работает. Несколько лет назад наличие регистров (вместо стека), регистровых фреймов и т. Д. Считалось хорошим решением, позволяющим сделать архитектуру более простой для людей. Однако в настоящее время важна производительность кеша, и слова переменной длины x86 позволяют хранить в кеше больше инструкций. «Декодирование инструкций», на которое, как я полагаю, указали оппоненты, когда-то занимало половину чипа, уже не совсем так.

Я думаю, что параллелизм - один из наиболее важных факторов в настоящее время - по крайней мере, для алгоритмов, которые уже работают достаточно быстро, чтобы их можно было использовать.Выражение высокого параллелизма в программном обеспечении позволяет оборудованию амортизировать (или часто полностью скрывать) задержки памяти. Конечно, более далекое будущее архитектуры, вероятно, связано с чем-то вроде квантовых вычислений.

Я слышал от nVidia, что одна из ошибок Intel заключалась в том, что они хранили двоичные форматы близко к оборудованию. PTX CUDA выполняет некоторые быстрые вычисления использования регистров (раскрашивание графиков), поэтому nVidia может использовать регистровую машину вместо стековой, но все же имеет путь обновления, который не нарушает все старое программное обеспечение.

3
ответ дан 24 November 2019 в 04:42
поделиться

Помимо уже упомянутых причин:

  • x86-16 имел довольно странную схему адресации памяти , которая допускала единственную память местоположение можно адресовать до 4096 различными способами, ограничить ОЗУ до 1 МБ и вынудить программистов иметь дело с двумя разными размерами указателей. К счастью, переход на 32-битную архитектуру сделал эту функцию ненужной, но чипы x86 по-прежнему несут в себе хлам сегментных регистров.
  • Хотя это и не является ошибкой x86 как таковой , соглашения о вызовах x86 не были стандартизированы, как MIPS (в основном потому, что MS-DOS не поставлялась с какими-либо компиляторами), что оставило нас с беспорядком __ cdecl , __ stdcall , __ fastcall и т. Д.
3
ответ дан 24 November 2019 в 04:42
поделиться

Язык ассемблера x86 не так уж и плох. Когда вы дойдете до машинного кода, он начинает становиться действительно уродливым. Кодирование инструкций, режимы адресации и т. Д. Намного сложнее, чем для большинства процессоров RISC. И для целей обратной совместимости встроено дополнительное развлечение - вещи, которые срабатывают только тогда, когда процессор находится в определенном состоянии.

Например, в 16-битных режимах адресация может показаться совершенно необычной; есть режим адресации для [BX + SI] , но не для [AX + BX] . Подобные вещи, как правило, усложняют использование регистров, так как вам нужно убедиться, что ваше значение находится в регистре, который вы можете использовать по мере необходимости.

(К счастью, 32-битный режим намного разумнее (хотя иногда сам по себе все еще немного странный - например, сегментация), а 16-битный код x86 больше не актуален за пределами загрузчиков и некоторых встроенных сред.)

Есть также остатки былых времен, когда Intel пыталась сделать x86 лучшим процессором. Инструкции длиной в пару байтов, которые выполняли задачи, которые на самом деле больше никто не выполняет, потому что они были, откровенно говоря, слишком медленными или сложными. Инструкции ENTER и LOOP , для двух примеров - обратите внимание, что код кадра стека C похож на «push ebp; mov ebp, esp», а не «enter» для большинства компиляторов.

8
ответ дан 24 November 2019 в 04:42
поделиться

Архитектура x86 восходит к дизайну микропроцессора 8008 и его родственников. Эти процессоры были разработаны в то время, когда память была медленной, и если бы вы могли сделать это на кристалле ЦП, он часто был намного быстрее. Однако место на кристалле ЦП также было дорогим. Эти две причины заключаются в том, что существует лишь небольшое количество регистров, которые, как правило, имеют специальное назначение, и сложный набор инструкций со всевозможными подводными камнями и ограничениями.

Другие процессоры той же эпохи (например, семейство 6502) также имеют аналогичные ограничения и особенности. Интересно, что и серия 8008, и серия 6502 предназначались как встраиваемые контроллеры. Даже тогда ожидалось, что встроенные контроллеры будут программироваться на ассемблере и во многом ориентированы на программиста на ассемблере, а не на автора компилятора. (Посмотрите на микросхему VAX, чтобы узнать, что происходит, когда вы обслуживаете компилятор.) Разработчики не ожидали, что они станут вычислительными платформами общего назначения; вот для чего были нужны вещи, подобные предшественникам архива POWER. Революция домашних компьютеров, конечно, изменила это.

20
ответ дан 24 November 2019 в 04:42
поделиться

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

Например, большинство инструкций сложения и вычитания целых чисел x86 изменяют регистр флагов.После выполнения сложения или вычитания следующей операцией часто является просмотр регистра флагов на предмет переполнения, бит знака и т. Д. Если после этого есть еще одно добавление, очень сложно определить, безопасно ли начинать выполнение второго сложения. до того, как станет известен результат 1-го добавления.

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

Микросхема DEC Alpha AXP, выполненная в стиле RISC в стиле MIPS, была болезненно спартанской в ​​доступных инструкциях, но набор инструкций был разработан таким образом, чтобы избежать неявных зависимостей регистров между инструкциями. Не было аппаратного регистра стека. Регистр аппаратно определяемых флагов отсутствовал. Даже указатель инструкции был определен ОС - если вы хотели вернуться к вызывающей стороне, вам нужно было решить, как вызывающая сторона собиралась сообщить вам, по какому адресу вернуться. Обычно это определялось соглашением о вызовах ОС. Однако на x86 это определяется аппаратным обеспечением чипа.

Так или иначе, в течение 3 или 4 поколений микросхем Alpha AXP аппаратное обеспечение превратилось из буквальной реализации спартанского набора команд с 32 регистрами int и 32 регистрами с плавающей запятой в механизм массового неупорядоченного выполнения с 80 внутренними регистрами, переименование регистров, пересылка результатов (где результат предыдущей инструкции пересылается более поздней инструкции, которая зависит от значения) и всевозможные дикие и сумасшедшие бустеры производительности. И несмотря на все эти навороты, кристалл чипа AXP все еще был значительно меньше, чем сопоставимый кристалл чипа Pentium того времени, а AXP был чертовски быстрее.

Вы не увидите такого рода всплесков повышения производительности в генеалогическом дереве x86 в основном потому, что сложность набора инструкций x86 делает многие виды оптимизации выполнения непомерно дорогими, если не невозможными. Гениальный ход Intel заключался в отказе от реализации набора инструкций x86 на оборудовании - все современные чипы x86 на самом деле являются ядрами RISC, которые в определенной степени интерпретируют инструкции x86, переводя их во внутренний микрокод, сохраняющий всю семантику исходного x86. инструкция, но допускает небольшую часть этого неупорядоченного RISC и другие оптимизации микрокода.

Я написал много ассемблера x86 и могу полностью оценить удобство его корней CISC. Но я не полностью осознавал, насколько сложна x86, пока не потратил некоторое время на написание ассемблера Alpha AXP. Я был потрясен простотой и единообразием AXP. Различия огромны и глубоки.

25
ответ дан 24 November 2019 в 04:42
поделиться

Я думаю, вы получите часть ответа, если когда-нибудь попытаетесь написать компилятор, ориентированный на x86, или если вы напишете эмулятор машины x86, или даже если вы попытаетесь реализовать ISA в конструкции оборудования.

Хотя я понимаю, что «x86 - это некрасиво!» аргументы, я все еще думаю забавнее писать сборку x86, чем MIPS (например) - последнее просто утомительно. Это всегда должно было быть приятным для компиляторов, а не для людей. Я не уверен, что микросхема могла бы быть более враждебной по отношению к разработчикам компиляторов, если бы попыталась ...

Самая уродливая часть для меня - это способ (в реальном режиме) работы сегментации - что любой физический адрес имеет 4096 псевдонимов сегмент: смещение. Когда в последний раз вам это было нужно ? Все было бы намного проще, если бы сегментная часть была строго старшими битами 32-битного адреса.

3
ответ дан 24 November 2019 в 04:42
поделиться
  1. x86 имеет очень, очень ограниченный набор регистров общего назначения

  2. , он продвигает очень неэффективный стиль разработки на самом низком уровне (ад CISC) вместо эффективной методологии загрузки / сохранения

  3. Intel приняла ужасающее решение ввести явно глупую модель адресации сегмента / смещения памяти, чтобы оставаться совместимой с (уже сейчас!) устаревшей технологией

  4. В то время, когда все переходили на 32-битную версию, x86 сдерживал массовый мир ПК, будучи скудным 16-битный (большинство из них - 8088 - даже только с 8-битными внешними путями данных, что еще страшнее!) CPU


Для меня (и я ветеран DOS, который видел каждое поколение ПК с перспектива разработчиков!) пункт 3. был худшим.

Представьте себе следующую ситуацию, которая была у нас в начале 90-х (мейнстрим!):

а) Операционная система, которая имела безумные ограничения по устаревшим причинам (640 КБ легкодоступной ОЗУ) - DOS

б) Операционная система расширение (Windows), которое могло бы делать больше с точки зрения ОЗУ, но было ограничено, когда дело касалось таких вещей, как игры и т. д., и было не самым стабильным на Земле (к счастью, позже это изменилось, но я говорю о здесь начало 90-х)

c) Большая часть программного обеспечения все еще была DOS, и нам часто приходилось создавать загрузочные диски для специального программного обеспечения, потому что там был EMM386.exe, что некоторым программам нравилось, а другим не нравилось (особенно геймеры - а я в то время был геймером AVID - знаю, о чем я здесь говорю)

г) Мы были ограничены битами MCGA 320x200x8 (хорошо, было немного еще со специальными приемами, 360x480x8 было возможно, но только без поддержки библиотеки времени выполнения), все остальное было беспорядочно и ужасно ("VESA" - смеется)

e) Но с точки зрения оборудования у нас были 32-битные машины с довольно большим количеством мегабайт карт RAM и VGA с поддержкой до 1024x768

Причина плохой ситуации?

Простое дизайнерское решение Intel. Совместимость уровня машинных инструкций (НЕ двоичного уровня!) С чем-то, что уже умирало, я думаю, это был 8085. Другие, казалось бы, не связанные проблемы (графические режимы и т. Д.) Были связаны по техническим причинам и из-за очень узкой Платформа x86 принесла с собой продуманную архитектуру.

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

1
ответ дан 24 November 2019 в 04:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: