Il y a deux façons bien connues de mettre un registre entier à zéro sur x86.
Soit
mov reg, 0
ou
xor reg, reg
Certains pensent que la deuxième variante est meilleure car la valeur 0 n'est pas stockée dans le code, ce qui permet d'économiser plusieurs octets de code machine produit. C'est certainement une bonne chose - moins de cache d'instructions est utilisé et cela peut parfois permettre une exécution plus rapide du code. De nombreux compilateurs produisent ce type de code.
Cependant, il existe officiellement une dépendance inter-instruction entre l'instruction xor et toute instruction antérieure qui modifie le même registre. Comme il y a une dépendance, la dernière instruction doit attendre que la première soit terminée, ce qui peut réduire la charge des unités du processeur et nuire aux performances.
add reg, 17
;do something else with reg here
xor reg, reg
Il est évident que le résultat de xor sera exactement le même quelle que soit la valeur initiale du registre. Mais le processeur est-il capable de le reconnaître ?
J'ai essayé le test suivant en VC++7 :
const int Count = 10 * 1000 * 1000 * 1000;
int _tmain(int argc, _TCHAR* argv[])
{
int i;
DWORD start = GetTickCount();
for( i = 0; i < Count ; i++ ) {
__asm {
mov eax, 10
xor eax, eax
};
}
DWORD diff = GetTickCount() - start;
start = GetTickCount();
for( i = 0; i < Count ; i++ ) {
__asm {
mov eax, 10
mov eax, 0
};
}
diff = GetTickCount() - start;
return 0;
}
Avec les optimisations désactivées, les deux boucles prennent exactement le même temps. Est-ce que cela prouve raisonnablement que le processeur reconnaît qu'il n'y a pas de dépendance de xor reg, reg
l'instruction sur l'ancien mov eax, 0
instruction ? Quel pourrait être un meilleur test pour vérifier cela ?
2 votes
Je pense que c'est pour cela que nous utilisons des langages de haut niveau. Si vous voulez vraiment savoir, il suffit de changer l'étape du codegen pour faire l'un ou l'autre. Benchmark. Choisissez le meilleur.
3 votes
Ah, l'ancien
xor reg, reg
truc - le bon vieux temps :)2 votes
Je pense que l'architecture x86 définit explicitement XOR reg,reg comme brisant la dépendance à reg. Voir le manuel de l'architecture Intel. Je m'attendrais à ce que MOV reg,... fasse la même chose simplement parce que c'est un MOV. Donc votre vrai choix est de savoir lequel prend le moins de place (je suppose que le temps d'exécution est le même), si vous ne vous souciez pas des bits d'état (XOR les endommage tous).
1 votes
Votre
Count
La variable est débordée, donc les boucles fonctionneront pendant beaucoup moins de cycles que prévu.2 votes
Sur les micro-architectures plus récentes,
xor reg,reg
ne nécessite pas d'unité d'exécution (gérée dans le décodage ?). Il brise les dépendances surreg
et des blocages partiels de la mise à jour des drapeaux. Et il a un encodage plus petit. Il n'y a pas de bonne raison pour que lemov
sur les x86-64 récents, sauf si vous devez préserver les [e]flags.