Come posso dire a gcc di non incorporare una funzione?

Diciamo che ho questa piccola funzione in un file sorgente

static void foo() {} 

e costruisco una versione ottimizzata del mio binario, ma non voglio che questa funzione sia in linea (per scopi di ottimizzazione). c’è una macro che posso aggiungere in un codice sorgente per evitare che si inlini?

Vuoi l’attributo noinline specifico di gcc .

Questo attributo di funzione impedisce che una funzione venga considerata per l’inlining. Se la funzione non ha effetti collaterali, ci sono ottimizzazioni diverse dalla inlining che fa sì che le chiamate di funzione vengano ottimizzate, sebbene la chiamata alla funzione sia live. Per evitare che tali chiamate vengano ottimizzate, metti asm ("");

Usalo in questo modo:

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

GCC ha chiamato un interruttore

-fno-inline-small-functions

Quindi usalo quando evochi gcc. Ma l’effetto collaterale è che tutte le altre piccole funzioni sono anche non in linea.

Un modo portatile per farlo è chiamare la funzione tramite un puntatore:

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

Anche se questo produce istruzioni diverse per la filiale, che potrebbe non essere il tuo objective. Il che evidenzia un buon punto: qual è il tuo objective qui?

Nel caso in cui si verifichi un errore del compilatore per __attribute__((noinline)) , si può semplicemente provare:

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

Questo è ciò che ha funzionato per me.

Utilizza l’ attributo noinline :

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

Probabilmente dovresti usarlo entrambi quando dichiari la funzione per uso esterno e quando scrivi la funzione.

So che la domanda riguarda GCC, ma ho pensato che potrebbe essere utile avere alcune informazioni sui compilatori anche su altri compilatori.

L’ noinline funzione noinline di GCC è piuttosto popolare anche con altri compilatori. È supportato almeno da:

  • Clang (controlla con __has_attribute(noinline) )
  • Compilatore Intel C / C ++ (la loro documentazione è terribile, ma sono sicuro che funzioni su 16.0+)
  • Oracle Solaris Studio torna almeno a 12.2
  • Compilatore ARM C / C ++ di almeno 4.1
  • IBM XL C / C ++ di nuovo almeno a 10.1
  • TI 8.0+ (o 7.3+ con –gcc, che definirà __TI_GNU_ATTRIBUTE_SUPPORT__ )

Inoltre, MSVC supporta __declspec(noinline) per Visual Studio 7.1. Probabilmente anche Intel lo supporta (cercano di essere compatibili sia con GCC che con MSVC), ma non mi sono preso la briga di verificarlo. La syntax è fondamentalmente la stessa:

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

PGI 10.2+ (e probabilmente precedente) supporta un pragma noinline che si applica alla funzione successiva:

 #pragma noinline static void foo(void) { } 

TI 6.0+ supporta un pragma FUNC_CANNOT_INLINE che (fastidiosamente) funziona in modo diverso in C e C ++. In C ++, è simile a PGI:

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

In C, tuttavia, è richiesto il nome della funzione:

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

Cray 6.4+ (e forse anche prima) ha un approccio simile, richiedendo il nome della funzione:

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

Oracle Developer Studio supporta anche un pragma che prende il nome della funzione, che risale almeno a Forte Developer 6 , ma nota che deve venire dopo la dichiarazione, anche nelle versioni recenti:

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

A seconda di quanto sei dedicato, potresti creare una macro che funzionerebbe ovunque, ma dovresti avere il nome della funzione e la dichiarazione come argomenti.

Se, OTOH, stai bene con qualcosa che funziona solo per la maggior parte delle persone, puoi farla franca con qualcosa che è un po ‘più esteticamente gradevole e non richiede di ripetere te stesso. Questo è l’approccio che ho seguito per Hedley , dove la versione attuale di HEDLEY_NEVER_INLINE è simile a:

 #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 

Se non vuoi usare Hedley (è un singolo header di pubblico dominio / CC0) puoi convertire i macro di controllo di versione senza troppa fatica, ma più di quanto io sia disposto a inserire in ☺.

Lavoro con gcc 7.2. In particolare, avevo bisogno che una funzione fosse non-in-linea, perché doveva essere istanziata in una libreria. Ho provato la __attribute__((noinline)) , così come la risposta asm("") . Nessuno dei due ha risolto il problema.

Infine, ho pensato che la definizione di una variabile statica all’interno della funzione costringerebbe il compilatore ad allocare lo spazio per esso nel blocco di variabili statiche e ad emetterne un’inizializzazione quando la funzione viene chiamata per la prima volta.

È una specie di trucco sporco, ma funziona.