C'est la nature de compilateurs. En supposant qu'ils vont prendre le plus rapide ou le meilleur chemin, c'est tout à fait faux. Toute personne qui implique que vous n'avez pas besoin de faire quelque chose pour votre code afin d'optimiser parce que "les compilateurs modernes" remplir le vide, faire le meilleur travail, faire de la manière la plus rapide de code, etc. En fait j'ai vu gcc s'aggraver à partir de 3.x à 4.x sur les bras, au moins. 4.x pourrait avoir pris jusqu'à 3.x en ce moment, mais dès le début, on produit plus lent code. Avec la pratique, vous pouvez apprendre comment écrire votre code de sorte que le compilateur n'a pas à travailler aussi dur et comme un résultat produit de plus en plus cohérentes et les résultats attendus.
Le bug ici sont vos attentes de ce qui sera produit, pas ce qui était réellement produit. Si vous souhaitez que le compilateur pour générer la même sortie, de le nourrir à la même entrée. Pas mathmatically le même, pas un peu la même chose, mais en fait la même, pas de chemins différents, pas de partage ou de distribuer des opérations à partir d'une version à l'autre. C'est un bon exercice de compréhension de la façon d'écrire votre code et de voir ce que les compilateurs faire avec elle. Ne faites pas l'erreur de croire que parce qu'une version de gcc pour un processeur cible, un jour, a produit un certain résultat, c'est la règle pour tous les compilateurs et l'ensemble du code. Vous devez utiliser beaucoup de compilateurs et de nombreux objectifs pour avoir une idée de ce qui se passe.
gcc est assez méchant, je vous invite à regarder derrière le rideau, regarder les entrailles de la gcc, essayez d'ajouter une cible ou de modifier de quelque chose de vous-même. Il est à peine maintenus ensemble par un ruban et fil de puisage. Un supplément de ligne de code ajoutée ou supprimée dans des endroits critiques et il vient de s'écrouler. Le fait qu'il a produit utilisable code est quelque chose pour être heureux à ce sujet, au lieu de se demander pourquoi il na pas de répondre à d'autres attentes.
avez-vous regardé ce que les différentes versions de gcc produire? 3.x et 4.x en particulier 4.5 vs vs 4.6 4.7, etc? et pour les différents processeurs cibles, x86, arm, mips, etc ou différentes saveurs de x86 si c'est le compilateur natif que vous utilisez, 32 bits vs 64 bits, etc? Et puis llvm (clang) pour des cibles différentes?
Mystique a fait un excellent travail dans le processus de pensée nécessaires pour résoudre le problème de l'analyse et de l'optimisation du code, en attente d'un compilateur à venir avec de de qui est, ainsi, ne s'attend pas du tout "moderne compilateur".
Sans entrer dans le calcul des propriétés, le code de ce formulaire
if (exponent < 0) {
r = mantissa << -exponent; /* diff */
} else {
r = mantissa >> exponent; /* diff */
}
return (r ^ -sign) + sign; /* diff */
est va conduire le compilateur à: mettre en œuvre sous cette forme, réaliser le si-alors-sinon convergent ensuite vers le code commun pour finir et en revenir. ou B: enregistrer une branche puisque c'est la fin de la queue de la fonction. Aussi de ne pas s'embêter avec l'aide ou de l'enregistrement de la r.
if (exponent < 0) {
return((mantissa << -exponent)^-sign)+sign;
} else {
return((mantissa << -exponent)^-sign)+sign;
}
Ensuite, vous pouvez obtenir en tant que Mystique, a souligné le signe de la variable disparaît tous ensemble pour le code écrit. Je ne reviendrai pas attendre le compilateur de voir le signe de la variable aller loin si vous devez avez fait vous-même et pas forcé le compilateur pour essayer de le comprendre.
Ce est une occasion parfaite pour creuser dans le code source de gcc. Il semble que vous avez trouvé un cas où l'optimiseur a vu une chose dans un cas, puis une autre chose dans un autre cas. Puis prendre la prochaine étape et de voir si vous arrivez à gcc de voir cette affaire. Chaque optimisation est là parce qu'un individu ou d'un groupe reconnu l'optimisation et intentionnellement mis là. Pour cette optimisation d'être là et de travail à chaque fois que quelqu'un l'a mis là (et puis le tester, et le maintenir dans le futur).
Certainement ne pas supposer que moins de code est plus rapide et plus code est plus lent, il est très facile de créer et de trouver des exemples de ce n'est pas vrai. Il serait peut-être plus souvent que de ne pas être le cas de moins de code étant plus rapide que plus de code. Comme je l'ai démontré depuis le début si vous pouvez créer plus d'un code à enregistrer de ramification dans ce cas, ou en boucle, etc et avoir le résultat net serait plus rapide de code.
La ligne de fond est que vous nourrissiez d'un compilateur source différente et d'attendre les mêmes résultats. Le problème n'est pas la sortie du compilateur, mais les attentes de l'utilisateur. Il est assez facile à démontrer pour un compilateur et d'un processeur, l'ajout d'une ligne de code qui fait toute la fonction considérablement plus lent. Par exemple, pourquoi le fait de passer a = b + 2; a = b + c + 2; cause _fill_in_the_blank_compiler_name_ générer radicalement différent et plus lent code? La réponse étant bien sûr le compilateur a été nourri différents code de l'entrée et il est parfaitement valable pour le compilateur pour générer de sortie différents. (encore mieux, lorsque vous permutez deux indépendants des lignes de code et la cause de la sortie à changer de façon spectaculaire) Il n'y a pas de relation attendue entre la complexité et de la taille de l'entrée de la complexité et de la taille de la sortie. Nourrir quelque chose comme cela dans clang:
for(ra=0;ra<20;ra++) dummy(ra);
Il produit quelque part entre 60 à 100 lignes d'assembleur. Il déroulé la boucle. Je n'ai pas compter les lignes, si vous pensez cela, il a à ajouter, copier le résultat à l'entrée à l'appel de la fonction, de faire l'appel de fonction, trois opérations minimum. donc, en fonction de la cible, qui est probablement 60 instructions d'au moins 80 si quatre par boucle, 100 si cinq par boucle, etc.