Voici deux fonctions qui je demande de faire exactement la même chose:
bool fast(int x)
{
return x & 4242;
}
bool slow(int x)
{
return x && (x & 4242);
}
Logiquement, ils font la même chose, et juste pour être sûr à 100%, j'ai écrit un test qui a couru tous les quatre milliards d'entrées possibles par le biais de deux d'entre eux, et qu'ils correspondaient. Mais le code assembleur est une autre histoire:
fast:
andl $4242, %edi
setne %al
ret
slow:
xorl %eax, %eax
testl %edi, %edi
je .L3
andl $4242, %edi
setne %al
.L3:
rep
ret
J'ai été surpris de voir que GCC ne pouvait pas faire le saut de la logique pour éliminer le test redondants. J'ai essayé de g++ 4.4.3 et 4.7.2 avec -O2-O3, et-Os, tout ce qui a généré le même code. La plate-forme Linux x86_64.
Quelqu'un peut m'expliquer pourquoi GCC ne devrait pas être assez intelligente pour générer le même code dans les deux cas? Je voudrais aussi savoir si d'autres compilateurs peuvent faire mieux.
Modifier pour ajouter un harnais de test:
#include <cstdlib>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
// make vector filled with numbers starting from argv[1]
int seed = atoi(argv[1]);
vector<int> v(100000);
for (int j = 0; j < 100000; ++j)
v[j] = j + seed;
// count how many times the function returns true
int result = 0;
for (int j = 0; j < 100000; ++j)
for (int i : v)
result += slow(i); // or fast(i), try both
return result;
}
J'ai testé le dessus avec clang 5.1 sur Mac OS avec-O3. Il a fallu 2.9 secondes à l'aide d' fast()
et 3,8 secondes à l'aide d' slow()
. Si j'utilise plutôt un vecteur de tous les zéros, il n'y a pas de différence significative de performance entre les deux fonctions.