Встроенная функция
Встроенная функция — это функция в программном обеспечении, в теории компиляторов, доступная для использования в данном языке программирования, реализация которой обрабатывается компилятором особым образом. Как правило, компилятор способен заменить исходный вызов функции на последовательность автоматически сгенерированных инструкций, подобно встраиваемой функции[1]. В отличие от встраиваемой функции, компилятор обладает «глубоким знанием» о встроенной функции и, таким образом, может лучше интегрировать и оптимизировать её для конкретной ситуации. Компиляторы, реализующие встроенные функции, могут активировать их только тогда, когда программа запрашивает оптимизацию, в противном случае используя реализацию по умолчанию, предоставляемую системой времени выполнения языка.
Векторизация и распараллеливание
Встроенные функции часто используются для явной реализации векторизации и распараллеливания в языках, которые не поддерживают такие конструкции. Некоторые API, например AltiVec и OpenMP, используют встроенные функции для объявления, соответственно, векторизуемых и поддерживающих многопроцессорную обработку операций на стадии компиляции. Компилятор анализирует встроенные функции и преобразует их в векторные математические или многопроцессорные объектные коды, соответствующие целевой платформе. Некоторые встроенные функции используются для предоставления дополнительных ограничений оптимизатору, например, значения, которые переменная не может принимать[2].
По языкам программирования
Компиляторы для языков C и C++ от Microsoft[3], Intel[1] и GCC[4] реализуют встроенные функции, которые напрямую отображаются на инструкции x86 типа SIMD (один поток команд, множество потоков данных) (MMX, SSE, SSE2, SSE3, SSSE3, SSE4, AVX, AVX2, AVX-512, FMA и т. д.). Встроенные функции позволяют отображать код на стандартные ассемблерные инструкции, которые обычно недоступны через C/C++: например, сканирование битов и параллельные операции над 128-битными (SSE) и 256-битными (AVX) данными.
Некоторые компиляторы C и C++ предоставляют непереносимые, платформенно-зависимые встроенные функции. Другие встроенные функции (например, встроенные функции GNU) являются более абстрактными, аппроксимируя возможности нескольких современных платформ, и имеют переносимые резервные реализации (fall back) для платформ без соответствующих инструкций[5]. Для библиотек C++, таких как glm или библиотеки векторной математики от Sony[6], распространена практика достижения переносимости с помощью условной компиляции (на основе специфичных для платформы флагов компилятора). Это позволяет предоставлять полностью переносимые высокоуровневые примитивы (например, тип четырёхэлементного вектора с плавающей запятой), отображённые на соответствующие реализации на низкоуровневых языках, сохраняя при этом преимущества системы типов C++ и встраивания; отсюда и преимущество перед компоновкой с объектными файлами, написанными вручную на ассемблере, с использованием двоичного интерфейса приложений (ABI) языка C.
Ниже приведены примеры сигнатур встроенных функций из набора Intel.
uint64_t __rdtsc (); // возвращает внутренний счётчик тактов процессора
uint64_t __popcnt64 (uint64_t n); // подсчитывает количество установленных битов в n
uint64_t _umul128 (uint64_t Factor1, uint64_t Factor2, uint64_t* HighProduct); // умножение 64 бит * 64 бит => 128 бит
__m512 _mm512_add_ps (__m512 a, __m512 b); // вычисляет a + b для двух векторов из 16 чисел с плавающей запятой
__m512 _mm512_fmadd_ps(__m512 a, __m512 b, __m512 c); // вычисляет a*b + c для трёх векторов из 16 чисел с плавающей запятой
Модуль встроенных функций для COBOL был введён в стандарте ANSI INCITS X3.23a-1989 / ISO 1989:1985/Amd 1:1992.
JIT-компилятор виртуальной машины Java (JVM) HotSpot также имеет встроенные функции для определённых API Java[8]. Встроенные функции HotSpot — это стандартные API Java, которые могут иметь одну или несколько оптимизированных реализаций на некоторых платформах.
Стандарт ANSI/ISO для языка PL/I определяет около 90 встроенных функций[9]. Их принято группировать следующим образом[10]:
- Встроенные функции для обработки строк, такие как INDEX, LENGTH;
- Арифметические встроенные функции, такие как ABS, CEIL, ROUND;
- Математические встроенные функции, такие как SIN, COS, LOG, ERF;
- Встроенные функции для обработки массивов, например ANY, ALL, PROD;
- Встроенные функции для обработки условий, такие как ONCODE, ONFILE;
- Встроенные функции управления памятью, например ADDR, POINTER;
- Встроенные функции ввода-вывода: LINENO;
- Прочие встроенные функции, такие как DATE и TIME.
Отдельные компиляторы добавляли дополнительные встроенные функции, специфичные для архитектуры машины или операционной системы.
Встроенная функция идентифицируется, если её имя не объявляется и используется по умолчанию, или если она объявляется с атрибутом BUILTIN. Предоставленная пользователем функция с тем же именем может быть подставлена, если объявить её как ENTRY.
Примечания
Ссылки
- Intel Intrinsics Guide
- Using milicode routines, документация IBM AIX 6.1 (англ.)


