簡體   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