« Optimisation des compilateurs » : différence entre les versions

Contenu supprimé Contenu ajouté
Tavernier (discussion | contributions)
fusion en résumé introductif
Tavernierbot (discussion | contributions)
m Robot : Retouches cosmétiques
Ligne 23 :
 
Ce type d’optimisation a besoin d’avoir des hypothèses sur l’efficacité des instructions. Dans ce cas précis, on a assumer que l’opération « dup », qui duplique et écrit dans la pile, est plus efficace que l’opération « aload X », qui lit une variable locale et l’écrit dans la pile.
Un autre exemple d’optimisation est d’éliminer les opérations de lecture redondante.
 
Ligne 75 :
A [j]=A [1] + B [j]
 
Comme cette affectation du tableau A dépend du tableau A lui même, le compilateur ne peut pas utiliser le parallélisme en toute sécurité. Pour cela, il supprime l’affectation problématique de A[1] de l’intérieur de la boucle et la met à l’extérieur.
 
On obtient donc après ce type d’optimisation :
Ligne 128 :
}
 
Avec cette modification, on exécute seulement 20 boucles au lieu de 100. Donc on diminue le nombre d’instructions composées par un test et un « jump » par un facteur de 1/5.
 
;« Loop unswitching »
Ligne 153 :
end_if;
 
Chacune de ces boucles peut être optimisée séparément. On note aussi que le code générer est presque le double en terme de quantité que le code initial. Cette technique est introduit dans le gcc version 3.4
 
;Inversion de boucle
Ligne 175 :
} while (i < 100);
}
Apparemment, cette technique n’est pas efficace ; la même boucle et un code plus long. Mais la plus part des CPU utilisent les « pipeline » pour exécuter leurs instructions. Donc par nature un « jump » causera un « pipeline stall », c’est à dire une initialisation de la pipeline.
 
Considérant ce code assembleur suivant :
Ligne 226 :
 
;Le nombre de registres
: Généralement, plus on a de registres, plus facile sera l’opération d’optimisation. En effet, les variables locales peuvent être enregistré dans les registres et n’ont pas dans la pile. En outre les résultats intermédiaires peuvent être sauvegardé dans les registres au lieu d’effectuer une opération d’écriture en suite une autre opération de lecture pour récupérer le résultat.
;RISC vs. CISC
: Les instructions de CISC sont de longueurs variables. Et il y a une panoplie d’instructions possibles qui différent en temps d’exécution. En revanche les instructions RISC ont généralement la même longueur avec quelques exceptions. En plus, le nombre d’instructions par cycle est presque constant dans le cas où on ne considère pas la durée d’accès mémoire. Ceci dit les instructions CISC nous offrent une marge par rapport celle du RISC, pour optimiser certaines opérations. Ce qui reste à faire pour le compilateur est de savoir le coût des différentes instructions et de choisir la meilleure séquence (Voire optimisation sur des fenêtres).
Ligne 239 :
 
;La taille et le type du cache
: Quelques techniques d’optimisations, comme « loop unwiding », permettent d’augmenter la taille du code générer et en même temps vérifier de plus en plus le principe de localité.
;Le temps moyen d’accès mémoire/cache
: En ayant connaissance de ce facteur, un compilateur a une connaissance des pénalités causées par les différents types d’opérations mémoire/cache. Ceci est pris compte dans des applications très spécialisées.