Як я можу сказати gcc не вбудовувати функцію?


126

Скажіть, у мене є ця невелика функція у вихідному файлі

static void foo() {}

і я будую оптимізовану версію свого бінарного файлу, але я не хочу, щоб ця функція була вбудованою (для оптимізації). чи є макрос, який я можу додати у вихідний код, щоб запобігти вставці?


Дякую за це запитання! Я профілював oprofile, коли функція не з’явилася, відповіді тут виправлені.
Саймон А. Егстер

Відповіді:


149

Ви хочете атрибут gcc-specific noinline.

Цей атрибут функції запобігає врахуванню функції для вбудовування. Якщо функція не має побічних ефектів, існують інші оптимізації, крім вбудованих, що призводить до оптимізації викликів функцій, хоча виклик функції є в реальному часі. Щоб запобігти оптимізації таких дзвінків, поставте asm ("");

Використовуйте його так:

void __attribute__ ((noinline)) foo() 
{
  ...
}

32
Використовуючи gcc 4.4.3 в Arch Linux, я отримую помилку синтаксису з атрибутом, розміщеним як вище. Працює правильно, коли вона передує функції (наприклад, атрибут ((noinline)) void foo () {})
mrkj

2
Ардуїно також хотів, щоб це було поставлено перед функцією.
Пітер Н Льюїс

2
Відредаговано для виправлення синтаксису атрибута.
Квомплусон

1
Конструкція asm ("") насправді є досить платформою і виконала роботу. Я зробив це для x86 Linux, і це не спричинило проблеми з побудовою на PowerPC AIX. Дякуємо за цю корисну пропозицію!
Марті

1
Підхід, який потребує змін коду скрізь, не може бути розумно вважатися прийнятною відповіддю.
ajeh

31

GCC має перемикач, який називається

-fno-inline-small-functions

Тому використовуйте це, коли викликаєте gcc. Але побічний ефект полягає в тому, що всі інші невеликі функції також не вбудовані.


Не працював на рівні компілятора. Використовував gcc 5.2.1 20150902 (Red Hat 5.2.1-2)
Джон Грін

Або поточний GCC 6.4 порушений, або це та простіше -fno-inlineвзагалі не працює. gdbяк і раніше вводить методи на перехід. Щось порушено, і я сумніваюся, що це так gdb.
ajeh

Він вимкне вбудовану оптимізацію для всіх, а не лише для визначеної функції.
де23

@ajeh Не вбудовані функції означають, що вони викликаються нормально, чи не так?
Мелебій

21

Портативний спосіб зробити це - викликати функцію через покажчик:

void (*foo_ptr)() = foo;
foo_ptr();

Хоча це дає різні вказівки щодо галузей, що може не бути вашою метою. Що призводить точку хорошого: що це ваша мета?


2
Якщо вказівник визначений в області файлу, а не статичний, він повинен працювати, оскільки компілятор тоді не може припустити, що він має своє початкове значення під час використання. Якщо це локальний (як показано), він майже напевно трактується так само, як foo (). ("У цьому десятилітті", додав він, дивлячись на дати)
greggo

16

Я знаю, що питання стосується GCC, але я подумав, що може бути корисним мати деяку інформацію про компілятори та інших компіляторів.

noinline Функціональний атрибут GCC досить популярний і у інших компіляторів. Він підтримується щонайменше:

  • Кланг (перевірити __has_attribute(noinline))
  • Компілятор Intel C / C ++ (їх документація жахлива, але я впевнений, що працює на 16.0+)
  • Oracle Solaris Studio повертається щонайменше до 12.2
  • Компілятор ARM C / C ++ назад, принаймні до 4.1
  • IBM XL C / C ++ повертається щонайменше до 10.1
  • TI 8.0+ (або 7.3+ з --gcc, що визначатиме __TI_GNU_ATTRIBUTE_SUPPORT__)

Крім того, підтримує MSVC __declspec(noinline) до Visual Studio 7.1. Intel, ймовірно, також підтримує це (вони намагаються бути сумісними і з GCC, і з MSVC), але я не намагався це перевірити. Синтаксис в основному однаковий:

__declspec(noinline)
static void foo(void) { }

PGI 10.2+ (і, можливо, старші) підтримує a noinline прагму, яка застосовується до наступної функції:

#pragma noinline
static void foo(void) { }

TI 6.0+ підтримує FUNC_CANNOT_INLINE прагму, яка (прикро) працює по-різному в C і C ++. У C ++ він схожий на PGI:

#pragma FUNC_CANNOT_INLINE;
static void foo(void) { }

Однак у C потрібна назва функції:

#pragma FUNC_CANNOT_INLINE(foo);
static void foo(void) { }

Cray 6.4+ (можливо, і раніше) застосовує аналогічний підхід, вимагаючи назви функції:

#pragma _CRI inline_never foo
static void foo(void) { }

Oracle Developer Studio також підтримує прагму, яка приймає ім'я функції, повертаючись принаймні до Forte Developer 6 , але зауважте, що вона повинна відповідати після декларації навіть у останніх версіях:

static void foo(void);
#pragma no_inline(foo)

Залежно від того, наскільки ви присвячені, ви можете створити макрос, який буде працювати всюди, але вам потрібно мати ім'я функції, а також декларацію в якості аргументів.

Якщо, OTOH, у вас все в порядку з чимось, що працює для більшості людей, ви можете піти від чогось, що є естетичніше і не вимагає повторення. Це такий підхід, який я застосував до Hedley , де виглядає поточна версія HEDLEY_NEVER_INLINE :

#if \
  HEDLEY_GNUC_HAS_ATTRIBUTE(noinline,4,0,0) || \
  HEDLEY_INTEL_VERSION_CHECK(16,0,0) || \
  HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
  HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
  HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
  HEDLEY_TI_VERSION_CHECK(8,0,0) || \
  (HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
#  define HEDLEY_NEVER_INLINE __attribute__((__noinline__))
#elif HEDLEY_MSVC_VERSION_CHECK(13,10,0)
#  define HEDLEY_NEVER_INLINE __declspec(noinline)
#elif HEDLEY_PGI_VERSION_CHECK(10,2,0)
#  define HEDLEY_NEVER_INLINE _Pragma("noinline")
#elif HEDLEY_TI_VERSION_CHECK(6,0,0)
#  define HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

Якщо ви не хочете використовувати Hedley (це єдиний загальнодоступний домен / заголовок CC0), ви можете конвертувати макроси для перевірки версій без особливих зусиль, але більше, ніж я готовий вкласти ☺.


Дякуємо за посилання на ваш проект @nemequ. Я попросив інших наших розробників оцінити це для нашого використання. У нас різноманітна архітектура.
Дайсуке

Мені б дуже цікаво знати, що вони говорять, особливо якщо вони не зацікавлені. І, звичайно, я збираюся відповідати на запитання (трекер випуску GitHub, електронна пошта, що завгодно…).
nemequ

14

Якщо ви отримаєте помилку компілятора для __attribute__((noinline)), ви можете просто спробувати:

noinline int func(int arg)
{
    ....
}

10
static __attribute__ ((noinline))  void foo()
{

}

Це те, що працювало для мене.


8

Використовуйте noinline атрибут :

int func(int arg) __attribute__((noinline))
{
}

Ймовірно, ви повинні використовувати його як при оголошенні функції для зовнішнього використання, так і під час написання функції.


2

Я працюю з gcc 7.2. Мені спеціально була потрібна функція, щоб вона не була вбудованою, тому що її потрібно було інстанціювати в бібліотеці. Я спробував __attribute__((noinline))відповідь, як іasm("") відповідь. Жоден із них не вирішив проблему.

Нарешті, я зрозумів, що визначення статичної змінної всередині функції змусить компілятор виділити для неї простір у блоці статичної змінної та здійснити ініціалізацію для неї, коли функція вперше викликається.

Це свого роду брудна хитрість, але вона працює.


Ви можете визначити свою функцію inline void foo(void) { ... }в заголовку та оголосити її extern inline void foo(void);у вихідному файлі бібліотеки. Дотримуючись семантики C99, компілятору буде дозволено вбудовувати функцію, коли воно вподобає І випускає об'єктний код у вашій бібліотеці. Дивіться, чи "inline" без "статичного" або "зовнішнього" коли-небудь корисний у C99? .
діапір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.