Процессоры в некоторой степени разработаны с учетом программного обеспечения, которое люди будут писать для него, неявно или явно.
Мне кажется, что если вы посмотрите на архитектуру набора команд, они очень «императивны» в том смысле, что каждая команда кодирует команду императивного стиля. Мне также кажется, что текущие архитектуры набора команд развивались частично в зависимости от типа кода, который создают программисты.
Если бы кто-то проектировал ЦП с нуля, зная, что он будет запускать только программы, написанные в функциональном стиле программирования, как этот ЦП будет отличаться от существующих ЦП?
Ответы:
На самом деле, это было сделано: https://en.wikipedia.org/wiki/Lisp_machine
Одним из аспектов проектирования ЦП для FP является сборка мусора. GC очень важен для функциональных языков. Обычные реализации требуют, чтобы GC мог различать указатели и данные без указателей. По сути, это означает сохранение дополнительного бита в ваших данных. По этой причине, например, целые числа OCaml являются только 31-разрядными на 32-разрядных архитектурах и 63-разрядными на 64-разрядных архитектурах. Затем целочисленная арифметика включает в себя неловкие дополнительные операции сдвига. Другие языки (или другие типы данных OCaml) могут тратить целые машинные слова на этот дополнительный бит, используя 128 бит для 64-битных целых чисел. Процессор, изначально разработанный для GC, может иметь 65-битную шину данных, но 64-битную арифметику.
Тем не менее, многие нефункциональные языки также имеют сборку мусора и, таким образом, выиграют от соответствующих архитектур.
Еще одна вещь, которая приходит на ум, заключается в том, что использование памяти FP обычно гораздо более разбросано, чем использование императивных программ. Главным образом потому, что это менее естественно использовать массивы. Как следствие, эти программы извлекают меньшую выгоду из кэширования смежных фрагментов памяти. Таким образом, процессор FP может использовать разные стратегии кэширования.
источник
Он либо ничего не изменит, либо использует массивные параллельные настройки, как в Reduceron и его преемнике PilGRIM 1 с огромным стеком.
Утверждение о том, что это ничего не изменит, поначалу кажется жирным, но поскольку процессор является последовательным, существует процесс перевода (компиляция), который использует доступное оборудование для своего расширения для повышения эффективности. Если бы существовала другая архитектура, некоторые операции были бы быстрее, некоторым потребовались бы хитрые трюки, чтобы ускорить ее.
Архитектура, которая будет иметь значение, потребует более быстрой работы карты и списков (не вся история, но достаточно, чтобы показать эффект). Невозможно создать динамически изменяемое оборудование для собственных списков, поэтому они хранятся в постоянной памяти. Мы придерживаемся представления массива некоторой формы. Для карты, чтобы работать в непоследовательном режиме - мы возвращаемся к Reduceron. Так эффективно одна центральная обработка для последовательных инструкций и поддержка параллельной обработки.
Что может отличаться - это возможность загружать несколько функций и запускать их без фокусировки кадров, но добавление нескольких модулей для функций может создать беспорядок с доступом к памяти.
Если добавить ответ Колена, GC будет полезен для работы в качестве сопроцессора, это будет очень удобная функция.
1: PilGRIM должным образом описан в Boeijink A., Hölzenspies PKF, Kuper J. (2011) Представляем PilGRIM: процессор для исполнения ленивых функциональных языков. В: Hage J., Morazán MT (eds) Реализация и применение функциональных языков. IFL 2010. Конспект лекций в области компьютерных наук, том 6647. Springer, Берлин, Гейдельберг .
источник
Сначала небольшая шутка: поскольку запуск 100% -ной функциональной программы никогда не может сделать ничего полезного, достаточно иметь только инструкцию NOP. (Я открываю это для пламенных войн).
Таким образом, потребуются некоторые обязательные инструкции для ввода-вывода и обычная поддержка императивного программирования.
В противном случае это частично зависит от используемого языка. Двое на вершине моего ума - Хаскелл и Эрланг.
Я полагаю, что Haskell мог бы извлечь выгоду из поддержки списков и карт. Список может поддерживаться определенным отображением памяти оборудования, превращая связанный список в последовательный набор адресов. Первый элемент может быть по адресу n, второй по адресу n + 1 и так далее. Чтобы удалить первый элемент из списка, вы просто измените указатель n. Наконец, при удалении указателя n вся память может быть освобождена. Карты могут поддерживаться как ассоциативные массивы - введите значение поиска, и система памяти вернет элемент. Нет необходимости в итеративных поисках.
Erlang, в свою очередь, может получить выгоду от поддержки сообщений / процессов и хвостовой рекурсии с полным состоянием. Сообщения и процессы могут поддерживаться различными способами, одним примером может быть чрезвычайно большое количество процессорных ядер. Хвостовая рекурсия может быть улучшена контроллером памяти, зная, что позволяет копировать состояние намного быстрее, возможно, не копируя большие порции данных, а просто изменяя указатели системы памяти.
источник