¿Cómo puedo decirle a gcc que no ponga en línea una función?

Digamos que tengo esta pequeña función en un archivo fuente

static void foo() {} 

y construyo una versión optimizada de mi binario, pero no quiero que esta función esté en línea (para fines de optimización). ¿Existe una macro que pueda agregar en un código fuente para evitar la creación de líneas?

Desea el atributo noinline específico de gcc .

Este atributo de función evita que se considere una función para alinear. Si la función no tiene efectos secundarios, existen optimizaciones distintas de la línea interna que hacen que las llamadas a funciones se optimicen, aunque la llamada a la función es en vivo. Para evitar que esas llamadas se optimicen, coloque asm ("");

Úselo así:

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

GCC tiene un interruptor llamado

-fno-inline-small-functions

Así que úsalo cuando evoques gcc. Pero el efecto secundario es que todas las otras funciones pequeñas tampoco están en línea.

Una forma portátil de hacerlo es llamar a la función a través de un puntero:

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

Aunque esto produce diferentes instrucciones para ramificar, que puede no ser tu objective. Lo cual trae a colación un buen punto: ¿cuál es tu objective aquí?

En caso de que obtenga un error de __attribute__((noinline)) para __attribute__((noinline)) , puede simplemente intentar:

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

Esto es lo que funcionó para mí.

Use el atributo noinline :

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

Probablemente debería usarlo tanto cuando declara la función para uso externo como cuando escribe la función.

Sé que la pregunta es sobre GCC, pero pensé que podría ser útil tener también información sobre comstackdores y otros comstackdores.

El atributo de función noinline de GCC es bastante popular también con otros comstackdores. Es apoyado por al menos:

  • Clang (verificar con __has_attribute(noinline) )
  • Comstackdor Intel C / C ++ (su documentación es terrible, pero estoy seguro de que funciona en 16.0+)
  • Oracle Solaris Studio vuelve al menos a 12.2
  • Comstackdor de ARM C / C ++ de nuevo a al menos 4.1
  • IBM XL C / C ++ vuelve al menos a 10.1
  • TI 8.0+ (o 7.3+ con –gcc, que definirá __TI_GNU_ATTRIBUTE_SUPPORT__ )

Además, __declspec(noinline) admite __declspec(noinline) vuelta a Visual Studio 7.1. Intel probablemente también lo respalde (intentan ser compatibles tanto con GCC como con MSVC), pero no me he molestado en verificarlo. La syntax es básicamente la misma:

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

PGI 10.2+ (y probablemente más antiguo) es compatible con un pragma noinfinito que se aplica a la siguiente función:

 #pragma noinline static void foo(void) { } 

TI 6.0+ admite un pragma FUNC_CANNOT_INLINE que (molestamente) funciona de manera diferente en C y C ++. En C ++, es similar a las IGP:

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

En C, sin embargo, se requiere el nombre de la función:

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

Cray 6.4+ (y posiblemente antes) toma un enfoque similar, que requiere el nombre de la función:

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

Oracle Developer Studio también admite un pragma que toma el nombre de la función, que se remonta al menos a Forte Developer 6 , pero tenga en cuenta que debe venir después de la statement, incluso en versiones recientes:

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

Dependiendo de cuán dedicado esté, podría crear una macro que funcionaría en todas partes, pero necesitaría tener el nombre de la función y la statement como argumentos.

Si, OTOH, estás de acuerdo con algo que simplemente funciona para la mayoría de la gente, puedes salirte con la tuya con algo que es un poco más estético y no es necesario que te repitas. Ese es el enfoque que he tomado para Hedley , donde la versión actual de HEDLEY_NEVER_INLINE se ve así:

 #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 

Si no quiere usar Hedley (es un solo dominio público / encabezado CC0) puede convertir las macros de comprobación de versión sin demasiado esfuerzo, pero más de lo que estoy dispuesto a poner ☺.

Yo trabajo con gcc 7.2. Específicamente necesitaba que una función no estuviera en línea, porque tenía que crearse una instancia en una biblioteca. __attribute__((noinline)) la __attribute__((noinline)) , así como la respuesta asm("") . Ninguno de los dos resolvió el problema.

Finalmente, calculé que la definición de una variable estática dentro de la función forzará al comstackdor a asignarle espacio en el bloque de variable estática y emitirá una inicialización cuando se llame por primera vez a la función.

Esto es una especie de truco sucio, pero funciona.