Страницы

Поиск по вопросам

воскресенье, 24 ноября 2019 г.

Что такое интринсики (intrinsics)?


Объясните, пожалуйста, что такое интринсики?
    


Ответы

Ответ 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-функции, он теоретически может извлечь из этог определения полное знание о семантике этой функции. Но на этом сходство и заканчивается. В случае интринсиков компилятору не нужно ничего ниоткуда извлекать: полное знание о семантике интринсика уже изначально заложено в компилятор его авторами.

Комментариев нет:

Отправить комментарий