Это один из тех случаев, когда ABI начинает кровоточить в ISA.Вы найдете несколько таких в RISC-V.В результате того, что у нас был довольно значительный программный стек, портированный к моменту стандартизации ISA, мы получили возможность точно настроить ISA для соответствия реальному коду.Поскольку явная цель базовых ISA RISC-V состояла в том, чтобы сохранить много места для кодирования, доступного для будущего расширения.
В этом случае проектное решение ABI состоит в том, чтобы ответить на вопрос "Существует ли каноническое представлениетипы, которые при хранении в регистрах не нуждаются в каждом битовом шаблоне, предоставленном этими регистрами, чтобы представлять каждое значение, представляемое типом? "В случае RISC-V мы решили назначить каноническое представление для всех типов.Здесь есть петля обратной связи с некоторыми проектными решениями ISA, и я думаю, что лучший способ сделать это - проработать пример того, что ISA развивалось бы совместно с ABI, где мы не требовали канонического представления.
В качестве упражнения для размышления давайте предположим, что RISC-V ABI не предписывал каноническое представление старших бит int
при сохранении в регистре X в RV64I.В результате получается, что существующее семейство инструкций W не будет особенно полезным: вы можете использовать addiw t0, t0, 0
в качестве расширения знака, чтобы компилятор мог полагаться на то, что находится в старших битах, но это добавляет дополнительную инструкцию кмного общих шаблонов, таких как сравнение + ветвь.Правильное проектное решение ISA, которое нужно принять, будет иметь другой набор W-инструкций, что-то вроде «сравните на младших 32 битах и ветви».Если вы запустите числа, вы получите примерно такое же количество дополнительных инструкций (ветвление и настройка в отличие от сложения, подстановки и сдвига).Проблема в том, что инструкции ветвления намного дороже с точки зрения пространства кодирования, потому что они имеют намного более длинные смещенияПоскольку пространство кодирования считается важным ресурсом в RISC-V, когда нет явного преимущества в производительности, мы склонны выбирать проектное решение, которое экономит больше места для кодирования.В этом случае нет никакого значимого различия в производительности, если ABI соответствует ISA.
Здесь необходимо принять решение о разработке второго порядка: будет ли каноническое представление расширяться до нуля или расширяться до нуля?Здесь есть компромисс: расширение знака приводит к более быстрому программному обеспечению (при том же объеме используемого пространства кодирования), но более сложному аппаратному обеспечению.В частности, общий фрагмент C
long func_pos();
long func_neg();
long neg_or_pos(int a) {
if (a > 0) return func_pos();
return func_neg();
}
очень эффективно компилируется, когда используется расширение знака
neg_or_pos:
bgtz a0,.L4
tail func_neg
.L4:
tail func_pos
, но медленнее, когда используется нулевое расширение (опять же, предполагая, что мы не хотимвзорвать много места для кодирования при сравнении размера слова + инструкции ветвления)
neg_or_pos:
addiw a0, a0, 0
bgtz a0,.L4
tail func_neg
.L4:
tail func_pos
Когда мы уравновесили ситуацию, оказалось, что стоимость программного обеспечения нулевого расширения была выше, чем стоимость аппаратного расширения знака: дляДля наименьшего возможного дизайна (т. е. микрокодированной реализации) вам по-прежнему необходим арифметический сдвиг вправо, чтобы не потерять какой-либо путь к данным, а для максимально возможного дизайна (т. е. с широким ядром, вышедшим из строя) код просто переставит перемешиваться.биты перед ветвлением.Как ни странно, единственное место, где вы платите значительную цену за расширение знака, - это машины на заказ с короткими конвейерами: вы могли бы сократить задержку MUX на пути ALU, что является критичным в некоторых конструкциях.На практике существует множество других мест, в которых расширение знака является правильным решением, поэтому простое его изменение не приведет к удалению этого канала данных.