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