Могу ли я перевести знак между целыми числами быстрее (на C5515)? - PullRequest
2 голосов
/ 18 июня 2019

Я реализовал 32-разрядное деление с фиксированной точкой на TSP C5515 с использованием итеративного метода, описанного в DSPLIB .Это 16-битный DSP, и эта функция является узким местом с некоторыми повторными 32-битными вычислениями, поэтому каждая команда имеет значение.

Первая часть функции вырабатывает начальную оценку для обратной величинызнаменатель.Это линейная оценка, которая делает ±3 - 2x (но в фиксированной точке).Знак на 3 взят из знака знаменателя.Обратите внимание, что знаменатель никогда не равен нулю.

У меня сейчас есть (den - это int32_t):

int32_t offset = den > 0 ? 0x60000000 : -0x60000000;

Это компилируется в (AC0 - это смещение, AC3 - знаменатель):

        MOV #-24576 << #16, AC0
        XCCPART AC3 > #0 ||
           MOV #24576 << #16, AC0

Результат используется следующим образом, если это помогает (_l[s]shl - [насыщающий] сдвиг влево, _lssub - насыщающий вычитающий):

int32_t est = _lsshl(_lssub(offset, _lshl(den, -1)), 1);

Можно ли удалить ветку (XCCPART) и еще больше сократить количество инструкций?Я был бы рад использовать побитовые операции для этого, но я не могу понять, как это сделать (C5515 использует дополнение до двух, поэтому побитовое копирование не будет работать).Он не должен быть переносимым (я использую встроенные функции в других местах функции), поведение, определяемое реализацией, хорошо, но не неопределенное поведение.

Ответы [ 2 ]

1 голос
/ 18 июня 2019

С помощью следующей функции

inline int32_t SignOf(int32_t val)
{
    return (+1 | (val >> 31)); // if v < 0 then -1, else +1
}

, которая должна скомпилироваться во что-нибудь по линии арифметического сдвига вправо с последующим побитовым или с 1. Например, на руке M0:

ASRS     R2,R1,#+31
MOVS     R0,#+1
ORRS     R0,R0,R2

Тогда вы могли бы сделать

int32_t offset = SignOf(den) * 0x60000000;

Надеемся, что при некотором переупорядочении и распараллеливании компилятора это может быть быстрее, чем в ветке?

РЕДАКТИРОВАТЬ:

для конкретного случая+ -0x60000000, это может быть быстрее:

int32_t offset = ((den >> 1) & 0xC0000000) ^ 0x60000000;
1 голос
/ 18 июня 2019

Если ваш DSP имеет разные штрафы за разветвление теста, вы можете вычислить результат «разветвления в худшем случае», затем проверить знак в «разветвлении в лучшем случае» и исправить результат, добавив / вычтя 6 к более раннему предварительно вычисленномурезультат.Это сведет к минимуму влияние ветвления (хотя вы упомянули, что на вашем DSP нет прогноза ветвления, скачки все равно занимают несколько циклов).

Например, если оно стоит меньше , а не , введитеif body:

res = 3 - 2*x; // Consider den > 0
if (den & 0x80000000)
    res -= 6; // Back to -3-2*x

Или, если ввести if:

res = -3 - 2*x;
if (den & 0x80000000 == 0)
    res += 6;
дешевле
...