Préfixe Intel x86 0x2e / 0x3e prédiction de branche réellement utilisée?

Dans les derniers processeurs Intel logiciel dev manuel, il décrit deux opcode préfixes:

Group 2 > Branch Hints

    0x2E: Branch Not Taken
    0x3E: Branch Taken

ceux-ci permettent la prédiction explicite de branche des instructions de saut (opcodes comme Jxx )

je me souviens avoir lu il y a quelques années que sur x86 la prédiction explicite de branche était essentiellement un no-op dans le contexte de la prédiction de branche GCCS intrinsèques.

Je ne sais pas si ces indices de branche x86 sont une nouvelle fonctionnalité ou si ils sont pas coopératives dans la pratique.

quelqu'un peut clarifier ça?

(C'est-à-dire: les fonctions de prédiction de la branche GCC génèrent-elles ces indices de la branche x86? - et les processeurs Intel actuels ne les ignorent pas? - et quand est-ce arrivé?)

mise à jour:

j'ai créé un programme de test rapide:

int main(int argc, char** argv)
{
    if (__builtin_expect(argc,0))
        return 1;

    if (__builtin_expect(argc == 2, 1))
        return 2;

    return 3;
}

désassemblage du suivant:

00000000004004cc <main>:
  4004cc:   55                      push   %rbp
  4004cd:   48 89 e5                mov    %rsp,%rbp
  4004d0:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004d3:   48 89 75 f0             mov    %rsi,-0x10(%rbp)
  4004d7:   8b 45 fc                mov    -0x4(%rbp),%eax
  4004da:   48 98                   cltq   
  4004dc:   48 85 c0                test   %rax,%rax
  4004df:   74 07                   je     4004e8 <main+0x1c>
  4004e1:   b8 01 00 00 00          mov    "151920920"x1,%eax
  4004e6:   eb 1b                   jmp    400503 <main+0x37>
  4004e8:   83 7d fc 02             cmpl   "151920920"x2,-0x4(%rbp)
  4004ec:   0f 94 c0                sete   %al
  4004ef:   0f b6 c0                movzbl %al,%eax
  4004f2:   48 85 c0                test   %rax,%rax
  4004f5:   74 07                   je     4004fe <main+0x32>
  4004f7:   b8 02 00 00 00          mov    "151920920"x2,%eax
  4004fc:   eb 05                   jmp    400503 <main+0x37>
  4004fe:   b8 03 00 00 00          mov    "151920920"x3,%eax
  400503:   5d                      pop    %rbp
  400504:   c3                      retq   
  400505:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40050c:   00 00 00 
  40050f:   90                      nop

Je ne vois pas 2E ou 3E ? Peut-être que gcc les a élidés pour une raison quelconque?

22
demandé sur Andrew Tomazos 2013-01-15 11:20:38

4 réponses

ces préfixes d'instructions n'ont aucun effet sur les processeurs modernes (rien de plus récent que le Pentium 4). Ils coûtent juste un octet d'espace de code, et donc, ne pas les générer est la bonne chose.

pour plus de détails, voir les manuels d'optimisation D'Agner Fog, en particulier 3. Microarchitecture: http://www.agner.org/optimize /

le "manuel de référence D'optimisation des Architectures Intel® 64 et IA-32" ne les mentionne plus dans le l'article sur l'optimisation des branches (section 3.4.1): http://www.intel.de/content/dam/doc/manual/64-ia-32-architectures-optimization-manual.pdf

ces préfixes sont une relique (inoffensive) de L'architecture de Netburst. Dans l'optimisation all-out, vous pouvez les utiliser pour aligner le code, mais c'est tout ce qui est bon pour aujourd'hui.

26
répondu Chris 2013-01-15 10:06:50

gcc a raison de ne pas générer le préfixe, car ils n'ont aucun effet pour tous les processeurs depuis le Pentium 4.

mais __builtin_expect a d'autres effets, comme déplacer un chemin de code non prévu loin de la cache-points chauds dans le code ou décisions en cours d'exécution, il est donc encore utile.

12
répondu Gunther Piez 2013-01-15 09:45:27

alors que Pentium 4 est la seule génération qui respecte réellement les instructions d'indication de branche, la plupart des CPU ont une certaine forme de prédiction de branche statique , qui peut être utilisé pour atteindre le même effet. Cette réponse est un peu tangentielle à la question initiale, mais je pense que ce serait une information précieuse pour quiconque vient à cette page.

Le Intel optimisation guide et Agner Brouillard guide de l' (qui ont déjà été mentionnés ici) ont tous deux d'excellentes descriptions de cette caractéristique.


Intel a ceci à dire sur les générations plus récent que le Core 2 :

faire en sorte que le code de basculement suivant une branche conditionnelle soit la cible probable d'une branche avec une "forward target

donc branches conditionnelles qui sautent en avant dans le code sont prédits pour ne pas être pris, par l'algorithme de prédiction statique.

ceci est cohérent avec ce que GCC semble avoir généré en utilisant __builtin_expect : le code" attendu " return 1 / return 2 est placé dans les chemins non-pris des branches conditionnelles, qui seront statiquement prédites comme non-prises.

en outre:

Branches qui n'ont pas une histoire dans le La zone tampon cible de la branche est prédite à l'aide d'un algorithme de prédiction statique:

  • prédisent les branches inconditionnelles à prendre.

  • prédire branches indirectes à ne pas prendre.

ainsi dans les chemins non-pris "attendus" où GCC a placé inconditionnel jmp s à la fin de la fonction, ces sauts seront statiquement prédites telles quelles (c.-à-d. non sautées).

Intel dit aussi:

faire de la chute-à l'aide de code à la suite d'une branche conditionnelle être le cas peu probable de la cible pour une branche avec une en arrière de la cible

ainsi les branches conditionnelles qui sautent en arrière dans le code sont prédites pour être prises, par l'algorithme de prédiction statique.

selon pour Agner Fog, la plupart des Pentiums suivent également cet algorithme:

sur PPro, P2, P3, P4 et P4E, une instruction de transfert de contrôle qui n'a pas été vue auparavant, ou qui n'est pas dans le tampon cible de la branche, est prédite tomber à travers si elle va en avant, et à prendre si elle va en arrière (par exemple une boucle). La prédiction statique prend plus de temps que la prédiction dynamique sur ces processeurs.

cependant, la noyau 2 famille (et Pentium M) a une politique tout à fait différente:

ces processeurs n'utilisent pas la prédiction statique. Le prédicteur fait simplement une prédiction aléatoire la première fois qu'une branche est vue, en fonction de ce qui se passe dans l'entrée BTB qui est assignée à la nouvelle branche. Il y a tout simplement une chance de 50% de faire la bonne prédiction de saut ou pas de saut, mais la cible prédite est correcte.

Comme AMD processeurs apparemment:

une branche est prédite non prise la première fois qu'elle est vue. Une branche est prévue toujours prise après la première fois qu'il a été pris. La prédiction dynamique n'est utilisée qu'après qu'une branche a été prise et non pas prise. Les préfixes d'indication de branche n'ont aucun effet.

il y a un facteur supplémentaire à considérer: les CPU aiment généralement exécuter dans un linéaire à la mode, donc même correctement prédites branches prises sont souvent plus coûteux que correctement prédites branches non prises.

7
répondu Cauterite 2016-07-23 19:29:22

Intel® 64 and IA-32 Architectures Software Developer's Manual -> Volume 2: Instruction Set Reference, A-Z - > Chapter 2: Instruction Format - > 2.1 Instruction Format for Protected Mode, real-address Mode, and virtual-8086 mode - > 2.1.1 Instruction Prefixes""

quelques microarchitectures antérieures ont utilisé ces derniers comme indices de branche, mais récente les générations n'ont pas et ils sont réservés pour l'usage futur indice.

1
répondu smart-rabbit 2017-08-24 12:08:31