2 votes

modifications de la construction de la boucle gcc en code d'assemblage

Pourquoi le compilateur gcc traduit-il les boucles while en constructions do-while lors de la création du code d'assemblage ? Je sais que toute boucle while peut être réécrite comme un do-while, par exemple en c

while (test) { ... }

peut être réécrit comme suit

if ( !test ) goto skip;
do {
. . .
} while ( test );
skip:

5voto

Zack Points 44583

Dans le prolongement de la réponse d'anatolyg, vous pouvez vous poser les questions suivantes pourquoi la construction do-while est plus efficace, surtout si l'on considère que, comme indiqué, le test a été dupliqué (le code généré est donc plus gros). La réponse est que très souvent, on peut prouver que l'expression de test est toujours vraie à l'entrée de la boucle, alors

    if ( !test ) goto skip;
loop:
    . . . // loop body
    if ( test ) goto loop;
skip:
    . . . // continue the program

peut être simplifié en

loop:
    . . . // loop body
    if ( test ) goto loop;
    . . . // continue program

Maintenant, pourquoi ne pas faire cela en même temps que la transformation originale, et éviter la transformation originale si le compilateur ne peut pas prouver que la boucle va tourner au moins une fois ? Parce que l'algorithme qui prouve que la boucle effectuera au moins un cycle est en fait un optimiseur générique de condition if. La séquence habituelle d'optimisations est quelque chose comme ceci :

  1. Transformer toutes les boucles en une forme "canonique" (plus ou moins comme indiqué dans le premier bloc de code ci-dessus)
  2. Faites beaucoup d'optimisations qui s'attendent à des boucles sous cette forme canonique, comme l'élimination de l'instruction if présentée.
  3. Une fois que vous en aurez fini avec tout ce qui concerne les boucles en tant que telles, essayez de les décanoniser là où cela éliminerait la redondance.

L'autre chose à savoir est que parfois, un test en double est délibérément laissé en place parce que le compilateur s'attend à ce que cela produise un meilleur comportement à l'exécution. Par exemple, si le compilateur a des raisons de penser que la boucle généralement cycles de nombreuses fois, mais ne peut pas prouver qu'elle toujours au moins une fois, alors l'instruction de branchement conditionnel au-dessus de la boucle passera presque toujours, et le branchement conditionnel au-dessous de la boucle sautera presque toujours. Dans ce cas, le fait de les laisser séparées rendra probablement le prédicteur de branchement du processeur plus précis. La précision de la prédiction de branchement est, après la convivialité du cache, le facteur limitant la vitesse des processeurs modernes hors ordre.

3voto

anatolyg Points 8076

En général, un do-while est plus efficace qu'une boucle while boucle. Puisque le compilateur veut créer un programme rapide (plutôt que lisible), il convertit la plupart des boucles de while boucles vers do-while les uns et les autres.

En fait, la mise en œuvre d'un while boucle en utilisant uniquement if y goto (qui se rapproche du langage assembleur) peut se faire comme suit :

start:
    if ( !test ) goto skip;
    . . . // loop body
    goto start;
skip:
    ; // continue the program

C'est équivalent mais probablement moins efficace que la méthode do-while (parce que cette dernière a une ligne de code de moins dans la boucle) :

    if ( !test ) goto skip;
loop:
    . . . // loop body
    if ( !test ) goto loop;
skip:
    ; // continue the program

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