我怎样才能告诉gcc不要内联一个函数?

t2a7ltrp  于 2022-12-26  发布在  其他
关注(0)|答案(9)|浏览(301)

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

static void foo() {}

并且我构建了我的二进制的优化版本,但是我不希望这个函数内联(为了优化的目的)。有没有一个宏我可以在源代码中添加来防止内联?

camsedfj

camsedfj1#

您需要特定于gccnoinline属性。
此函数属性可防止考虑对函数进行内联。如果函数没有副作用,则内联以外的优化会导致函数调用被优化掉,尽管函数调用是活动的。若要防止此类调用被优化掉,请放置asm ("");
像这样使用它:

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

qxsslcnc2#

GCC有一个名为
第一个月
所以在调用gcc时使用它,但是副作用是所有其他小函数也是非内联的。

vmjh9lq9

vmjh9lq93#

我知道这个问题是关于GCC的,但我认为了解一些关于编译器和其他编译器的信息可能会很有用。
GCC的noinline函数属性在其他编译器中也很流行。至少有以下编译器支持它:

  • 叮当声(用__has_attribute(noinline)检查)
  • 英特尔C/C++编译器(他们的文档很糟糕,但我确信它能在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也支持它。Intel可能也支持它(他们试图同时兼容GCC和MSVC),但我没有费心去验证它。

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

PGI 10.2+(可能更早)支持应用于下一个函数的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还支持接受函数名的杂注,可以追溯到at least Forte Developer 6,但请注意,即使在最新版本中,它也需要出现在声明的 * 之后 *:

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

根据你的专注程度,你可以创建一个在任何地方都能工作的宏,但是你需要有函数名和声明作为参数。
OTOH,如果你觉得对大多数人都有效的东西没问题,你可以做一些更美观的东西,不需要重复。这就是我在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

如果你不想使用赫德利(它是一个公共域/CC 0头文件),你可以转换版本检查宏,而不需要太多的工作,但是我愿意花更多的精力在中。

oknrviil

oknrviil4#

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

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

虽然这会产生不同的分支指令,但这可能不是你的目标。这带来了一个好的观点:你的目标是什么?

h9vpoimq

h9vpoimq5#

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

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

a8jjtwal6#

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

}

这对我很有效。

aemubtdh

aemubtdh7#

使用noinlineattribute

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

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

kdfy810k

kdfy810k8#

我使用gcc 7.2,我特别需要一个非内联函数,因为它必须在库中示例化,我尝试了__attribute__((noinline))asm(""),但都没有解决问题。
最后,我发现在函数内部定义一个静态变量将迫使编译器在静态变量块中为它分配空间,并在第一次调用函数时为它发出初始化。
这是一种肮脏的伎俩,但它的工作。

rkkpypqq

rkkpypqq9#

我无法让__attribute__((noinline))工作,但它可以在clang和GCC上工作。
Linux内核定义了noinline

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

相关问题