Программирование DSP Встроенные функции компиляторов Blackfin VisualDSP и GCC Thu, April 25 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

Встроенные функции компиляторов Blackfin VisualDSP и GCC Печать
Добавил(а) microsin   

Оба компилятора, и VisualDSP++, и GCC, поддерживают встроенные (built-in) или внутренние (intrinsic) функции, чтобы позволить программисту эффективно использовать аппаратные ресурсы процессоров Blackfin. Например, для вычислений с использованием комплексных дробных чисел. Программа использует intrinsic-функции так же, как обычные, через стандартный синтаксис вызова функции. В результате вместо встроенной функции компилятор генерирует одну или несколько машинных инструкций точно так же, как это он делает для обычных операторов, таких как + или *.

Встроенные функции имеют имена, начинающиеся на __builtin. 

Примечание: идентификаторы, начинающиеся на двойное подчеркивание '__', зарезервированы стандартом C, чтобы эти имена не конфликтовали с именами идентификаторов, определенных пользователем.

Встроенные функции специфичны для определенной архитектуры. Различные системные файлы заголовка предоставляют пользователю определения intrinsic-функций и доступ к ним. Эта функция может быть запрещена опцией командной строки компилятора -no-builtin [7].

Ниже приведено описание текущей реализации intrinsic-функций GCC, и наличие аналогичных функций для компилятора среды VisualDSP++.

void __builtin_aligned(const void *p, int align);

Функция __builtin_aligned это утверждение, что первый параметр укажет на аргумент, который выравнен на значение второго аргумента (т. е. адрес *p нацело делится на align). Второй аргумент дает количество единиц размером char, что тает 8 бит (байт) режиме байтовой адресации (byte-addressing) и 32-битные слова в режиме адресации слова (word-addressing). Информация о выравнивании помогает оптимизатору комбинировать загрузки (load) и сохранения (store) из последовательных итераций в цикле. Идеальная ситуация, когда все обрабатываемые данные в первой итерации цикла выровнены на границу 4 слова.

Пример в режиме word-addressing, где параметр "a" указывает на данные, выравненные на 4 слова:

void fn(int *a)
{
   __builtin_aligned(a, 4); 
   .... 
}

[Использование заголовочного файла builtins.h]

Заголовочный файл builtins.h предоставляет пользователю видимые прототипы для встроенных функций, хотя это не обязательно, потому что компилятор VisualDSP уже осведомлен об этих функциях. Однако заголовочный файл builtins.h также предоставляет короткие формы некоторых более сложных встроенных функций (например, __builtin_memcpy заменяется на memcpy, и т. п. Настоятельно рекомендуется использовать именно эти сокращенные имена для встраиваемых функций.

При использовании компилятора Microsoft C/C++ используйте опцию командной строки /TP, чтобы выбрать компиляцию C++: "inline" не распознается как ключевое слово в режиме компиляции языка C.

[Представление чисел fract16 и fract32]

Тип fract16 представляет 16-битное дробное число с фиксированной запятой, со знаком. Тип fract32 представляет 32-битное дробное число с фиксированной запятой, со знаком. Оба этих типа работают в одинаковом диапазоне дробных чисел [-1.0,+1.0), т. е. от -1 включительно до +1 исключительно. Однако fract32 в 2 раза точнее, чем fract16.

У fract16 и fract32 нет специального встроенного формата, они определены просто через typedef:

typedef short fract16;
typedef long fract32;

Представление данных fract16 и fract32:

VisualDSP fract16 fract32

Таким образом, чтобы представить число 0.25 в fract16, нужно использовать число 0x2000 (2-2) в формате HEX. Для -0.25 в fract32, соответствующее HEX-число должно быть 0xe0000000 (-1 + 2-1 + 2-2). Для -1 HEX-представление fract16 должно быть 0x8000 (-1). Числа fract16 и fract32 не могут точно представить значение +1, однако представляют его довольно близко числами 0x7fff для fract16, или 0x7fffffff для fract32. Существует также тип fract2x16, в котором два значения fract16 упакованы в 32 бита. Первые 2 байта принадлежат одному fract16, и вторые 2 байта принадлежат другому fract16. Есть встроенные функции, которые работают с параметрами fract2x16.

Внимание: поскольку fract16 и fract32 не являются в действительности встроенными типами данных, на языке C для выполнения базовой арифметики нужно использовать встроенные функции. Вы не можете просто так выполнить умножение fract16 * fract16 и получить правильный результат. На C++ для fract-данных классы fract и shortfract определяют базовые арифметические операторы, в то время как на языке C традиционные типы с фиксированной запятой fract и accum предоставляют более натуральную альтернативу для fract16 и fract32. Таким образом, типы fract16 и fract32 имеет смысл применять только для использования с готовыми, оптимизированными (написанными на ассемблере) библиотеками [2].

[Функции C для работы с дробными значениями]

Все встроенные функции, описанные в этом разделе, применяют насыщение для результата, если не указано обратное. Все функции, вызываемые gcc, получают префикс __builtin_bfin_.

fract16. Эти встроенные функции работают напрямую с типом fract16 [2], хотя одна из функций умножения возвращает fract32.

VisualDSP++ GCC аргументы вернет Описание
add_fr1x16 add_fr1x16 fract16 f1,
fract16 f2
fract16 Выполняет 16-битное сложение двух входных параметров (f1+f2).
sub_fr1x16 sub_fr1x16 fract16 f1,
fract16 f2
fract16 Выполняет 16-битное вычитание двух входных параметров (f1-f2).
mult_fr1x16 mult_fr1x16 fract16 f1,
fract16 f2
fract16 Выполняет 16-битное умножение входных параметров (f1*f2). Результат обрезается до 16 бит.
multr_fr1x16 multr_fr1x16 fract16 f1, fract16 f2 fract16 Выполняет 16-битное дробное умножение (f1*f2) двух входных параметров. Результат округляется до 16 бит. Какой будет вид округления - смещенный (biased) или не смещенный (unbiased) - зависит от состояния бита RND_MOD в регистре ASTAT.
mult_fr1x32 mult_fr1x32 fract16 f1, fract16 f2 fract32 Выполняет дробное умножение двух 16-битных частей, с возвратом 32-битного результата. Здесь будет потеря точности.
abs_fr1x16 abs_fr1x16 fract16 f1 fract16 Возвратит 16-битное значение, которое является абсолютной величиной входного параметра. Когда на входе число 0x8000, произойдет насыщение и будет возвращено число 0x7fff.
min_fr1x16 min_fr1x16 fract16 f1, fract16 f2 fract16 Вернет минимальное значение из двух входных параметров.
max_fr1x16 max_fr1x16 fract16 f1, fract16 f2 fract16 Вернет максимальное значение из двух входных параметров.
negate_fr1x16 negate_fr1x16 fract16 f1 fract16 Вернет 16-битный результат отрицания входного параметра (-f1). Если входное значение было 0x8000, то произойдет насыщение, и будет возвращено значение 0x7fff.
shl_fr1x16 shl_fr1x16 fract16 src, short shft fract16 Выполняет арифметический сдвиг переменной src влево на shft позиций бит. Пустые образующиеся биты заполняются нулями. Если shft отрицателен, то будет выполнен сдвиг вправо на abs(shft) бит с расширением знака.
shl_fr1x16_clip   fract16 src, short shft fract16 Выполняет арифметический сдвиг переменной src на shft позиций бит (с отсечением до 5 бит). Пустые места бит заполняются нулевыми битами. Если shft отрицательный, то выполняется сдвиг вправо на abs(shft) позиций с расширением знака.
shr_fr1x16   fract16 src, short shft fract16 Выполняет арифметический сдвиг переменной src вправо на shft позиций бит с расширением знака. Если shft отрицателен, то выполняется сдвиг влево на abs(shft) позиций, и пустые биты заполняются нулями.
shr_fr1x16_clip   fract16 src, short shft fract16 Выполняет арифметический сдвиг переменной src вправо на shft позиций (с отсечением до 5 бит) с расширением знака. Если shft отрицательный, то выполняется сдвиг влево на abs(shft) позиций, с заполнением пустых бит нулями.
shrl_fr1x16   fract16 src, short shft fract16 Выполняет логический сдвиг fract16 вправо на shft позиций. Здесь не выполняется расширение знака и не выполняется насыщение - пустые биты заполняются нулями.
shrl_fr1x16_clip   fract16 src, short shft fract16 Выполняет логический сдвиг fract16 вправо на shft позиций (с отсечением до 5 бит). Здесь не выполняется расширение знака и не выполняется насыщение - пустые биты заполняются нулями.
norm_fr1x16 norm_fr1x16 fract16 f1 int Возвратит количество левых сдвигов, которое требуется, чтобы нормализовать входную переменную так, чтобы она была либо в интервале 0x4000 .. 0x7fff, либо в интервале 0x8000 .. 0xc000. Другими словами, fract16 x; shl_fr1x16(x,norm_fr1x16(x)); вернет значение в диапазоне 0x4000 .. 0x7fff, или в диапазоне 0x8000 .. 0xc000.

fract32. Эти встроенные функции работают напрямую с типом fract32 [], хотя есть несколько функций, которые конвертируют числа из fract32 в fract16.

VisualDSP++ GCC аргументы вернет Описание
add_fr1x32 add_fr1x32 fract32 f1,
fract32 f2
fract32 Выполняет 32-битное сложение двух входных параметров (f1+f2).
sub_fr1x32 sub_fr1x32 fract32 f1,
fract32 f2
fract32 Выполняет 32-битное вычитание двух входных параметров (f1-f2).
mult_fr1x32x32 mult_fr1x32x32 fract32 f1,
fract32 f2
fract32 Выполняет 32-битное умножение входных параметров (f1*f2). Результат (который внутренне вычисляется с точностью 40 бит) округляется (округление со смещением, biased rounding) до 32 бит.
multr_fr1x32x32   fract32 f1,
fract32 f2
fract32 То же самое, что и mult_fr1x32x32, но с дополнительной точностью округления.
mult_fr1x32x32NS mult_fr1x32x32NS fract32 f1, fract32 f2 fract32 Выполняет 32-битное умножение без насыщения входных параметров (f1*f2). Эта функция работает несколько быстрее, чем mult_fr1x32x32. Результат (который внутренне вычисляется с точностью 40 бит) округляется (округление со смещением, biased rounding) до 32 бит.
abs_fr1x32 abs_fr1x32 fract32 f1 fract32 Возвратит 32-битное число, равное абсолютному значению входного параметра. Когда входное число равно 0x80000000, произойдет насыщение, и будет возвращено значение 0x7fffffff.
min_fr1x32 min_fr1x32 fract32 f1, fract32 f2 fract32 Возвратит минимальное значение из двух входных параметров.
max_fr1x32 max_fr1x32 fract32 f1, fract32 f2 fract32 Возвратит максимальное значение из двух входных параметров.
negate_fr1x32 negate_fr1x32 fract32 f1 fract32 Возвратит 32-битное число, равное отрицанию входного параметра (-f1). Если входное число равно 0x80000000, то произойдет насыщение, и будет возвращено значение 0x7fffffff.
shl_fr1x32 shl_fr1x32 fract32 src, short shft fract32 Производит арифметический сдвиг переменной src влево на shft позиций. Появляющиеся пустоты бит заполняются нулями. Если shft отрицателен, то сдвиг осуществляется вправо на abs(shft) позиций, с расширением знака.
shl_fr1x32_clip   fract32 src, short shft fract32 Производит арифметический сдвиг переменной src на shft позиций (с отсечением до 6 бит). Появляющиеся пустоты бит заполняются нулями. Если shft отрицателен, то осуществляется сдвиг вправо на abs(shft) позиций, с расширением знака.
shr_fr1x32   fract32 src, short shft fract32 Производит арифметический сдвиг переменной src право на shft позиций, с расширением знака. Если shft отрицателен, то происходит сдвиг влево на abs(shft) позиций, с заполнением пустот нулями.
shr_fr1x32_clip   fract32 src, short shft fract32 Производит арифметический сдвиг переменной src право на shft позиций (с отсечением до 6 бит), с расширением знака. Если shft отрицателен, то происходит сдвиг влево на abs(shft) позиций, с заполнением пустот нулями.
sat_fr1x32   fract32 f1 fract16 Если f1 > 0x00007fff, то функция вернет 0x7fff. Если f1 < 0xffff8000, то вернет 0x8000. Иначе будет возвращены младшие 16 бит входного параметра f1.
round_fr1x32   fract32 f1 fract16 Округляет 32-битное дробное число до 16-битного дробного, с использованием округления со смещением (biased rounding).
norm_fr1x32 norm_fr1x32 fract32 int Возвратит количество сдвигов влево, которое требуется для нормализации входной переменной так, чтобы она была в диапазоне либо 0x40000000 .. 0x7fffffff, либо в диапазоне 0x80000000 .. 0xc0000000. Другими словами, fract32 x; shl_fr1x32(x,norm_fr1x32(x)); возвратит значение в диапазоне 0x40000000 .. 0x7fffffff, или в диапазоне 0x80000000 .. 0xc0000000.
trunc_fr1x32   fract32 f1 fract16 Возвратит старшие 16 бит f1 - младшие 16 бит будут отрезаны и отброшены.

fract2x16. Эти встроенные функции работают главным образом с типом fract2x16, хотя есть функции композиции и декомпозиции для типа fract2x16, а также функции умножения, которые возвращают результат в виде fract32, и операции на одиночной паре fract2x16, которые возвращают типы fract16. Используется нотация {a,b} для представления двух значений fract16, упакованных в fract2x16, где "a" это fract16, упакованный в старшую половину, и "b" это fract16, упакованный в младшую половину.

VisualDSP++ GCC аргументы    вернет Описание
compose_fr2x16   fract16 f1, fract16 f2 fract2x16 Принимает два значения fract16, и возвращает значение fract2x16.
high_of_fr2x16   fract2x16 f fract16 Принимает fract2x16 и возвращает "старшую половину" fract16.
low_of_fr2x16   fract2x16 f fract16 Принимает fract2x16 и возвращает "младшую половину" fract16
add_fr2x16 add_fr2x16 fract2x16 f1, fract2x16 f2 fract2x16 Складывает два упакованных дробных.
sub_fr2x16 sub_fr2x16 fract2x16 f1, fract2x16 f2 fract2x16 Вычитает два упакованных дробных.
mult_fr2x16 mult_fr2x16 fract2x16 f1, fract2x16 f2 fract2x16 Умножает два упакованных дробных. Обрезает результат до 16 бит.
multr_fr2x16 multr_fr2x16 fract2x16 f1, fract2x16 f2 fract2x16 Умножает два упакованных дробных. Округляет результат до 16 бит. Какой будет вид округления - смещенный (biased) или не смещенный (unbiased), зависит от состояния бита RND_MOD в регистре ASTAT.
negate_fr2x16 negate_fr2x16 fract2x16 f1 fract2x16 Отрицает оба 16-битных дробных в упакованном дробном. Если одно из значений fract16 входного параметра равно 0x8000, то происходит его насыщение и в результате отрицания будет возвращено значение 0x7fff.
shl_fr2x16 shl_fr2x16 fract2x16 f1,
short shft
fract2x16 Выполняет арифметический сдвиг обоих fract16 в упакованном дробном fract2x16 влево на shft позиций, и возвратит упакованный результат. Пустые биты заполняются нулями. Если shft отрицателен, то выполняется сдвиг вправо на abs(shft) позиций, с расширением знака.
shl_fr2x16_clip   fract2x16 f1,
short shft
fract2x16 Выполняет арифметический сдвиг обоих fract16 в упакованном дробном fract2x16 влево на shft позиций (с отсечением до 5 бит), и возвратит упакованный результат. Пустые биты заполняются нулями. Если shft отрицателен, то выполняется сдвиг вправо на abs(shft) позиций, с расширением знака.
shr_fr2x16   fract2x16 f1,
short shft
fract2x16 Выполняет арифметический сдвиг обоих fract16 в упакованном дробном fract2x16 вправо на shft позиций, с расширением знака, и возвратит упакованный результат. Если shft отрицателен, то выполняется сдвиг влево на abs(shft) позиций, с заполнением пустых бит нулями.
shr_fr2x16_clip   fract2x16 f1,
short shft
fract2x16 Выполняет арифметический сдвиг обоих fract16 в упакованном дробном fract2x16 вправо на shft позиций (с отсечением до 5 бит), с расширением знака, и возвратит упакованный результат. Если shft отрицателен, то выполняется сдвиг влево на abs(shft) позиций, с заполнением пустых бит нулями.
shrl_fr2x16   fract2x16 f1,
short shft
fract2x16 Выполняет логический сдвиг обоих fract16s в упакованном fract2x16 вправо на shft позиций. Здесь нет ни расширения знака, ни насыщения - пустые биты заполняются нулями.
shrl_fr2x16_clip   fract2x16 f1,
short shft
fract2x16 Выполняет логический сдвиг обоих fract16s в упакованном fract2x16 вправо на shft позиций (с отсечением до 5 бит). Здесь нет ни расширения знака, ни насыщения - пустые биты заполняются нулями.
abs_fr2x16 abs_fr2x16 fract2x16 f1 fract2x16 Вернет абсолютное значение обоих fract16 в упакованном fract2x16.
min_fr2x16 min_fr2x16 fract2x16 f1,
fract2x16 f2
fract2x16 Возвратит минимумы из двух пар fract16s в двух fract2x16s.
max_fr2x16 max_fr2x16 fract2x16 f1, fract2x16 f2 fract2x16 Возвратит максимумы из двух пар fract16s в двух fract2x16s.
sum_fr2x16 sum_fr2x16 fract2x16 f1 fract16 Выполняет поперечное сложение двух fract16 в f1.
add_as_fr2x16   fract2x16 f1, fract2x16 f2 fract2x16 Выполняет векторное сложение/вычитание двух входных fract2x16.
add_sa_fr2x16   fract2x16 f1, fract2x16 f2 fract2x16 Выполняет векторное вычитание/сложение двух входных fract2x16.
diff_hl_fr2x16 diff_hl_fr2x16 fract2x16 f1 fract16 Берет различие (старшее - младшее) двух fract16 в the fract2x16.
diff_lh_fr2x16 diff_lh_fr2x16 fract2x16 f1 fract16 Берет различие (младшее - старшее) двух fract16 в fract2x16.
mult_ll_fr2x16   fract2x16 f1, fract2x16 f2 fract32 Перекрестное умножение. Умножает младшую половину f1 на младшую половину f2.
mult_hl_fr2x16   fract2x16 f1, fract2x16 f2 fract32 Перекрестное умножение. Умножает старшую половину f1 на младшую половину f2.
mult_lh_fr2x16   fract2x16 f1, fract2x16 f2 fract32 Перекрестное умножение. Умножает младшую половину f1 на старшую половину f2.
mult_hh_fr2x16   fract2x16 f1, fract2x16 f2 fract32 Перекрестное умножение. Умножает старшую половину f1 на старшую половину f2.

[Конвертация между дробными числами и числами с плавающей запятой]

Библиотеки реального времени выполнения VisualDSP++ (VisualDSP++ run-time libraries) содержат высокоуровневую поддержку для преобразования между дробными числами (fractional) и числами с плавающей запятой (floating-point). Под дробными числами понимаются числа с фиксированной точкой, которые могут аппаратно обрабатываться процессорами Blackfin так же быстро, как целые числа (у процессоров Blackfin нет аппаратной поддержки вычислений с плавающей точкой). Подключаемый файл fract2float_conv.h определяет функции, которые выполняют преобразования между типами fract16, fract32 и float.

VisualDSP++ GCC аргумент вернет Описание
fr16_to_fr32   fract16 fract32 Расширяет fract16 так, чтобы получить fract32.
fr32_to_fr16   fract32 fract16 Обрезает fract32, чтобы получить fract16.
float_to_fr32   float fract32 Преобразует float в fract32.
float_to_fr16   float fract16 Преобразует float в fract16.
fr16_to_float   fract16 float Преобразует fract16 в float.
fr32_to_float   fract32 float Преобразует fract32 в float.

[Поддержка ETSI]

VisualDSP++ для процессоров Blackfin предоставляет подпрограммы поддержки стандартов European Telecommunications Standards Institute (ETSI) в библиотеке libetsi*.dlb library. Коллекция компилятора GNU (GCC) не имеет таких функций.

Функции истории и декодирования Витерби. VisualDSP++ для Blackfin предоставляет 4 функции Viterbi, позволяющие выполнять левый или правый сдвиг. Коллекция компилятора GNU (GCC) не имеет таких функций.

[Работа с кольцевым буфером]

Встроенная функция circptr позволяет программисту реализовать кольцевой буфер в коде C или C++, используя при этом выделенные для кольцевого буфера регистры процессора Blackfin.

VisualDSP++ GCC аргументы            вернет Описание
circptr __builtin_bfin_circptr void *ptr,
long incr,
void * base,
unsigned long bufle
void* ptr = __builtin_bfin_circptr(ptr, sizeof *ptr, buf, sizeof buf); возвратит инкрементированный указатель в буфере, с переходом по кругу в начало буфера, если был достигнут конец буфера.

[Endianness]

Имеются 2 встроенные функции, предназначенные для перевода представления данных в памяти из big-endian в little-endian, и наоборот [6].

VisualDSP++ GCC аргумент вернет Описание
byteswap4   int int byteswap4(0x12345678) возвратит 0x78563412.
byteswap2   short short byteswap2(0x1234) возвратит 0x3412.

[Системные встроенные функции]

Следующие встроенные функции позволяют получить доступ к системным возможностям процессоров Blackfin. Все функции, вызываемые gcc, получают префикс __builtin_bfin_.

VisualDSP++ GCC аргумент вернет Описание
idle   void void Переводит процессор в режим ожидания (idle mode).
csync csync void void Синхронизация только для ядра - команда сбрасывает конвейер и сохраняет буферы.
ssync ssync void void Синхронизация системы, и эта команда также ждет инструкцию ACK от системной шины.

[Производительность компилятора]

Эти встроенные функции предоставляют компилятору информацию об ожидаемом поведении программы. Вы можете использовать их, чтобы указать компилятору, какие части программы будут чаще всего выполнены; тогда компилятор может попытаться перетасовать указанный код так, чтобы он выполнялся более эффективно.

VisualDSP++ аргумент вернет GCC аргументы вернет Описание
expected_true int cond int __builtin_expect long exp, long c long Говорит компилятору, что эта часть программы более предпочтительна для выполнения.
expected_false int cond int !__builtin_expect long exp, long c long Говорит компилятору, что эта часть программы менее желательна для выполнения.

Например, рассмотрим следующий код:

int example(int call_the_function, int value)
{
   int r = 0;
   if (call_the_function)
      r = func(value);
   return r;
}

Если Вы ожидаете, что вызов функции call_the_function вернет true в большинстве случаев, то можете написать эту функцию следующим образом:

int example(int call_the_function, int value)
{
   int r = 0;
   if (__builtin_expected_true(call_the_function))
      r = func(value);
   return r;
}

Это даст информацию компилятору, что Вы ожидаете результат call_the_function равным true для большинства случаев, и опираясь на это компилятор установит вызов функции func() в ветвь кода по умолчанию. Аналогично используется обратная встроенная функция __builtin_expected_false, она используется в том случае, когда в проверке if чаще всего ожидается результат false:

int example(int call_the_function, int value)
{
   int r = 0;
   if (__builtin_expected_false(call_the_function))
      r = func(value);
   return r;
}

В результате компилятор так скомпонует генерируемый код, что по умолчанию будет выполняться ветвь без вызова func().

Эти встроенные функции не меняют алгоритм генерируемого кода. Вместо этого они показывают компилятору, какой код наиболее вероятен для выполнения, и компилятор вставляет этот код в ветвь, которая будет выполняться наиболее быстро. Такая оптимизация особенно полезна, когда проверки ветвления осуществляются в высоконагруженном цикле с большим количеством итераций.

Функции __builtin_expected_true и __builtin_expected_false дают эффект только тогда, когда в компиляторе разрешена оптимизация. Они поддерживаются только в выражениях проверки условия.

Встроенные функции, оптимизирующие код по ожидаемому значению. Функция __builtin_assert() предоставляет компилятору информацию о значениях переменных, которые можно или нельзя вывести (определить) из контекста. Для примера рассмотрим код:

int example(int value, int loop_count) 
{
   int r = 0;
   int i;
 
   for (i = 0; i < loop_count; i++)
   {
      r += value;
   }
   return r;
}

У компилятора нет способа узнать, какие значения могут быть переданы в функцию. Если Вы знаете о том, что количество итераций цикла loop_count всегда больше 4, то можете позволить оптимизатору использовать эту информацию с помощью __builtin_assert().

int example(int value, int loop_count)
{
   int r = 0;
   int i;
 
   __builtin_assert(loop_count > 4);
   for (i = 0; i < loop_count; i++)
   {
      r += value;
   }
   return r;
}

Оптимизатор теперь может опустить проход по телу цикла, которое иначе соответствовало бы loop_count == 0. В более сложном коде возможны еще более улучшенные оптимизации, когда известны границы значений переменных.

[Работа с упакованными 16-битными целыми числами]

Компилятор предоставляет встроенные функции, которые манипулируют переменными и выполняют базовые операции над двумя 16-разрядными числами, упакованными в один 32-битный тип int2x16. Использование встроенных функций приводит к оптимальным последовательностям выполнения кода с использованием векторизованных операций, где это возможно.

VisualDSP++ GCC аргументы вернет Описание
compose_i2x16 compose_2x16 short _x, short _y int2x16  
high_of_i2x16 extract_hi int2x16 _x short  
low_of_i2x16 extract_lo int2x16 _x short  

[Работа с комплексными числами]

Следующие функции используются для умножения комплексных чисел. Старшая половина аргумента вектора 2x16 назначена для мнимой части, и младшая половина назначена для вещественной части комплексного числа. Все функции, вызываемые gcc, получают префикс __builtin_bfin_.

VisualDSP++ GCC аргумент вернет Описание
cmlt_fr16 cmplx_mul fract2x16 f1, fract2x16 f2 fract2x16 Интерпретирует 2x16 векторные аргументы как комплексные числа, и умножает их.
cmac_fr16 cmplx_mac fract2x16 f1, fract2x16 f2, fract2x16 f3 fract2x16 Интерпретирует 2x16 векторные аргументы как комплексные числа, умножает последние два аргумента и прибавляет первый (MAC).
cmsu_fr16 cmplx_msu fract2x16 f1, fract2x16 f2, fract2x16 f3 fract2x16 Интерпретирует 2x16 векторные аргументы как комплексные числа, умножает последние два и затем из результата вычитает первый аргумент.

[Некоторые функции GCC, которых нет у VisualDSP++]

Все функции, вызываемые gcc, получают префикс __builtin_bfin_.

VDSP++ GCC аргумент    вернет Описание
  dspaddsubsat fract2x16 f1, fract2x16 f2 fract2x16 Выполняет 16-битное сложение старшей половины двух входных параметров и 16-битное вычитание двух младших половин входных параметров. На результат действует насыщение.
  dspsubaddsat fract2x16 f1, fract2x16 f2 fract2x16 Выполняет 16-битное вычитание старших половин двух входных параметров и 16-битное сложение младших половин двух входных параметров. На результат действует насыщение.
  mulhisill fract2x16 f1, fract2x16 f2 int Выполняет 16-битное умножение младшей половины первого параметра и младшей половины второго параметра.
  mulhisihl fract2x16 f1, fract2x16 f2 int Выполняет 16-битное умножение старшей половины первого параметра и младшей половины второго параметра.
  mulhisilh fract2x16 f1, fract2x16 f2 int Выполняет 16-битное умножение младшей половины первого параметра и старшей половины второго параметра.
  mulhisihh fract2x16 f1, fract2x16 f2 int Выполняет 16-битное умножение старшей половины первого параметра и старшей половины второго параметра.
  lshl_fr2x16 fract2x16 f1, short shft fract2x16 Сдвиг вектора (с модификатором (V)), либо влево, либо вправо.

Пример использования этих примитивов можно найти в оптимизированных алгоритмах вычисления FFT (БПФ) [4, 5].

[Ссылки]

1Blackfin GCC Built-in Functions site:blackfin.uclinux.org.
2VisualDSP: использование типов с фиксированной точкой.
3Библиотека Blackfin DSP Run-Time, общее описание.
4Библиотека Blackfin DSP Run-Time, справочник функций.
5EXAMPLE BUILTIN As applied to the FFT site:blackfin.uclinux.org.
6Порядок следования байт (endianness).
7. Опции командной строки компилятора Blackfin.
8VisualDSP: использование форматов переменных.
9Поддержка традиционных типов с фиксированной точкой в VisualDSP++.

 

Добавить комментарий


Защитный код
Обновить

Top of Page