58 votes

Pourquoi les compilateurs dupliquent-ils certaines instructions?

Parfois, les compilateurs de générer du code avec bizarre instruction des duplications qui peuvent être retirés. Envisager le morceau de code suivant:

int gcd(unsigned x, unsigned y) {
  return x == 0 ? y : gcd(y % x, x);
}

Voici le code assembleur (généré par clang 5.0 avec les optimisations activées):

gcd(unsigned int, unsigned int): # @gcd(unsigned int, unsigned int)
  mov eax, esi
  mov edx, edi
  test edx, edx
  je .LBB0_1
.LBB0_2: # =>This Inner Loop Header: Depth=1
  mov ecx, edx
  xor edx, edx
  div ecx
  test edx, edx
  mov eax, ecx
  jne .LBB0_2
  mov eax, ecx
  ret
.LBB0_1:
  ret

Dans l'extrait suivant:

  mov eax, ecx
  jne .LBB0_2
  mov eax, ecx

Si le saut ne se produit pas, eax est réaffecté pour aucune raison évidente.

L'autre exemple est deux ret à la fin de la fonction: on pourrait parfaitement fonctionner aussi bien.

Est le compilateur simplement pas assez intelligent ou il y a une raison de ne pas supprimer les doublons?

40voto

janm Points 9310

Les compilateurs peuvent effectuer des optimisations qui ne sont pas évidentes pour les gens et la suppression des instructions de ne pas toujours faire les choses plus vite.

Une petite quantité de la recherche montre que les différents processeurs AMD ont succursale de prédiction des problèmes quand un RET est immédiatement après une branche conditionnelle. Par le remplissage de cette fente avec ce qui est essentiellement un no-op, le problème est évité.

Mise à jour:

Exemple de référence, à l'article 6.2 du Logiciel "Guide d'Optimisation pour les Processeurs AMD64" (voir http://support.amd.com/TechDocs/25112.PDF) dit:

Plus précisément, éviter les les deux situations suivantes:

  • Tout type de branche (soit conditionnelle ou inconditionnelle) qui a l'octet près-retour instruction RET comme sa cible. Voir La Section "Exemples".

  • Une branche conditionnelle qui se produit dans le code directement avant l'octet près-retour instruction RET.

Il passe également en détail sur les raisons de sauter objectifs devrait alignement qui est également susceptible d'expliquer le double des Technologies des énergies renouvelables à la fin de la fonction.

5voto

J_H Points 2740

Quel que soit le compilateur va avoir un tas de transformations pour s'inscrire renommer, de déroulage, de levage, et ainsi de suite. Combinant leurs résultats peuvent conduire à sous-optimale des cas tels que celui que vous avez indiqué. Marc Glisse offre de bons conseils: il vaut la peine d'un rapport de bogue. Vous décrivez une occasion pour un judas de l'optimiseur de jeter des instructions pour que soit

  • n'affectent pas l'état des registres et mémoire, ou
  • n'affectent pas l'état qui compte pour une fonction de post-conditions, n'a pas d'importance pour son API publique.

Sonne comme une opportunité pour l' exécution symbolique techniques. Si le solveur de contraintes ne trouve pas de points de branchement pour un MOV, peut-être qu'il est vraiment un NOP.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X