Объясните, пожалуйста, что такое интринсики?
Ответы
Ответ 1
Вот конкретный пример из VC++.
#pragma intrinsic(strlen)
int main(int argc, const char * argv[])
{
cout << strlen(argv[0]);
}
Компилируем с отключенной оптимизацией (/Od). При наличии #pragma intrinsic(strlen) получаем
mov eax, 4
imul ecx, eax, 0
mov edx, DWORD PTR _argv$[ebp]
mov eax, DWORD PTR [edx+ecx]
mov DWORD PTR tv74[ebp], eax
mov ecx, DWORD PTR tv74[ebp]
add ecx, 1
mov DWORD PTR tv77[ebp], ecx
$LL3@main:
mov edx, DWORD PTR tv74[ebp]
mov al, BYTE PTR [edx]
mov BYTE PTR tv80[ebp], al
add DWORD PTR tv74[ebp], 1
cmp BYTE PTR tv80[ebp], 0
jne SHORT $LL3@main
mov ecx, DWORD PTR tv74[ebp]
sub ecx, DWORD PTR tv77[ebp]
mov DWORD PTR tv70[ebp], ecx
mov edx, DWORD PTR tv70[ebp]
push edx
mov ecx, OFFSET ?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
А при отсутствии -
mov eax, 4
imul ecx, eax, 0
mov edx, DWORD PTR _argv$[ebp]
mov eax, DWORD PTR [edx+ecx]
push eax
call _strlen
add esp, 4
push eax
mov ecx, OFFSET ?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@I@Z ; std::basic_ostream >::operator<<
(Для информации - при включенной оптимизации одинаково в обоих случаях -
mov eax, DWORD PTR _argv$[esp-4]
mov eax, DWORD PTR [eax]
lea edx, DWORD PTR [eax+1]
npad 7
$LL3@main:
mov cl, BYTE PTR [eax]
inc eax
test cl, cl
jne SHORT $LL3@main
sub eax, edx
mov ecx, OFFSET ?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
push eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@I@Z ; std::basic_ostream >::operator<<
Т.е. в определенном смысле это inline-функции, только с заранее готовым ассемблерным кодом...
Ответ 2
В С/С++ любая сущность, объявленная, но не определённая в пределах компилируемог
файла считается внешней. Это относится и к функциям в не меньшей степени, к чем к переменным
Ссылки на внешние функции остаются в скомпилированном объектном файле и будут заменен
на обращения к настоящим сущностям только на этапе линковки, если все межмодульные зависимост
будут удовлетворены. Не существует никакой разницы между PrivetVasya() и printf()
с точки зрения компилятора обе абсолютно равнозначны и про обе можно сказать «да эт
просто какие-то внешние функции». Когда идиотские учебники или учителя-недоучки начинаю
говорить «встроенная функция языка printf()» (а это очень популярный бред) — надо понимать, что это просто глупость, что в язык ничего такого не встроено, что компилятор обрабатывает вызов к printf() на тех же условиях, что и вызов к любой другой функции, да хоть в соседнем файле реализованной. Что касается той же printf() — то это не встроенная функция языка, а функция стандартной библиотеки языка. Стандарт на язык эту функцию описывает, провозглашает её наличие в стандартной библиотеке, но сам компилятор к стандартной библиотеке отношения не имеет — она может появиться на этапе линковки, а может и вообще не появляться.
Тем не менее, есть поистине встроенные функции, для которых в компиляторе на само
деле реализована особая обработка — они называются intrinsic-ами. У разных компиляторо
набор intrinsic-ов разный. Intrinsic-ом может быть и функция, которая штатно должн
жить в стандартной библиотеке. При вызове intrinsic-функции компилятор генерирует особый код, характерный именно для данной функции: не генерируется никакого call-а, не будет никакого реального вызова и возврата, а будет несколько инструкций, выполняющих нужную задачу. Например очень распространённый intrinsic memcpy() компилируется не в вызов какой-то функции, а в инструкцию repnz movs (пример для x86).
Понятное дело, что в стандартной библиотеке С (libc) для AVR есть некоторые функции
которые обеспечивают задержку. Естественно, это полновесные функции, которые внутр
крутят цикл. Если нужна задержка в 1—2 такта, то естественно, такие тяжеловесные функции не подходят. Сделать задержку в 1 такт полноценной (и обыкновенной) функцией нельзя: даже если это будет совершенно пустая функция, инструкция call выполняется за 4 такта, и инструкция ret — ещё 4 такта, итого 8 тактов на вызов пустой функции.
Без малейшей лишней мысли понятно, что задержки в единицы тактов (меньше 8) могу
быть реализованы только intrinsic-ами. И теперь, скрестив пальцы, спросим: а есть ли в avr-gcc delay-функции (функции задержки), выполненные как intrinsic-и? Действительно есть такой intrinsic — функция называется __builtin_avr_delay_cycles().
Источник: Фейл gcc (или назвался intrinsic'ом — полезай в оптимизатор).
Ответ 3
Интринсики — это функции, вызовы которых заменяются компилятором на некую внутрикомпиляторну
магию. То есть вы думаете, что вызываете функцию, но на самом деле её не существует, и вместо неё напрямую подставляется некий машинный код вне зависимости от флагов оптимизации.
Ответ 4
Intrinsic - это обёртка над функциями, которая встроена в компилятор, в таком ж
виде, как и обычные функции. Иными словами можно сказать, что это механизм включения машинных инструкций в код.
Полезные ссылки для ознакомления:
Intrinsic function (en WiKi)
Встроенные объекты компилятора
What are intrinsics? (en SO)
Ответ 5
Интринсиками в терминологии С и С++ называются сущности (обычно функции), которы
с одной стороны формально не являются частью ядра языка (т.е. формально это сущности библиотечного уровня), но семантика которых тем не менее досконально и исчерпывающе известна компилятору.
Например, с формальной точки зрения стандартная функция strcmp является обычной библиотечно
функцией. Компилятор не знает об этой функции ничего, кроме информации, содержащейс
в ее объявлении: список и типы параметров и тип возвращаемого значения. Компилятор не знает, чему равно strcmp("abc", "abc") и не знает, меняет ли функция strcmp глобальньую переменную int vasya;.
Однако в некоторых реализациях эта функция может быть интринсиком: компилятор може
обладать исчерпывающей информацией о том, что именно делает и чего не делает эта функци
и использовать эту информацию в процессе генерации кода и выполнения оптимизаций. Реализация, в которой strcmp является интриниском, знает, что вызов strcmp("abc", "abc") можно заменить на константу 0 и что функция strcmp не меняет никаких глобальных переменных.
Можно сказать, что интринсики в чем-то похожи на inline-функции. Так как компилято
всегда видит полное определение inline-функции, он теоретически может извлечь из этог
определения полное знание о семантике этой функции. Но на этом сходство и заканчивается. В случае интринсиков компилятору не нужно ничего ниоткуда извлекать: полное знание о семантике интринсика уже изначально заложено в компилятор его авторами.
Комментариев нет:
Отправить комментарий