Самое быстрое чтение смещения для небольшого массива - PullRequest
1 голос
/ 03 февраля 2020

Для скорости я хотел бы прочитать один из 8 регистров, на которые ссылается значение в 9-м регистре. Самый быстрый способ сделать это - использовать 3 условных перехода (проверка 3 битов в 9-м регистре). Это должно иметь меньшую задержку, чем стандартный способ сделать это со считыванием из смещенной памяти, но для этого все еще требуется по крайней мере 6 тактов (по крайней мере, один тест плюс один условный бит в секунду на бит).

Есть ли коммерческий ЦП (предпочтительно x86 / x64) с внутренним значением c для выполнения этого «чтения смещения регистра» с задержкой всего в один такт?

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

1 Ответ

1 голос
/ 03 февраля 2020

В наши дни обработка регистров ЦП как массива на самом деле не является распространенным подходом. Последней известной мне архитектурой, которая позволила это, был 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...