Прямые арифметические операции над числами малого размера в RISC-архитектурах

Существуют ли какие-либо архитектуры RISC, которые позволяют применять арифметические операции индивидуально к байтам, полусловам и другим ячейкам данных, размер которых меньше размера регистров общего назначения ЦП?

В процессорах Intel x86 (IA-32) и x86-64 (известных как EM64T или AMD64) доступен не только весь регистр, но и его меньшие части. Intel ISA позволяет производить все арифметические операции со всем регистром, его половиной, четвертью и байтом (точнее, доступны два байта в регистре, например AL и AH в RAX). После выполнения операции мы можем выполнить проверку переполнения, и если переполнение произошло во время предыдущей операции, с этим можно легко справиться. Независимо от того, работали ли мы со всем словом (32-разрядным для IA-32 и 64-разрядным для EM64T) или арифметическая инструкция выполнялась над данными меньшего размера (полуслова, четверть слова или байт), если результат превышает размер выбранной ячейки данных, соответствующий флаг (OF или CF) будет установлен в 1. Таким образом, в архитектуре Intel нет необходимости имитировать обработку таких ошибок, которые возникают при операциях с малыми размер данных, с цепочкой инструкций, анализирующих старшие биты результата.

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


person Victor    schedule 06.12.2017    source источник
comment
Пометка x86, потому что в основном возникает вопрос, похож ли RISC на x86, а если нет, то почему?   -  person Peter Cordes    schedule 06.12.2017


Ответы (3)


TL: DR: нет, AFAIK не существует RISC ISA с установкой флага частичным регистром операций уже, чем 32 бита. Но многие 64-битные RISC ISA (например, AArch64), которые вообще имеют ФЛАГИ, могут установить их из результата 32-битной операции.

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

Только RISC с шириной регистра 8 или 16 бит может устанавливать флаги из этого размера операнда. например AVR 8-битный RISC с 32 регистрами и 16-битными командными словами. Для реализации 16-битного int требуется добавление / adc повышенной точности.

Это в основном исторический факт: x86 имеет 16-битный размер операнда для всего, потому что он эволюционировал от 16-битного только 286. Когда был разработан 80386, было важно, чтобы он мог работать только с 16-битным. код на полной скорости, и они предоставили способы постепенного добавления 32-битных операций к 16-битному коду. И использовал тот же механизм, чтобы разрешить 16-битные операции в 32-битном коде.

8-битные младшие / высокие регистры x86 (AX = AH: AL) снова частично связаны с тем, что 8086 был разработан как преемник 8080 и чтобы упростить перенос (и даже возможно автоматизировать) См. Почему первые четыре x86 GPR названы в таком неинтуитивном порядке? . (А также потому, что было просто полезно иметь одновременно восемь 1-байтовых регистров и четыре 2-байтовых регистра.)


Связанный: Какое целое число дополнения 2 операции можно использовать без обнуления старших битов во входных данных, если требуется только младшая часть результата? Для многих вычислений вам не нужно заново обнулять старшие биты после каждой операции, чтобы получить то же самое результат. Таким образом, отсутствие 8-битного / 16-битного размера операнда не является препятствием для эффективной реализации большей части кода, который логически ограничивает свои результаты 8 или 16 битами.

64-битные RISC-машины часто имеют 32-битную версию по крайней мере некоторых важных инструкций, таких как add, поэтому вы можете получить результат add с нулевым расширением бесплатно, не усекая его отдельно, например чтобы сделать код типа array[i++] эффективным с uint32_t i и 64-битными указателями. Но никогда не делайте частичные регистры размеров операндов меньше 32-битных на любом RISC, о котором я слышал.

DEC Alpha интересен тем, что это был новый дизайн, 64-битный с нуля, не 64-битное расширение существующего ISA, как MIPS64. Эта таблица мнемоник Alpha показывает, что добавление / sub / mul / div были доступны в 32- и 64-битных формах, но сдвиги и сравнения - нет. (Существуют также инструкции по манипулированию байтами, которые в основном представляют собой перетасовку / маску / вставку / извлечение SIMD внутри 64-битных целочисленных регистров, а также упакованное сравнение SIMD для эффективного строкового материала.)

Согласно этому официальному MIPS64 ISA doc (раздел 4.3 Регистры ЦП).

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

(Вы используете специальные инструкции для полных 64-битных регистров, например DADDU (двойное слово-добавление без знака) вместо ADDU. Обратите внимание, что версии add и dadd, отличные от U, ловят перегрузку подписанного дополнения до 2 (с 32-битным или 64-битным размер операнда), поэтому вы должны использовать версию U для обертывания математических вычислений со знаком (ссылки на ISA-ссылки на mips.com). В любом случае, MIPS не имеет специального режима для 32-битной версии, но ОС должна заботиться о 32-битных программах по сравнению с 64-битными, потому что 32-битная версия предполагает все указатели находятся в младших 32 единицах виртуального адресного пространства.


На машине загрузки / сохранения RISC вы обычно просто используете нулевую (или расширяющую знак) загрузку байтов / полуслов. Когда вы закончите, вы должны использовать хранилище байтов / полуслов, чтобы получить усеченный результат. (Обычно используется для unsigned base2 или дополнения до 2 со знаком.) Именно так компилятор (или человек) реализует исходный код C, который использует short или uint8_t.

Наполовину связанный: правила продвижения целых чисел C автоматически продвигают все, что уже, чем int, до int, когда используется в качестве операнда для бинарного оператора, такого как +, поэтому в большинстве случаев это хорошо соответствует этому способу вычислений. (т.е. unsigned result = (a+b) * c в C не нужно усекать результат a+b обратно до uint8_t перед умножением, если a, b и c равны uint8_t. Но очень плохо, что uint16_t продвигается до int со знаком, поэтому uint16_t a,b; unsigned c = a * b рискует переполнить знак UB от продвижения до подписанного int для умножения.) В любом случае правила продвижения C выглядят так, как будто они разработаны для машин без полной поддержки узких размеров операндов, потому что это характерно для большого количества оборудования.


Но вы спрашиваете о проверке переполнения / установке флага от узких сотрудников.

Не все RISC-машины даже имеют регистр FLAGS. ARM делает, но, например, MIPS и Alpha нет. ARM не устанавливает флаги для каждой инструкции: вы должны явно использовать форму установки флага инструкции.

ЦП без ФЛАГОВ обычно имеют несколько простых инструкций сравнения и перехода (часто с нулевым значением, например MIPS bltz) и другие, которые сравнивают два ввода и записывают результат 0/1 в другой целочисленный регистр (например, MIPS SLTIU - устанавливается на значение без знака, меньшее, чем немедленно). Вы можете использовать инструкции Set + a bne с нулем для создания более сложных условий перехода.


Аппаратная и программная поддержка для эффективной проверки переполнения - это вообще проблема. Ставить jcc после каждой инструкции x86 тоже довольно отстой.

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

MIPS интересен захватом add для подписанного переполнения.

Способы его эффективной реализации могут включать наличие «липкого» флага, как фиксируются флаги исключения FPU: флаг Invalid остается установленным после деления на ноль (и получения NaN); другие инструкции FP не очищают его. Таким образом, вы можете проверить флаги исключения в конце серии вычислений или после цикла. Это делает его достаточно дешевым, чтобы его можно было использовать на практике, если бы для этого была программная среда.

С кодом FP ​​обычно не нужно смотреть на флаги, потому что NaN сам по себе «липкий» или «заразительный». Большинство бинарных операторов производят NaN, если любой из входных данных равен NaN. Но представления целых чисел без знака и дополнения до 2 не имеют каких-либо резервных битовых шаблонов: все они представляют собой определенные числа. (Дополнение до 1 имеет отрицательный ноль ...)

Чтобы узнать больше о дизайне ISA, который сделает возможной проверку переполнения, посмотрите обсуждение предложения Агнера Фога о новой ISA, которая сочетает в себе лучшие функции x86 (плотность кода, много работы на инструкцию) и RISC (легко декодируется) для высокопроизводительной бумажной архитектуры. Некоторые интересные идеи SIMD, включая обеспечение прозрачности будущих расширений векторной ширины, чтобы вам не приходилось перекомпилировать, чтобы работать быстрее с более широкими векторами.

person Peter Cordes    schedule 06.12.2017

Есть ли ...

Вы говорите только о коммерческих процессорах на рынке или также о студенческих проектах в университете и т. Д.?

Я сам разработал RISC CPU для образовательных целей, который может выполнять 8-, 16- и 32-битные операции. Таким образом, это показывает, что это, по крайней мере, возможно.

В 64-битных встроенных архитектурах PowerPC также есть нечто подобное: они могут выполнять 32-битные операции с младшими 32 битами 64-битных регистров.

В этой архитектуре нет 8- и 16-битных операций. Однако процессоры CISC также не поддерживают всю ширину, поддерживаемую другими компьютерами с меньшей шириной:

x86 не поддерживает ни 4-битные, ни 12-битные операции, хотя существуют процессоры (Intel 4004 и DEC PDP-8), использующие эту ширину.

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

Здесь интересна 64-битная архитектура SPARC:

Чтобы 32-битное программное обеспечение могло выполняться на 64-битных процессорах, есть некоторые специальные функции.

Один из них заключается в том, что все флаги (перенос, ноль, ...) дублируются: один раз для младших 32 бит и один раз для всех 64 бит.

Поэтому после выполнения операции «ДОБАВИТЬ» (которая может быть выполнена только в 64-разрядной версии) вы можете проверить наличие 64-разрядных или 32-разрядных флагов.

person Martin Rosenau    schedule 06.12.2017

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

Но есть одна такая необычная архитектура RISC, названная Blackfin, в которой регистры данных могут быть доступны как целиком или в виде нескольких отдельных частей. Из его документации (в формате bullets для удобства чтения):

  • Accumulators: The set of 40-bit registers A1 and A0 that normally contain data that is being manipulated. Each Accumulator can be accessed in five ways:
    • as one 40-bit register
    • как один 32-битный регистр (обозначенный как A1.W или A0.W)
    • в виде двух 16-битных регистров, похожих на регистры данных (обозначенных как A1.H, A1.L, A0.H или A0.L)
    • и как один 8-битный регистр (обозначенный A1.X или A0.X) для битов, выходящих за пределы бита 31.
  • Data Registers: The set of 32-bit registers (R0, R1, R2, R3, R4, R5, R6, and R7) that normally contain data for manipulation. Abbreviated D-register or Dreg.
    • Data Registers can be accessed as
      • 32-bit registers
      • или, по желанию, в виде двух независимых 16-битных регистров.
    • 16 младших разрядов каждого регистра называются «младшей» половиной и обозначаются «.L» после имени регистра. Старшие 16 битов называются «старшей» половиной и обозначаются символом «.H» после имени. Пример: R7.L, r2.h, r4.L, R0.h.

Регистры Blackfin

У него даже есть несколько независимых флагов переноса и переполнения в регистре арифметического статуса (ASTAT), что упрощает смешивание арифметических операций.


Еще один интересный случай - SuperH SH-5, который выполняет операции SIMD внутри регистров общего назначения, хотя у него есть отдельный набор из 64 плавающих -точечные регистры. Таким образом, вы можете выполнять арифметические операции с реальными байтами / словами / двойными словами. Другими словами, он использует аппаратную методику SWAR.

 Мультимедийные данные в регистрах общего назначения SH-5


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

cmpi    Compare Integer
cmpib   Compare Integer Byte
cmpis   Compare Integer Short
cmpo    Compare Ordinal
cmpob   Compare Ordinal Byte
cmpos   Compare Ordinal Short
concmpi Conditional Compare Integer
concmpo Conditional Compare Ordinal
person phuclv    schedule 04.05.2019
comment
PowerPC имеет 32 целочисленных регистра GP, и ни один из них не установлен в ноль. (math-atlas.sourceforge.net/devel/atlas_contrib/node96.html и ibm.com/support/knowledgecenter/en/ssw_aix_72 / ассемблер /). PowerPC подобен супер-усердной ISA, которая смеется над сложностями. - person Peter Cordes; 12.08.2019
comment
ИМО, термин SWAR действительно применяется, когда ваши элементы SIMD уже, чем границы переноса-распространения, и вы делаете то, что, как вы можете доказать, не будет нести. например маскировать / сдвигать и складывать с 2-битными или 4-битными аккумуляторами внутри более широких элементов. (Или когда вы маскируете нежелательный перенос, например, 8-битные сдвиги SSE2 с x86 psrlw (16-битная степень детализации) + pand.) Истинные инструкции SIMD, которые работают с данными в целочисленных регистрах GP, не делают его SWAR, ИМО. - person Peter Cordes; 12.08.2019
comment
@PeterCordes, вы правы насчет SWAR, но почему-то в статье в Википедии SIMD ISA указан как SWAR. Что касается PowerPC, то R0 означает либо GPR0, либо число 0 в зависимости от инструкций. Многие инструкции также не могут использовать источник R0. Plan 9 для PowerPC, даже требует, чтобы R0 был инициализирован 0 программным обеспечением - person phuclv; 13.08.2019