В наши дни обработка регистров ЦП как массива на самом деле не является распространенным подходом. Последней известной мне архитектурой, которая позволила это, был PDP11, и он умер в конце 80-х. Почему бы вам не поместить свой массив в какую-то область памяти, как в любой другой массив?
Тем не менее, вы можете использовать вычисленный прыжок. Это также заменяет зависимость данных (режим индексированной адресации) на управляющую зависимость, поэтому неупорядоченному exe c не нужно ждать, пока ввод индекса будет готов, прежде чем он сможет начать выполнение кода, использующего конечный RAX , Конечно, это предполагает правильное предсказание ветвления, что маловероятно, если индекс часто меняется. Неправильный прогноз ветки стоит многих циклов небольшой работы, но небольшая задержка нагрузки, которая попадает в кэш L1d, может очень легко перекрываться с независимой работой.
Стоимость пропускной способности выше, чем у массива в памяти: некоторые вычисления адреса, один переход, один ход и ret
вместо просто mov
или даже операнда памяти с индексным режимом адресации.
Чтобы встроить этот код, просто замените jmp *%rax
на call *%rax
, стоимостью еще один уоп. Или замените ret
инструкции с jmp
на метку внизу и увеличьте шаг таблицы переходов до 8, чтобы учесть более длинное кодирование.
# select a register from r8...r15 according to the value in rdi
select:
lea labels-4*8(%rip),%rax # rdi = 8 is the first jump table entry
lea (%rax,%rdi,4),%rax # pointer to the appropriate entry
jmp *%rax # computed jump
.align 4
labels:
mov %r8, %rax
ret
.align 4
mov %r9, %rax
ret
.align 4
mov %r10, %rax
ret
.align 4
mov %r11, %rax
ret
.align 4
mov %r12, %rax
ret
.align 4
mov %r13, %rax
ret
.align 4
mov %r14, %rax
ret
.align 4
mov %r15, %rax
ret
Хотя это, вероятно, быстрее, чем три условных перехода (в зависимости от схемы доступа), это, конечно, не будет лучше, если использовать массив.