web-dev-qa-db-fra.com

Comment puis-je dire à gcc de ne pas intégrer une fonction?

Disons que j'ai cette petite fonction dans un fichier source

static void foo() {}

et je construis une version optimisée de mon binaire mais je ne veux pas de cette fonction en ligne (à des fins d'optimisation). y a-t-il une macro que je peux ajouter dans un code source pour empêcher l'inline?

112
vehomzzz

Vous voulez l'attribut spécifique gcc- noinline .

Cet attribut de fonction empêche une fonction d'être prise en compte pour l'inline. Si la fonction n'a pas d'effets secondaires, il existe des optimisations autres que l'inline qui permettent d'optimiser les appels de fonction, bien que l'appel de fonction soit actif. Pour que ces appels ne soient pas optimisés, mettez asm ("");

Utilisez-le comme ceci:

void __attribute__ ((noinline)) foo() 
{
  ...
}
134
alex tingle

GCC a un commutateur appelé

-fno-inline-small-functions

Donc, utilisez cela lorsque vous appelez gcc. Mais l’effet secondaire est que toutes les autres petites fonctions ne sont pas non plus en ligne.

28
lukmac

Une méthode portable consiste à appeler la fonction via un pointeur:

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

Bien que cela produise différentes instructions pour créer une branche, cela peut ne pas être votre objectif. Ce qui soulève un bon point: quel est votre objectif ici?

21
Andy Ross

Si vous obtenez une erreur de compilation pour __attribute__((noinline)), vous pouvez simplement essayer:

noinline int func(int arg)
{
    ....
}
13
Sam Liao

Je sais que la question concerne GCC, mais j’ai pensé qu’il serait peut-être utile de disposer également d’informations sur les compilateurs.

L'attribut de fonction noinline de GCC est également très populaire auprès des autres compilateurs. Il est soutenu par au moins:

  • Clang (vérifier avec __has_attribute(noinline))
  • Compilateur Intel C/C++ (leur documentation est terrible, mais je suis certain que cela fonctionne sur 16.0+)
  • Oracle Solaris Studio à au moins 12.2
  • Compilateur ARM C/C++ vers au moins 4.1
  • IBM XL C/C++ vers au moins 10.1
  • TI 8.0+ (ou 7.3+ avec --gcc, qui définira __TI_GNU_ATTRIBUTE_SUPPORT__)

De plus, MSVC prend en charge __declspec(noinline) dans Visual Studio 7.1. Intel le supporte probablement aussi (ils essaient d'être compatibles avec GCC et MSVC), mais je n'ai pas pris la peine de le vérifier. La syntaxe est fondamentalement la même:

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

PGI 10.2+ (et probablement plus ancien) supporte un pragma noinline qui s'applique à la fonction suivante:

#pragma noinline
static void foo(void) { }

TI 6.0+ prend en charge un pragma FUNC_CANNOT_INLINE qui fonctionne (de manière gênante) différemment en C et C++. En C++, cela ressemble à l'IGP:

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

En C, cependant, le nom de la fonction est requis:

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

Cray 6.4+ (et peut-être plus tôt) adopte une approche similaire, nécessitant le nom de la fonction:

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

Oracle Developer Studio prend également en charge un pragma qui prend le nom de la fonction et remonte à au moins Forte Developer 6 , mais notez que cela doit venir après la déclaration, même dans les versions récentes:

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

En fonction de votre niveau de spécialisation, vous pouvez créer une macro qui fonctionnerait partout, mais le nom de la fonction ainsi que la déclaration devraient être utilisés comme arguments.

Si, OTOH, vous êtes d'accord avec quelque chose qui ne fonctionne que pour la plupart des gens, vous pouvez vous en tirer avec quelque chose d'un peu plus esthétique et qui ne nécessite pas de vous répéter. C'est l'approche que j'ai adoptée pour Hedley , où la version actuelle de HEDLEY_NEVER_INLINE ressemble à ceci:

#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_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
#else
#  define HEDLEY_NEVER_INLINE HEDLEY_INLINE
#endif

Si vous ne voulez pas utiliser Hedley (c'est un en-tête de domaine public/CC0), vous pouvez convertir les macros de contrôle de version sans trop d'effort, mais plus que ce que je suis disposé à mettre dans.

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

}

C'est ce qui a fonctionné pour moi.

9
KenBee

Utilisez le noinlineattribut :

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

Vous devriez probablement l'utiliser à la fois lorsque vous déclarez la fonction pour une utilisation externe et lorsque vous écrivez la fonction.

7
Chris Lutz

Je travaille avec gcc 7.2. J'avais précisément besoin d'une fonction non intégrée, car elle devait être instanciée dans une bibliothèque. J'ai essayé la réponse __attribute__((noinline)), ainsi que la réponse asm(""). Ni l'un ni l'autre n'a résolu le problème.

Enfin, j’ai pensé que définir une variable statique dans la fonction obligerait le compilateur à lui allouer de l’espace dans le bloc de variable statique et à lui attribuer une initialisation lors du premier appel de la fonction.

C'est un peu un truc sale, mais ça marche.

1
Ofri Sadowsky