Как я могу сказать gcc не встроить функцию?


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

static void foo() {}

и я создаю оптимизированную версию моего двоичного файла, но я не хочу, чтобы эта функция была встроена (для целей оптимизации). есть ли макрос, который я могу добавить в исходный код, чтобы предотвратить встраивание?

8 99

8 ответов:

вы хотите gcc - specific noinline.

этот атрибут функции предотвращает функции рассматриваются встраивание. Если функция не есть побочные эффекты, есть оптимизации, отличные от встраивания этого причины вызова функции должны быть оптимизированы прочь, хотя вызов функции жить. Чтобы такие звонки не были оптимизировать, поставить asm ("");

использовать его как это:

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

GCC имеет переключатель под названием

-fno-inline-small-functions

Так что используйте это при вызове gcc. Но побочным эффектом является то, что все другие небольшие функции также не встроены.

портативный способ сделать это-вызвать функцию через указатель:

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

хотя это создает различные инструкции для ветвления, которые могут не быть вашей целью. Что поднимает хороший вопрос: что и ваша цель здесь?

в случае, если вы получаете ошибку компилятора для __attribute__((noinline)), вы можете просто попробовать:

noinline int func(int arg)
{
    ....
}
static __attribute__ ((noinline))  void foo()
{

}

Это то, что работал для меня.

использовать noinlineатрибут:

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

вероятно, вы должны использовать его как при объявлении функции для внешнего использования, так и при написании функции.

Я знаю, что вопрос о GCC, но я подумал, что это может быть полезно есть некоторая информация о компиляторах других компиляторов, а также.

GCC noinline атрибут функции довольно популярен и у других компиляторов. Оно поддерживается по крайней мере:

  • Clang (проверьте с __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 + поддерживает a 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 также поддерживает прагму, которая принимает имя функции, возвращаясь к по крайней мере разработчик Форте 6, но обратите внимание, что он должен прийти после декларация, даже в последнее время версии:

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

в зависимости от того, насколько вы преданы, вы можете создать макрос, который будет работать везде, но вам нужно будет иметь имя функции как а также декларации в качестве аргументов.

если, Ото, ты в порядке с чем-то, что просто работает для большинства людей, вы можете уйти с чем-то, что немного более эстетично приятно и не требует повторения себя. Вот такой подход Я принял за Хедли, где текущая версия 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) && defined(__cplusplus)
#  define HEDLEY_NO_RETURN _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

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

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

наконец, я понял, что определение статической переменной внутри функции заставит компилятор выделить для нее место в блоке статической переменной и инициализировать ее при первом вызове функции.

Это своего рода грязный трюк, но он работает.