Como posso dizer ao gcc para não incorporar uma função?

126

Digamos que eu tenho essa pequena função em um arquivo de origem

static void foo() {}

e eu construo uma versão otimizada do meu binário, mas não quero essa função incorporada (para fins de otimização). existe uma macro que eu possa adicionar em um código fonte para impedir o inlining?

vehomzzz
fonte
Obrigado por esta pergunta! Eu estava criando um perfil com oprofile quando uma função não aparecia, as respostas aqui corrigiam isso.
Simon A. Eugster
c ++: stackoverflow.com/questions/3329214/…
Ciro Santilli escreveu:

Respostas:

149

Você quer o gccespecíficonoinline atributo .

Esse atributo de função impede que uma função seja considerada para embutir. Se a função não tiver efeitos colaterais, há outras otimizações além do inlining que fazem com que as chamadas de função sejam otimizadas, embora a chamada de função esteja ativa. Para impedir que essas chamadas sejam otimizadas, coloque asm ("");

Use-o assim:

void __attribute__ ((noinline)) foo() 
{
  ...
}
alex formigamento
fonte
32
Usando o gcc 4.4.3 no Arch Linux, recebo um erro de sintaxe com o atributo colocado como acima. Funciona corretamente quando precede a função (por exemplo, attribute ((noinline)) void foo () {})
mrkj:
2
O Arduino também queria que ele fosse colocado antes da função.
Peter N Lewis
2
Editado para corrigir a sintaxe do atributo.
Quuxplusone
1
A construção asm ("") é na verdade bastante multiplataforma e fez o trabalho. Eu fiz isso para o Linux x86 e não causou um problema de construção no PowerPC AIX. Obrigado por esta sugestão útil!
287 Marty
1
A abordagem que requer alterações de código em qualquer lugar não pode ser razoavelmente considerada uma resposta aceitável.
31818 Ajeh
31

O GCC tem um comutador chamado

-fno-inline-small-functions

Portanto, use isso ao invocar o gcc. Mas o efeito colateral é que todas as outras funções pequenas também não são incorporadas.

lukmac
fonte
Não funcionou no nível do compilador. Estava usando o gcc 5.2.1 20150902 (Red Hat 5.2.1-2)
John Greene
O GCC 6.4 atual está quebrado ou isso e mais simples -fno-inlinenão funcionam. gdbainda entra os métodos no step-over. Algo está quebrado, e eu duvido que esteja gdb.
ajeh
Ele desativará a otimização embutida para todos, não apenas para uma função especificada.
where23
@ajeh Não incluir funções inline significa que elas são chamadas normalmente, não é?
Melebius
21

Uma maneira portátil de fazer isso é chamar a função através de um ponteiro:

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

Embora isso produza instruções diferentes para ramificação, o que pode não ser seu objetivo. O que traz um bom ponto: qual é o seu objetivo aqui?

Andy Ross
fonte
2
Se o ponteiro estiver definido no escopo do arquivo e não estático, ele deverá funcionar, pois o compilador não poderá assumir que ele possui seu valor inicial no momento do uso. Se for local (como mostrado), certamente será tratado da mesma forma que foo (). ("Nesta década", acrescentou, observando as datas)
greggo 23/08/16
16

Eu sei que a pergunta é sobre o GCC, mas achei que poderia ser útil ter algumas informações sobre outros compiladores.

O noinline atributo de função do GCC também é bastante popular com outros compiladores. É suportado por pelo menos:

  • Clang (verifique com __has_attribute(noinline) )
  • Compilador Intel C / C ++ (a documentação deles é terrível, mas tenho certeza de que funciona no 16.0+)
  • Oracle Solaris Studio volta a pelo menos 12.2
  • Compilador ARM C / C ++ de volta a pelo menos 4.1
  • IBM XL C / C ++ de volta a pelo menos 10.1
  • TI 8.0+ (ou 7.3+ com --gcc, que definirá __TI_GNU_ATTRIBUTE_SUPPORT__)

Além disso, o MSVC oferece suporte __declspec(noinline) ao Visual Studio 7.1. A Intel provavelmente também suporta (eles tentam ser compatíveis com o GCC e o MSVC), mas não me preocupei em verificar isso. A sintaxe é basicamente a mesma:

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

A PGI 10.2+ (e provavelmente mais antiga) suporta um noinlinepragma que se aplica à próxima função:

#pragma noinline
static void foo(void) { }

A TI 6.0+ suporta um FUNC_CANNOT_INLINE pragma que (irritantemente) funciona de maneira diferente em C e C ++. No C ++, é semelhante ao IGP:

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

Em C, no entanto, o nome da função é necessário:

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

O Cray 6.4+ (e possivelmente anterior) adota uma abordagem semelhante, exigindo o nome da função:

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

O Oracle Developer Studio também suporta um pragma que leva o nome da função, que remonta a pelo menos o Forte Developer 6 , mas observe que ele precisa vir após a declaração, mesmo nas versões recentes:

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

Dependendo de como você é dedicado, é possível criar uma macro que funcione em qualquer lugar, mas é necessário ter o nome da função e a declaração como argumentos.

Se, OTOH, você concorda com algo que simplesmente funciona para a maioria das pessoas, você pode se safar de algo que é um pouco mais esteticamente agradável e não exige repetição. Essa é a abordagem que adotei para Hedley , onde a versão atual do HEDLEY_NEVER_INLINE se parece:

#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

Se você não quiser usar o Hedley (é um único cabeçalho de domínio público / CC0), poderá converter as macros de verificação de versão sem muito esforço, mas mais do que estou disposto a colocar ☺.

nemequ
fonte
Obrigado pelo link do seu projeto @nemequ. Pedi a nossos outros desenvolvedores para avaliá-lo para nosso uso. Temos diversas arquiteturas.
Daisuke Aramaki
Eu ficaria muito interessado em saber o que eles dizem, especialmente se não estiverem interessados. E, é claro, estou por perto para responder perguntas (rastreador de problemas do GitHub, e-mail, o que seja ...).
nemequ
14

Caso você receba um erro de compilador __attribute__((noinline)), tente:

noinline int func(int arg)
{
    ....
}
Sam Liao
fonte
10
static __attribute__ ((noinline))  void foo()
{

}

Isto é o que funcionou para mim.

KenBee
fonte
8

Use o noinline atributo :

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

Você provavelmente deve usá-lo quando declarar a função para uso externo e ao escrever a função.

Chris Lutz
fonte
2

Eu trabalho com o gcc 7.2. Eu especificamente precisava de uma função para não ser incorporada, porque tinha que ser instanciada em uma biblioteca. Eu tentei a __attribute__((noinline))resposta, bem como aasm("") resposta. Nenhum dos dois resolveu o problema.

Por fim, imaginei que definir uma variável estática dentro da função forçaria o compilador a alocar espaço para ela no bloco de variável estática e emitir uma inicialização para ela quando a função for chamada pela primeira vez.

Isso é meio que um truque sujo, mas funciona.

Ofri Sadowsky
fonte
Você pode definir sua função inline void foo(void) { ... }em um cabeçalho e declará-la extern inline void foo(void);em um arquivo de origem da biblioteca. Seguindo a semântica C99, o compilador poderia incorporar a função quando agradar E emitir código de objeto na sua biblioteca. Consulte "inline" sem "estático" ou "externo" é útil no C99? .
diapir 23/02