Во-первых, если эта переменная должна обновляться после (почти) каждой инструкции, очевидный совет:
не
Обновляйте его только тогда, когда последующим инструкциям нужно его значение. В любое другое время обновлять его бессмысленно.
Но в любом случае, когда мы обновляем его, нам нужно следующее поведение:
R < 0 => CR0 == 0b001
R > 0 => CR0 == 0b010
R == 0 => CR0 == 0b100
В идеале, нам вообще не нужно разветвляться. Вот один из возможных подходов:
- Установите CR0 на значение
1
. (если вам действительно нужна скорость, выясните, можно ли это сделать, не извлекая константу из памяти. Даже если вам придется потратить на это пару инструкций, это может стоить того)
- Если R> = 0, сдвиг влево на один бит.
- Если R == 0, сдвиг влево на один бит
Где шаги 2 и 3 могут быть преобразованы для исключения части "если"
CR0 <<= (R >= 0);
CR0 <<= (R == 0);
Это быстрее? Я не знаю. Как всегда, когда вы беспокоитесь о производительности, вам нужно измерить, измерить, измерить.
Однако я вижу несколько преимуществ этого подхода:
- избегаем веток полностью
- мы избегаем загрузки / хранения памяти.
- инструкции, на которые мы опираемся (сдвиг битов и сравнение), должны иметь низкую задержку, что, например, не всегда имеет место для умножения.
Недостатком является то, что у нас есть цепочка зависимостей между всеми тремя строками: каждая изменяет CR0, который затем используется в следующей строке. Это несколько ограничивает параллелизм на уровне команд.
Чтобы минимизировать эту цепочку зависимостей, мы могли бы сделать что-то вроде этого:
CR0 <<= ((R >= 0) + (R == 0));
поэтому нам нужно изменить CR0 только один раз, после его инициализации.
Или, делая все в одной строке:
CR0 = 1 << ((R >= 0) + (R == 0));
Конечно, существует множество возможных вариаций этой темы, поэтому продолжайте и экспериментируйте.