繁体   English   中英

我如何告诉 gcc 不要内联函数?

[英]How can I tell gcc not to inline a function?

假设我在源文件中有这个小函数

static void foo() {}

我构建了我的二进制文件的优化版本,但我不想内联此函数(出于优化目的)。 有没有我可以在源代码中添加的宏来防止内联?

您需要特定于gcc noinline属性。

此函数属性可防止考虑内联函数。 如果函数没有副作用,除了内联之外还有其他优化会导致函数调用被优化掉,尽管函数调用是实时的。 为了防止这些调用被优化掉,把asm ("");

像这样使用它:

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

GCC 有一个开关叫做

-fno-inline-small-functions

所以在调用 gcc 时使用它。 但副作用是所有其他小函数也是非内联的。

一种可移植的方法是通过指针调用函数:

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

尽管这会产生不同的分支指令,但这可能不是您的目标。 这提出了一个好观点:你在这里的目标什么?

我知道这个问题是关于 GCC 的,但我认为获得一些关于编译器和其他编译器的信息可能会很有用。

GCC 的noinline函数属性在其他编译器中也很受欢迎。 它至少得到以下支持:

  • Clang(检查__has_attribute(noinline)
  • Intel C/C++ Compiler(他们的文档很糟糕,但我确定它适用于 16.0+)
  • Oracle Solaris Studio 至少回到 12.2
  • ARM C/C++ 编译器至少回到 4.1
  • IBM XL C/C++ 至少回到 10.1
  • TI 8.0+(或带有 --gcc 的 7.3+,它将定义__TI_GNU_ATTRIBUTE_SUPPORT__

此外,MSVC 支持__declspec(noinline)回到 Visual Studio 7.1。 英特尔可能也支持它(他们试图与 GCC 和 MSVC 兼容),但我没有费心去验证。 语法基本相同:

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

PGI 10.2+(可能更旧)支持适用于下一个函数的noinline pragma:

#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 标头),您可以毫不费力地转换版本检查宏,但比我愿意投入的要多 ☺。

如果您收到__attribute__((noinline))的编译器错误,您可以尝试:

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

}

这对我有用。

使用noinline属性

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

在声明函数供外部使用时和编写函数时,您可能都应该使用它。

我使用 gcc 7.2。 我特别需要一个非内联函数,因为它必须在库中实例化。 我尝试了__attribute__((noinline))答案,以及asm("")答案。 没有一个人解决了这个问题。

最后,我认为在函数内定义一个静态变量将迫使编译器在静态变量块中为其分配空间,并在首次调用该函数时为其发出初始化。

这是一个肮脏的把戏,但它有效。

我无法让__attribute__((noinline))工作,但这适用于 clang 和 GCC。

Linux 内核定义了noinline

include/linux/compiler_attributes.h:#define noinline __attribute__((__noinline__))
#include <linux/kernel.h>
static noinline void foo(void);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM