Изначально я написала этот документ несколько лет назад, будучи инженером по проверке ядра исполнения команд (execution core verification engineer) в ARM. Конечно, на моё мнение повлияла углублённая работа с исполнительными ядрами разных процессоров. Так что делайте на это скидку, пожалуйста: может, я слишком категорична.

Однако я по-прежнему считаю, что создатели RISC-V могли справиться гораздо лучше. С другой стороны, если бы я сегодня проектировала 32-или 64-разрядный процессор, то, вероятно, реализовала бы именно такую архитектуру, чтобы воспользоваться существующим инструментарием.

Статья изначально описывала набор команд RISC-V 2.0. Для версии 2.2 в ней сделаны некоторые обновления.

Оригинальное предисловие: немного личного мнения


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

Например, вот код C:

int readidx(int *p, size_t idx)
{ return p[idx]; }

Это простой случай индексирования массива, очень распространённая операция. Так выглядит компиляция для x86_64:

mov eax, [rdi+rsi*4]
ret

или ARM:

ldr r0, [r0, r1, lsl #2]
bx lr // return

Однако для RISC-V необходим такой код:

slli a1, a1, 2
add a0, a1, a1
lw a0, a0, 0
jalr r0, r1, 0 // return

Симплификация RISC-V упрощает декодер (т. е. фронтенд CPU) за счёт выполнения большего количества инструкций. Но масштабирование ширины конвейера — сложная проблема, в то время как декодирование слегка (или сильно) нерегулярных инструкций хорошо реализуется (основная трудность возникает, когда трудно определить длину инструкции: это особенно проявляется в наборе команд x86 с многочисленными префиксами).

Упрощение набора инструкций не следует доводить до предела. Сложение регистра и регистра со сдвигом регистровой памяти — несложная и очень распространённая инструкция в программах, а процессору очень легко её эффективно реализовать. Если процессор не способен реализовать инструкцию напрямую, то может относительно легко разбить её на составляющие; это гораздо более простая проблема, чем слияние последовательностей простых операций.

Мы должны отличать «сложные» специфические инструкции CISC-процессоров — усложнённые, редко используемые и малооэффективные инструкции — от «функциональных» инструкций, общих для процессоров CISC и RISC, которые объединяют небольшую последовательность операций. Последние используются часто и с высокой производительностью.

Посредственная реализация


  • Почти неограниченная расширяемость. Хотя это и является целью RISC-V, но это создаёт фрагментированную, несовместимую экосистему, которой придётся управлять с особой осторожностью
  • Одна и та же инструкция (JALR) используется и для вызовов, и для возвратов и для косвенно-регистровых переходов (register-indirect branches), где требуется дополнительное декодирование для предсказания ветвей
    • Вызов: Rd = R1
    • Возврат: Rd = R0, Rs = R1
    • Косвенный переход: Rd = R0, Rs ? R1
    • (Странный переход: Rd ? R0, Rd ? R1)
  • Кодирование с переменной длиной поля записи не самосинхронизируется (такое часто встречается — например, аналогичная проблема у x86 и Thumb-2, — но это вызывает различные проблемы как с реализацией, так и с безопасностью, например, возвратно-ориентированное программирование, то есть атаки ROP)
  • RV64I требует расширения знака для всех 32-разрядных значений. Это приводит к тому, что верхнюю половину 64-битных регистров становится невозможно использовать для хранения промежуточных результатов, что ведёт к ненужному специальному размещению верхней половины регистров. Более оптимально использовать расширение нулями (поскольку оно уменьшает число переключений и обычно его можно оптимизировать путём отслеживания «нулевого» бита, когда верхняя половина, как известно, равна нулю)
  • Умножение опционально. Хотя быстрые блоки перемножения могут занимать довольно существенную площадь на крошечных кристаллах, но всегда можно использовать чуть более медленные схемы, которые активно используют существующий ALU для многократных циклов умножения.
  • У LR/SC строгое требование к поступательному продвижению для ограниченного подмножества применений. Хотя это ограничение довольно жёсткое, оно потенциально создаёт некоторые проблемы для небольших реализаций (особенно без кэша)
    • Это кажется заменой инструкции CAS, см. комментарий ниже
  • Биты закрепления в памяти (sticky bits) FP и режим округления находятся в одном регистре. Это требует сериализации канала FP, если выполняется операция RMW для изменения режима округления
  • Инструкции FP кодируются для 32, 64 и 128-битной точности, но не 16-битной (что значительно чаще встречается в аппаратном обеспечении, чем 128 бит)
    • Это можно легко исправить: кодирование 2'b10 бесплатно
    • Обновление: в версии 2.2 появился десятичный заполнитель, но нет заполнителя половинной точности. Уму непостижимо.
  • То, как значения FP представлены в файле регистра FP, не определено, но наблюдаемо (через load/store)
    • Авторы эмуляторов вас возненавидят
    • Миграция виртуальных машин может стать невозможной
    • Обновление: версия 2.2 требует более широких значений NaN-boxing

Плохо


  • Отсутствуют коды условий, а вместо них используются инструкции compare-and-branch. Это не проблема сама по себе, но последствия неприятные:
    • Уменьшение пространства кодирования в условных переходах из-за необходимости кодирования одного или двух спецификаторов регистров
    • Нет условного выбора (полезно для очень непредсказуемых переходов)
    • Нет сложения с переносом / вычитания с переносом или заимствованием
    • (Обратите внимание, что это всё равно лучше, чем наборы команд, которые пишут флаги в регистр общего назначения, а затем переходят на полученные флаги)
  • Высокоточные счётчики только кажутся, будто они требуются на уровне пользователя ISA. На практике, предоставление их приложениям является отличным вектором для атак по сторонним каналам
  • Умножение и деление являются частью одного и того же расширения, и кажется, что если одно реализовано, то и другое тоже должно быть. Умножение значительно проще, чем деление, и распространено на большинстве процессоров, а деление нет
  • Нет атомарных инструкций в базовой архитектуре набора команд. Всё более распространёнными становятся многоядерные микроконтроллеры, так что атомарные инструкции типа LL/SC обходятся недорого (для минимальной реализации в рамках единого [многоядерного] процессора нужен всего 1 бит состояния процессора)
  • LR/SC находятся в том же расширении, что и более сложные атомарные инструкции, что ограничивает гибкость для небольших реализаций
  • Общие атомарные инструкции (не LR/SC) не включают примитив CAS
    • Смысл в том, чтобы избежать необходимости в инструкции, которая читает пять регистров (Addr, CmpHi:CmpLo, SwapHi:SwapLo), но это, вероятно, наложит меньше накладных расходов на реализацию, чем гарантированное продвижение вперёд LR/SC, которое предоставляется в качестве замены
  • Предлагаются атомарные инструкции, которые работают на 32-разрядных и 64-разрядных величинах, но не 8-ми или 16-битных
  • Для RV32I нет способа передать значение DP FP между целым числом и регистровым файлом FP, кроме как через память, то есть из 32-битных целочисленных регистров нельзя составить 64-битное число двойной точности с плавающей точкой, придётся сначала записать промежуточное значение в память и загрузить его в регистровый файл оттуда
  • Например, у 32-битной инструкция ADD в RV32I и 64-битной ADD в RVI64 одинаковые кодировки, а в RVI64 добавляется ещё и другая кодировка ADD.W. Это ненужное усложнение для процессора, который реализует обе инструкции — было бы предпочтительнее вместо этого добавить новую 64-битную кодировку.
  • Нет инструкции MOV. Мнемокод команды MV транслируется ассемблером в инструкцию MV rD, rS-->ADDI rD, rS, 0. Высокопроизводительные процессоры обычно и так оптимизируют инструкции MOV, широко задействуя при этом переупорядочивание команд. В качестве канонической формы команды MV в RISC-V была выбрана инструкция с непосредственным 12-битовым операндом.
    • При отсутствии MOV инструкция ADD rD, rS, r0 фактически становится предпочтительнее канонической MOV, поскольку её проще декодировать, а операции с нулевым регисторм (r0) в CPU обычно оптимизированы

Ужасно


  • JAL тратит 5 бит на кодирование регистра связи, который всегда равен R1 (или R0 для переходов)
    • Это означает, что RV32I использует 21-битные смещения ветвей (branch displacement). Это недостаточно для больших приложений — например, веб-браузеров — без использования нескольких последовательностей команд и/или «островов ветвей» (branch islands)
    • Это ухудшение по сравнению с версией 1.0 архитектуры команд!
  • Несмотря на большие усилия на равномерное кодирование, инструкции load/store кодируются по-разному (меняются регистр и непосредственные поля)
    • Видимо, ортогональность кодирования выходного регистра была предпочтительнее ортогональности кодирования двух сильно связанных инструкций. Этот выбор кажется немного странным, учитывая, что генерация адресов более критична по времени
  • Нет команд загрузки из памяти со смещениями регистров (Rbase+Roffset) или индексов (Rbase+Rindex << Scale).
  • FENCE.I подразумевает полную синхронизацию кэша инструкций со всеми предыдущими хранилищами, с ограждением (fenced) или без него. Реализациям нужно или очищать весь I$ на ограждении, или выискивать D$ и накопительный буфер (store buffer)
  • В RV32I чтение 64-битных счётчиков требует двукратного чтения верхней половины, сравнения и ветвления в случае переноса между нижней и верхней половиной во время операции чтения
    • Обычно 32-разрядные ISA включают в себя инструкцию «чтение пары специальных регистров», чтобы избежать этой проблемы
  • Нет архитектурно определённого пространства hint-кодирования, так чтобы инструкции из этого пространства не вызывали ошибку на старых процессорах (обрабатывались как NOP), но что-то делали на самых современных CPU
    • Типичные примеры чистых «хинтов NOP» — такие вещи, как spinlock yield
    • На новых процессорах также реализованы более сложные хинты (с видимыми побочными эффектами на новых процессорах; например, инструкции проверки границ x86 кодируются в hint-пространстве, так что бинарники остаются обратно совместимыми)

Комментарии (50)


  1. zuborg
    29.07.2019 22:14
    -6

    Процессоры с крайне минималистичными наборами инструкций никогда не смогут сравняться производительностью со сложными процессорами, где целые последовательности вычислений реализованы на железном уровне. Т.е. с точки зрения эффективности RISC-V уже в проигрышном положении.
    Также непонятно, какой будет выигрыш с точки зрения энергопотребления, если для выполнения одной и той же работы надо будет выполнить в разы больше инструкций — можно понизить частоту на CISC до эквивалентного уровня производительности и тоже получить холодный процессор.


    1. VaalKIA
      29.07.2019 22:27
      +4

      Нет, меньше инструкций — больше переиспользование транзисторов: один и тот же набор выполняет кучу CISC инструкций, соотвественно, там где у CISC холодные блоки, простаивают и ждут своей уникальной инструкции, в RISC добавляют ядра/конвееры. Плюс к этому, за счёт коротких инструкций дискретность выше: там где у CISC длинные сложные схемы и низкие частоты (это не говорит о низкой производительности) выравнивание до границы такта съедает больше времени, чем вытягивание до границы такта более высокочастотной схемы (это как посекундная и поминутная тарификация). На практике, в эпоху тёмного кремния и близкого предела к границе частот — всё не так однозначно.


      1. creker
        30.07.2019 00:14
        -2

        Все эти идеалы всего лишь идеалы. CISC поголовно суперскалярные out of order процессоры. Там нечему простаивать. Маленькие инструкции RISC делают только хуже — у тебя всегда будет много мелких инструкции и быстрее их выполнять так просто не получится. Напротив, CISC инструкцию каждую можно засунуть в железо и именно так поступают в x86 процессорах. Вся эта экономия на транзисторах хороша, где бюджеты маленькие. RISC-V наверное тут вполне сгодится, но пост о том, что сделать что-то большее скорее всего не получится именно из-за ISA. Туда же миф о том, что сложные инструкции сложно декодировать, поэтому давайте тут сэкономим лучше. Декодер это мизерная часть современного процессора, которая не представляет никаких сложностей давно.


        1. VaalKIA
          30.07.2019 00:26
          +2

          x86 это RISC процессор с микропрограммой, соглашусь с вами «именно так поступают в x86 процессорах». Последний CISC x86, это был процессор от Cyrix.

          Маленькие инструкции RISC делают только хуже

          Нет, благодаря маленьким инструкциям возможна параллельная обработка и нет границ цисковых комманд, в итоге у CISC любая инструкция не меньше 1 такта, а в RISC цисковые комманды могут занимать и 0.5 такта в потоке и любые дробные значения, что было очень неплохой маркетинговой фишкей во времена Пентиумов.

          Вы плаваете в терминологии и железе.

          P.S. Про все новомодные AVX — не владею темой, но это уже и не x86, строго говоря, даже 64bit, это уже AMD64 архитектура. Фактически, современные процессоры, это SystemOnChip, там и видео ускорители и DSP и контроллеры памяти, нейронные ускорители и т.п. Если вы разные блоки плюсуете к x86, тогда почему АPU целиком не называть x86?


        1. checkpoint
          30.07.2019 00:47

          Декодер это мизерная часть современного процессора, которая не представляет никаких сложностей давно

          Мне кажется это сомнительное утверждение. В последнее время часто встречаются статью в которых пытаются либо разгромить либо расхвалить RISC-V, но авторы и тех и других согласны в одном — декодер (точнее — блок предсказания) современных CISC процессоров мало того, что заниемает много места на кристалле, так его сложность перестала быть управляемой. Вспомните Spectre и Meltdown. В этом смысле VLIW — архитектура почти без декодера, где всё планирование выполняет компилятор.

          Ну и по мне, отсутствие оптимизирующего компилятора это решаемая, со временем, проблема не требующая аппаратных изменений.


          1. bagamut
            30.07.2019 19:31

            Процессоры Itanium, EPIC и VLIW умерли по нескольким причинам, говорит Паттерсон:

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

            Пожалуй, самый известный в мире специалист по компьютерным алгоритмам Дональд Кнут заметил: «Подход Itanium… казался таким великолепным — пока не выяснилось, что желанные компиляторы по сути невозможно написать».
            habr.com/ru/post/411989


            1. checkpoint
              30.07.2019 21:02

              Пожалуй, самый известный в мире специалист по компьютерным алгоритмам Дональд Кнут заметил: «Подход Itanium… казался таким великолепным — пока не выяснилось, что желанные компиляторы по сути невозможно написать»


              Itanium умер так и не родившись почти 20 лет назад. С тех пор прогресс шагнул вперед довольно сильно. Если неполучается сделать предсказатель на четкой логике, значит нужно сделать его на нейросетях — обучаемым под конкретное приложение (в этой отрасли сейчас програсс скачет семимильными шагами). Оптимизирующий компилятор под VLIW (Эльбрус), кстати, написан и работает весьма не плохо. Так, что товарищу Кнуту пора бы уже перестать будоражить сознание молодых и горячих :-).


              1. bagamut
                30.07.2019 21:58
                +1

                Itanium умер в 2017 году, и для него тоже был написан компилятор в полном соответствии с прогрессом. И этот компилятор хорошо хорошо работал только на задачах, что и так хорошо работают на обычном CPU c SIMD, а еще лучше работают на GPU. Точно так же работает и компилятор Эльбруса, при теоретической 21 параллельно исполняемой операции среднее число в реальности 2-3 операции, и максимум 5-10 на счетных задачах с векторами.


            1. gnomeby
              30.07.2019 21:25

              Инженеры МЦСТ, смотрят на ваш коментарий с недоумением. А затем продолжают каждый год выпускать компилятор, который всё повышает и повышает быстродействие уже выпущенного железа.


              1. bagamut
                30.07.2019 23:28
                +2

                Инженеры Intel, смотрят на ваш комментарий с недоумением. Они точно также написали компилятор и каждый год все повышали и повышали. А потом оказалось что обычные Xeon дешевле, быстрее и компиляторы для них лучше, многоядерность гораздо универсальнее, а Itanium никогда достигнет их ожиданий. И GPU справляются еще лучше с теми задачами для которых он предназначался.


                1. checkpoint
                  31.07.2019 01:35
                  +1

                  Помоему Интел просто убил конкурента внутри себя. Чисто маркетинговое решение, не имеющее отношение к технологии.

                  Есть еще один момент. Интел заложник своего x86 ISA — везде и всюду нужно обеспечивать совместимость вниз. Выкатив на рынок Itanium, который мог исполнять x86 только в режиме эмуляции (или b2b компиляции) ни к чему доброму привести не могло — с экономической точки зрения.


                  1. bagamut
                    31.07.2019 02:39

                    С продажами в несколько десятков тысяч в год против миллионов x86-64 никаким конкурентом Itanium не являлся. С такими продажами улучшать его технологии было слишком дорого и не имело никакого смысла. И Itanium стал просто технологически отставать от массовых x86-64.

                    Есть другой момент. Выкатив на рынок Itanium, который мог в эмуляции исполнять PA-RISC и MIPS, и которые заменил, а так же заменил и Alpha. И вроде бы все это вело к добру с экономической точки, но что то пошло не так.


                1. gnomeby
                  31.07.2019 10:25
                  +1

                  У инженеров Itanium всё-таки была другая задача — убить рынок x86 и разорить AMD. По сути стать монополистом в сфере 64-х бит. Как только стало понятно, что ничего из запланированного не будет достигнуто, проект закопали.
                  У инженеров МЦСТ задача — обеспечить приемлемую производительность и стратегическую безопасность в рамках импортозамещения. И они со всеми пунктами справляются.


                  1. bagamut
                    31.07.2019 18:23

                    Intel не собиралась терять рынок x86. Проект Itanium как раз по сговору закопал всех прочих конкурентов — PA-RISC, MIPS, Alpha. И в свою очередь проиграл более дешевым и чаще обновляемым х86. Они же практически закопали и SPARC c PowerPC.


      1. zuborg
        30.07.2019 15:46

        На практике, в эпоху тёмного кремния и близкого предела к границе частот — всё не так однозначно.
        Я и не говорю что все однозначно ;) Свои плюсы есть у разных подходов. Просто RISC-V, вместо того, чтобы сделать однозначно лучшую архитектуру, достиг всего лишь уровня «не все однозначно».
        Что касается «больше ядер/конвееров» — вот в GPU много ядер, и они даже весьма универсальные — но их используют только для специализированных вычислений, а не в качестве ядер процессоров общего назначения.
        Дискретность выше, и частоты потенциальные выше, но!.. Вы правда полагаете, что сможете вычислить раунд AES быстрее на RISC-V, чем это сделает AES-NI? Да никогда в жизни. Согласен, это грубый пример, но принцип общий — если для CISC в кремнии есть специализированная логика для быстрого вычисления rdi+rsi*4, то на RISC это надо программировать! Это как сравнить нативное исполнение сложной инструкции с эмуляцией микрокодом — микрокоду кремний не догнать, как ни крути.


        1. checkpoint
          30.07.2019 22:11

          если для CISC в кремнии есть специализированная логика для быстрого вычисления rdi+rsi*4, то на RISC это надо программировать! Это как сравнить нативное исполнение сложной инструкции с эмуляцией микрокодом — микрокоду кремний не догнать, как ни крути


          Дык в том то весь прикол, что современный CISC это обертка для RISC + микропрограммы. Нет в интелловских процессорах куска кремния (выделенной транзисторной схемы) для rdi+rsi*4, есть микропрограмма из пары десятков микрокомманд исполняемых на скрытом от пользователя (программиста) RISC ядре (или нескольких ядрах).


          1. zuborg
            01.08.2019 13:28

            Конкретно в данном случае, думаю, Вы ошибаетесь. Операция смещения (умножения на 4) настолько дешева в аппаратной реализации, что нет никакого смысла (речь про высокопроизводительные процессоры, а не сверхэкономичные решения) выполнять вычисление rdi+rsi*4 микрокодом за несколько тактов, когда этот адрес можно легко вычислить за один (такт) прямой аппаратной реализацией.


            1. checkpoint
              01.08.2019 13:54

              Помимо чисто арифметической операции там есть масса вспомогательных uops. Вот цитата из Wikipedia про микрокод:

              Microprograms consist of series of microinstructions, which control the CPU at a very fundamental level of hardware circuitry. For example, a single typical horizontal microinstruction might specify the following operations:

              Connect register 1 to the A side of the ALU
              Connect register 7 to the B side of the ALU
              Set the ALU to perform two's-complement addition
              Set the ALU's carry input to zero
              Store the result value in register 8
              Update the condition codes from the ALU status flags (negative, zero, overflow, and carry)
              Microjump to microPC nnn for the next microinstruction


              Так, что приведенная вами rdi+rsi*4 может выйти в не один десяток uops. К сожалению, Интел не разглашает подробности реализации x86 ISA.

              Ну и что бы совсем не было сомнений, в статье Intel Microcode пишут, что начиная с P6 (конец 90-х) во всех процессорах Intel микрокод может быть пропатчен. А значит аппаратной реализации инструкции rdi+rsi*4 нет, есть набор микропрограмм, состоящих из примитивных операций (uops). Как тут уже многократно отмечалось, все интелловские процессоры это своего рода RISC с нахлабученой сверху x86 ISA.

              Вот еще цитата из той же Вики:
              In the P6 and later microarchitectures, lists of x86 instructions are internally converted into simpler RISC-style micro-operations


              1. Kabdim
                02.08.2019 16:05

                Имхо из-за названия микрокоманды вы неверно ставите их почти тождественными по значению просто командам, но это не совсем так. Эти микрокоманды ближе по логике действия к установке значения на конкретных шинах. Точно такая же микрокоманда может включать сложнейший блок явно являющейся элементом CISC архитектуры и этот способ запуска не сделает её RISC'ом.


        1. checkpoint
          30.07.2019 22:14

          Кстати, по поводу GPU. В Википедии пишут:

          Nvidia plans to use RISC-V to replace their Falcon processor on their GeForce graphics cards

          И дана ссылка на NVIDIA RISC V Evaluation Story


          1. zuborg
            31.07.2019 15:18

            Микроконтроллер видяхи? Так там и ARM или x86 можно поставить, если будет економический смысл, но к вычислительным ядрам GPU это вообще никакого отношения не имеет.


        1. mpa4b
          30.07.2019 22:38

          Раунды AES опасно вычислять на процессорах без аппаратной поддержки AES (типа той же AES-NI)… Каждый лукап в таблицу по секретному индексу — потенциальная утечка и цель для timing attack (из-за кешей). Есть конечно программный AES без таблиц, в виде bit-slicing, но там вынужденно приходится считать сразу много блоков подряд и во весь рост встаёт вычисление мультипликативной инверсии (SubBytes() в AES) без таблиц.


    1. checkpoint
      29.07.2019 23:31
      +1

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


      1. creker
        30.07.2019 00:09

        Современные процессоры не RISC. С каждым поколением x86 все больше «сложных» инструкций превращаются из нескольких микроопсов в одну, т.е. полная железная реализация. И в этом как раз сакральный смысл CISC архитектуры, возможность подобной оптимизации. «x86 внутри на самом деле RISC» популярный миф, который не имеет ничего общего с реальностью.

        RISC подход это устаревшая парадигма, которая выглядела красиво на бумаге, но на деле не работает. RISC-V полагается на то, что не работает. Компиляторы не умеют оптимизировать RISC код. RISC-V полагается на то, что компилятор будет генерировать такой код, который потом легко будет пользоваться microops fusion. Мало того, что компиляторы не умеют эффективно генерировать такой код и это банально ставит палки в колеса оптимизатору, т.к. ему надо думать в рамках того, что потом процессор мог склеить инструкции, так еще процессоры тоже не умеют это делать.

        Собственно, в этом весь пост. Вместо того, чтобы перенять весь опыт процессоростроения, RISC-V построен на устаревших понятиях о том, какой должна быть ISA, что делает, по сути, невозможным построение высокопроизводительного процессора. Весь современный опыт говорит, что современная высокопроизводительная ISA должна как раз иметь кучу специализированных инструкций. Это именно то, что компиляторы отлично умеют использовать. А дальше пусть работает out of order исполнение, предсказания и прочая магия. Если почитать, именно таковой является та же ARMv8, которую все хвалят. И от RISC идеалов там ушли довольно сильно.


        1. checkpoint
          30.07.2019 01:51

          А дальше пусть работает out of order исполнение, предсказания и прочая магия.

          Меня лично вот эта «магия» сильно смущает. Я бы предпочел минималистичный ISA, а всю магию вынести в компилятор. Изменения в компиляторе, при определенном опыте, доступны программисту, а «магия» под покровом CISC — нет.

          Вообще, в RISC я вижу одну серьезную проблему, которая почти не раскрыта в статье — большой обьём кода (видимо подразумевается, что читателю и так все понятно). Производительность процессоров сейчас во многом ограничена пропускной способностью шин: внутренних, ведущих к кэш памяти и внешних — к RAM. В этом смысле СISC архитектура выигрывает потому, что в одну инструкцию упаковывается больше «полезной работы», а значит меньше кода нужно передавать по шинам. Разработчики ARM даже отказались от своего стандартного набора команд и полностью перешли на укороченный (по размеру) набор инструкций Thumb в том числе и для того, что бы повысить эффективность исполняемого кода — небольшие по размеру команды выполняющие сразу много операций, даже SIMD утолкали. Некоторые коментаторы предлагают сжимать код алгоритмами сжатия данных (привет LZW), передавать его в таком виде по шинам и разжимать только в дешифраторе. Звучит бредово, но пока шина является узким местом — это действительно может сработать. И именно из-за этого CISC, по производительности, скорее всего будет выигрывать еще долгое время.

          Еще раз вспомню VLIW, где одной инструкцией кодируется большое количество операций. В Эльбрус-2000, если я правильно понимаю, может исполняться до 21-й операции на инструкцию, при этом — минималистичный дешифратор (b2b компиляцию не рассматриваем). Отсюда и кристалл небольших размеров и низкое энергопотребление при весьма высокой производительности.


          1. VaalKIA
            30.07.2019 02:39
            +1

            Creker вас вводит в заблуждение.
            Если современные процессоры x86 не RISC (хотя понятно, что речь про модуль исполнения этого набора комманд), то тогда и не CISC, а System On Chip, то есть набор разнородных микропроцессоров и специализированных блоков, включая потоковые и массивно-параллельные процессоры, он валит всё под один ярлык. Так же, соврешенно очевидно, что набор комманд x86 по прежнему исполняется как (RISC+микрокод). Фактически идёт подмена понятий.
            При этом, вам тоже следует разбираться более тонко в архитектурах процессоров. Существует такая вещь как стековый процессор, вот уж у кого как можно меньше инструкций и вы не совсем правы насчёт размера кода (Статься про стековые процессоры). А вот по поводу RISC… это не просто сокращённый набор комманд, это идеология: каким должен быть этот набор комманд, помимо того, что он маленький, например — все инструкции работы с памятью считаются медленными, поэтому набор комманд RISC не должен содержать комманд работы с памятью, помимо загрузки и выгрузки в регистр, фактически, там — целая иделогия. А уж терминов после наплодили море, на все вкусы (risc, cisc, zisc, misc, oisc и т.п.) и за каждым что-нибудь стоит.


            1. kt97679
              30.07.2019 18:34

              Под oisc вы имеете в виду вот это: en.wikipedia.org/wiki/One_instruction_set_computer?


              1. checkpoint
                30.07.2019 22:31

                Только хотел высказать идею использования Машины Тьюринга из одной инструкции и бесконечной памяти как «ультимативный RISC», а оказывается уже все давно придумано до нас. :-)


                1. kt97679
                  31.07.2019 07:49

                  Причем самые простые машины этого класса работают буквально с отдельными битами: esolangs.org/wiki/TOGA_computer esolangs.org/wiki/BitBitJump


          1. apro
            30.07.2019 02:43

            Разработчики ARM даже отказались от своего стандартного набора команд и
            полностью перешли на укороченный (по размеру) набор инструкций Thumb в том числе

            А можно более подробно об этом? Вроде для ARM 32bit Thumb и обычные инструкции сосуществуют, а в их следующей архитектуре Aarch64 вообще никакого thumb режима не предусмотрено?


            1. checkpoint
              30.07.2019 21:48

              В Cortex-M остался только Thumb-2 (как раз по причине пропускной способности шины). Про Aarch64 ничего не знаю, но смею предположить, что там и в помине нет предикатного исполнения инструкций, что долгое время являлось основным признаком ARM ISA.


          1. mpa4b
            30.07.2019 22:44

            Полностью перешли на Thumb-2 (смесь 16- и 32-битных команд в новой кодировке) перешли только в процессорах Cortex-M. Все остальные (в 32-битном режиме, если речь про 64-битные) продолжают поддерживать как ARM, так и Thumb режимы.


        1. mpa4b
          30.07.2019 22:53
          +2

          Как удобно сравнивать всё с интелом и армом. На их фоне что угодно будет устаревшим и малопроизводительным. Кто сделал хуже интела или арма — тот лузер.

          Ну да, и интел, и арм вкладывали и вкладывают дикие десятки (сотни, тысячи?) миллиардов баксов в течение многих десятков лет в развитие своих архитектур, в R&D, в зарплаты учёных и инженеров-разработчиков. Без сравнимых вложений, очевидно, их с пьедестала не сдвинуть просто так. А процессор, совместимый с архитектурой risc-v, может написать буквально один человек за пару месяцев на HDL.

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

          risc-v молодцы уже тем, что местами пошатали зажравшийся arm (и mips'у тоже досталось) по сути вообще без затрат бабла :)


      1. ProstoUser
        30.07.2019 10:15

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


        Я думаю, одна из причин — совместимость. Сейчас в разных процессорах может быть разное устройство этих «скрытых» RISC-процессоров. У них может быть разное количество внутренних регистров, возможно, разная логика предсказания переходов и т.п. Если поступать так как вы предлагаете, то надо будет компилировать каждую программу под каждую новую модель процессора отдельно. И не только компилировать, но и для каждой модели делать отдельный компилятор, который будет учитывать ее особенности.


        1. checkpoint
          30.07.2019 22:00

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


          Во-первых, не существует платформы/архитектуры без компилятора. Во-вторых, в среде UNIX/Linux перекомпиляция исходных кодов это не проблема, а добродетель. И втретьих, проблема совместимости железа решается с помощью Java (Android вам в пример), байт-код которой не зависит о разношерстного железа имеющегося на рынке. Т.е. совсместимость пользовательских приложений можно обеспечить спомощью Java или подобного механизма, а системное ПО (в том числе и интерпретатор байт-кода) обязятельно должно быть скомпилированно оптимизирующим компилятором под конкретную платформу. С моей дилетанской точки зрения это самый верный путь.


          1. torgeek
            30.07.2019 22:33

            Есть и более горячие головы, в том числе в России, которые предлагают весь код хранить в промежуточном виде аля ассемблер. Как байт код LLVM IR, например. И компилить под нативную платформу по мере надобности, а там кешировать, но сохранять байт код и ABI. Поговаривают, что так Apple уже практикует и рекомендует для MacOS и iOS. Потом бац и весь код работает не на х86, а на ARM или RISC-V.


            1. checkpoint
              30.07.2019 23:10

              У яблочников это называется Fat Binary, и уже давно. Помоему это банальное запихивание в один ELF сразу нескольких текстов собранных под различные ISA. Или вы имеете в виду что-то другое?


              1. torgeek
                30.07.2019 23:34

                Про другое, про IR, про промежуточный код низкого уровня, но не машинный. То есть когда приложение потребуется для установки на конкретном железе, то идёт запрос на компиляцию из IR под это железо со всеми доплючами и аппаратными оптимизациями. LLVM под это дело почти идеально годится – пишем на любом языке, получаем универсальный IR код, а дальше бекэнд-компилятор под платформу затачивает. Для РИСКов самое то, потому как IR проектировался под них. Даже игроделы будут рады – для них есть SPIR-V для GPU.


                1. checkpoint
                  31.07.2019 01:29

                  Так этож Just-in-Time компиляция, очень похоже на Android Run Time (ART). Прежде Dalvik в Android-е был интерпретатором Java, ART пришедший ему на смену — компилирует пользовательские приложения (Java байт-код) прямо в native и исполняет. Похоже в Apple решили не отставать, но за основу взяли IR. Очень интересно.


                  1. torgeek
                    31.07.2019 11:44

                    Общая идея похожа. Разница в поддержке языков и приоритете стратегии компиляции Ahead-of-Time над JIT. И тут байт код Java сильно проигрывает тому, сколько языков уже входит в обойму LLVM. Особенно таких как С, Rust и Go.

                    Тот, кто создаст платформу приложений на этой основе – будет новым Apple/Microsoft/Google :)


          1. ProstoUser
            31.07.2019 19:08

            Во-первых, не существует платформы/архитектуры без компилятора.


            Так платформы/архитектуры, а не модели процессора! И не один компилятор, а полный набор для всех более или менее популярных языков.

            Во-вторых, в среде UNIX/Linux перекомпиляция исходных кодов это не проблема, а добродетель.


            Компилятор надо сначала написать. Каждая новая модель процессора будет требовать собственный набор компиляторов для разных языков.

            И втретьих, проблема совместимости железа решается с помощью Java (Android вам в пример), байт-код которой не зависит о разношерстного железа имеющегося на рынке.


            Байткод, положим, не зависит. Но для каждого железа (платформы) нужна своя виртуальная машина. А с таким подходом будет нужна для каждой новой модели процессора.

            а системное ПО (в том числе и интерпретатор байт-кода) обязятельно должно быть скомпилированно оптимизирующим компилятором под конкретную платформу


            Интерпретатор байткода надо будет не просто скомпилировать под каждую новую платформу, его нужно будет написать под каждую новую модель процессора — там же будет новая система команд, фактически, а в виртуальной машине присутствует jit-компилятор. И этот компилятор должен будет генерировать нативный код для именно этой модели процессора.


      1. bm13kk
        30.07.2019 11:27

        На сколько я (по дилетански) понимаю сейчас все упирается в шину памяти.
        Все процессоры сейчас быстро выполняют инструкции первого-второго уровня кеша и ждут когда наконец прийдут новые команды (а не только данные) из оперативки.

        Интел выигрывает именно потому что хорошо угадывает что будет нужно и пока процессор выполняет такт — уже грузит будущие данные. Однако уязвимости последних лет постоенны именно на этой особенности.

        Если разбить инструкции на микроиснтрукции — процессоры будут работать дольше. Вне зависимости от своей частоты или архитектуры. Потому что шина памяти не справляется уже.


        1. torgeek
          30.07.2019 11:46
          -1

          Шины памяти тоже растут вширь. В новом MacPro используется 4096-разрядная шина.

          А можно пойти встречным путём – максимально использовать сжатые RISC-V инструкции при компиляции, то есть в 64 битный пакет разом влезет четыре 16-битные команды.
          (Chapter 16 “C” Standard Extension forCompressed Instructions, Version 2.0)


          1. bm13kk
            30.07.2019 12:59
            +1

            > Шины памяти тоже растут вширь.

            В терминах интернета — пинг важнее ширины канала. Тайминги памяти растут.

            > А можно пойти встречным путём – максимально использовать сжатые RISC-V инструкции при компиляции, то есть в 64 битный пакет разом влезет четыре 16-битные команды.

            На сколько я знаю ассемблер интелла, и о чем явно говорится в этой статье — 64 бита инструкций инелла легко могут быть 128 битами РИСКа или даже 256 битами. Это с учетом предложенного сжатия.


            1. torgeek
              30.07.2019 13:32

              Так для этого ссылку и дал на спецификацию, что б не гадать про РИСКи))
              Там прям по тексту: размер инструкции 16 бит.
              Зачем приводить гипотетические 128/256?


              1. bm13kk
                30.07.2019 14:27
                -2

                Статья начинасется с примера, когда 2 инструкции стают в риске 4. Если покопаться то можно найти случаи когда инструкций будет не в 2 раза больше, а в 6 или 10. Особенно в интеловских AVX или паках инструкций созданных для кодирования и шифрования.


                1. torgeek
                  30.07.2019 16:12

                  Поэтому раз, и RISC-V делает ход конём с использованием С-инструкций: «Typically, 50%–60% of the RISC-V instructions in a program can be replaced with RVC instructions, resulting in a 25%–30% code-size reduction.»

                  А реализация компактных аналогов AVX и прочих MMX радостей – это встроено прямо в идеологию расширяемости RISC-V. Вот в Alibaba взяли и добавили в свой процессор 50 дополнительных инструкций.


      1. bagamut
        30.07.2019 20:31

        На самом деле так и есть, современные компиляторы не используют устаревшие CISC инструкции х86, а только подмножество команд которые отлично укладываются на RISC ядро новых интел и амд х64, и соответствующе оптимизируют.


  1. mpa4b
    29.07.2019 23:19
    +4

    Тот случай, когда оригинал понятнее перевода:

    «Это приводит к ненужному переключению» — на самом деле «This produces unnecessary top-half toggling»
    «Биты закрепления в памяти FP» => «FP sticky bits» (какие нахрен 'биты закрепления'???)
    «При отсутствии MOV инструкция MOV rD, rS, r0» — очевидно ADD rD,rS,r0 (как и написано в оригинале)


  1. Sergei2405
    30.07.2019 09:19
    +7

    Может у RISC-V и есть недостатки, но то что он сдвинул монополию ARM в процессорных ядрах это факт.

    — ARM изменил политику лицензирования
    www.arm.com/products/flexible-access/product
    Вкратце берите что хотите, платить будите потом.

    — RISC-V поддерживается в среде разработки IAR
    www.iar.com/iar-embedded-workbench/#!?architecture=RISC-V&currentTab=partners
    (из 7 партнеров — двое из России)

    — Qualcome инвестировал $60M в RISC-V
    www.hpcwire.com/2019/06/07/qualcomm-invests-in-risc-v-startup-sifive

    — Alibaba выпустил свой чип на RISC-V
    www.eetimes.com/document.asp?doc_id=1334966#