Section courante

A propos

Section administrative du site

Optimisations

Non spécifique au microprocesseur

Les sections suivantes décrivent les optimisations générales effectuées par le compilateur, elles ne sont pas spécifiques au microprocesseur. Certains d'entre eux nécessitent un remplacement de commutateur du compilateur tandis que d'autres sont effectués automatiquement (ceux nécessitant un commutateur seront notés comme tels).

Simplification de sous-expressions constant

En Free Pascal, si le ou les opérandes d'un opérateur sont des constantes, ils seront évalués au moment de la compilation.

Exemple :

  1. X:=1+2+3+6+5;

générera le même code que :

  1. X:=17;

De plus, si un index de tableau est une constante, le déplacement sera évalué au moment de la compilation. Cela signifie que l'accès à MyData[5] est aussi efficace que l'accès à une variable normale.

Enfin, l'appel des fonctions Chr, Hi, Lo, Ord, Pred ou Succ avec des paramètres constants ne génère aucun appel à la bibliothèque d'exécution ; les valeurs sont évaluées au moment de la compilation.

Fusion de constante

L'utilisation de la même chaîne constante, de la même valeur à virgule flottante ou du même ensemble de constantes deux fois ou plus génère une seule copie de cette constante.

Évaluation de raccourcie

L'évaluation de l'expression booléenne s'arrête dès que le résultat est connu, ce qui accélère l'exécution du code par rapport à si tous les opérandes booléens étaient évalués.

Constante d'ensemble

L'utilisation de l'opérateur in est toujours plus efficace que l'utilisation des opérateurs équivalents <>, =, <=, >=, < et >. En effet, les comparaisons de l'intervalle peuvent être effectuées plus facilement avec l'opérateur in qu'avec les opérateurs de comparaison normaux.

Petits ensembles

Les ensembles contenant moins de 33 éléments peuvent être directement codés en utilisant une valeur de 32 bits, donc aucun appel à la bibliothèque d'exécution pour évaluer les opérandes sur ces ensembles n'est requis ; ils sont directement codés par le générateur de code.

Vérification de la portée

Les affectations de constantes aux variables sont vérifiées au moment de la compilation, ce qui élimine le besoin de générer un code de vérification de l'intervalle d'exécution.

Et au lieu de modulo

Lorsque le deuxième opérande d'un mod sur une valeur non signée est une puissance constante de 2, une instruction de Et binaire est utilisée à la place d'une division entière. Cela génère un code plus efficace.

Décalage au lieu de multiplier ou de diviser

Lorsque l'un des opérandes d'une multiplication est une puissance de deux, ils sont codés à l'aide d'instructions de décalage arithmétique, ce qui génère un code plus efficace (utilise moins de cycle d'horloge d'un microprocesseur).

De même, si le diviseur dans une opération div est une puissance de deux, il est codé à l'aide d'instructions de décalage arithmétique.

Il en va de même lors de l'accès à des index de tableau étant des puissances de deux, l'adresse est calculée à l'aide de décalages arithmétiques au lieu de l'instruction de multiplication.

Alignement automatique

Par défaut, toutes les variables supérieures à un octet sont garanties d'être alignées au moins sur une limite de mot. L'alignement sur la pile et dans la section de données dépend du microprocesseur.

Liaison intelligente

Cette fonctionnalité supprime tout le code non référencé dans le fichier exécutable final, ce qui rend le fichier exécutable beaucoup plus petit.

La liaison intelligente est activée avec le commutateur de ligne de commande -CX ou à l'aide de la directive globale {$SMARTLINK ON}.

Routines en ligne

Les routines de bibliothèque d'exécution suivantes sont codées directement dans l'exécutable final : Lo, Hi, High, SizeOf, TypeOf, Length, Pred, Succ, Inc, Dec et Assigned.

Omission du cadre de pile

Dans des conditions spécifiques, le cadre de pile sera omis et la variable sera directement accessible via le pointeur de pile.

Conditions d'omission d'un cadre de pile :

Enregistrer les variables

Lors de l'utilisation du commutateur -Or, les variables ou paramètres locaux étant très souvent utilisés seront déplacés vers les registres pour un accès plus rapide.

Spécifique au microprocesseur

Ceci répertorie les optimisations de bas niveau effectuées, microprocesseur par microprocesseur.

Spécifique au Intel 80x86

Voici une liste des techniques d'optimisation utilisées dans le compilateur :

Remarque : Si des optimisations incertaines sont activées, l'algorithme CSE suppose que :

Le résultat pratique est que vous ne pouvez pas utiliser les optimisations incertaines si vous écrivez et lisez des variables locales ou globales directement et via des pointeurs (cela inclut les paramètres Var, car ce sont également des pointeurs).

L'exemple suivant produira du mauvais code lorsque vous activerez des optimisations incertaines :

  1. Var 
  2.  Temp:LongInt;
  3.  
  4. Procedure MaProc(Var _Bar:LongInt);Begin
  5.  If(_Bar=Temp)Then Begin
  6.   Inc(_Bar);
  7.   If(_Bar<>Temp)Then Writeln('Bogue!')
  8.  End;
  9. End;
  10.  
  11. BEGIN
  12.  MaProc(Temp);
  13. END.

La raison pour laquelle il produit du mauvais code est que vous accédez à la variable globale Temp à la fois via son nom Temp et via un pointeur, dans ce cas en utilisant le paramètre de variable _Bar, n'étant rien d'autre qu'un pointeur vers Temp dans le code ci-dessus.

D'un autre côté, vous pouvez utiliser les optimisations incertaines si vous accédez à des variables ou paramètres globaux/locaux via des pointeurs, et y accédez uniquement via ce pointeur.

Par exemple :

  1. Type 
  2.  TMyRec=Record
  3.   a,b:LongInt;
  4.  End;
  5.  PMyRec=^TMyRec;
  6.  TMyRecArray=Array[1..100000]of TMyRec;
  7.  PMyRecArray=^TMyRecArray;
  8.  
  9. Var 
  10.  MyRecArrayPtr:PMyRecArray;
  11.  MyRecPtr:PMyRec;
  12.  Counter:LongInt;
  13.  
  14. BEGIN
  15.  New(MyRecArrayPtr);
  16.  For Counter:=1 to 100000 do Begin
  17.   MyRecPtr:=@MyRecArrayPtr^[Counter];
  18.   MyRecPtr^.a:=Counter;
  19.   MyRecPtr^.b:=Counter div 2;
  20.  End;
  21. END.

Produira un code correct, car la variable globale MyRecArrayPtr n'est pas accessible directement, mais uniquement via un pointeur (MyRecPtr dans ce cas).

En conclusion, on pourrait dire que l'on ne peut utiliser des optimisations incertaines que lorsqu'on sait ce que l'on fait.

Spécifique au Motorola 680x0

L'utilisation du commutateur -O2 (par défaut) effectue plusieurs optimisations dans le code produit, la plus notable étant :

Commutateurs d'optimisation

C'est ici que sont décrits les différents interrupteurs d'optimisation et leurs actions, regroupés par interrupteur :

Commutateur Description
-On: Avec n = 1..4 : ces interrupteurs activent l'optimiseur. Un niveau supérieur inclut automatiquement tous les niveaux inférieurs.
  • Le niveau 1 (-O1) active l'optimiseur de judas (les séquences d'instructions courantes sont remplacées par des équivalents plus rapides).
  • Le niveau 2 (-O2) active l'analyseur de flux de données assembleur, permettant à la procédure commune d'élimination des sous-expressions de supprimer les rechargements inutiles des registres avec les valeurs qu'ils contiennent déjà.
  • Le niveau 3 (-O3) équivaut aux optimisations de niveau 2 plus quelques optimisations fastidieuses.
  • Le niveau 4 (-O4) équivaut aux optimisations de niveau 3 plus quelques optimisations pouvant avoir des effets secondaires.
-OaX=Y Définissez l'alignement de X sur Y.
-Oo[NO XXX Activer ou désactiver des optimisations spécifiques.
-OpXXX Définissez le processeur cible pour l'optimisation sur XXX ; voir fpc -i ou fpc -ic pour les valeurs possibles.
-OWXXX Générez des commentaires d'optimisation de l'ensemble du programme pour l'optimisation XXX, voir fpc -i ou fpc -iw pour les valeurs possibles.
-OwXXX Effectuer l'optimisation de l'ensemble du programme XXX ; voir fpc -i ou fpc -iw pour les valeurs possibles.
-Os Optimisez pour la taille plutôt que pour la vitesse.

Conseils pour obtenir du code plus rapidement

Ici, quelques conseils généraux pour obtenir un meilleur code sont présentés. Ils concernent principalement le style de codage.

Conseils pour obtenir un code plus petit

Voici quelques conseils donnés pour obtenir le plus petit code possible.

Optimisation de l'ensemble du programme

Aperçu

Traditionnellement, les compilateurs optimisent un programme procédure par procédure, ou au mieux unité de compilation par unité de compilation. L'optimisation du programme complet (WPO) signifie que le compilateur prend en compte toutes les unités de compilation composant un programme ou une bibliothèque et les optimise en utilisant la connaissance combinée de la façon dont elles sont utilisées ensemble dans ce cas particulier.

La manière dont WPO fonctionne généralement est la suivante :

C'est le schéma suivi par Free Pascal.

La mise en oeuvre de ce schéma dépend fortement du compilateur. Une autre implémentation pourrait être que le compilateur génère une sorte de code intermédiaire (par exemple, du code d'octet) et que l'éditeur de liens effectue tous les WPO ainsi que la traduction vers le code machine cible.

Principes généraux

Quelques principes généraux ont été suivis lors de la conception de la mise en ouvre FPC de WPO :

Comment l'utiliser

Étape 1 : Générer un fichier de commentaires WPO

La première étape dans WPO consiste à compiler le programme (ou la bibliothèque) et toutes ses unités comme cela se ferait normalement, mais en spécifiant en plus les 2 options suivantes sur la ligne de commande :

-FW/path/to/feedbackfile.wpo -OWselected_wpo_options

La première option indique au compilateur où le fichier de commentaires WPO doit être écrit, la deuxième option indique au compilateur d'activer les optimisations WPO.

Le compilateur collectera alors, juste après que le programme ou la bibliothèque ait été lié, toutes les informations nécessaires pour exécuter les options WPO demandées lors d'une compilation ultérieure, et stockera ces informations dans le fichier indiqué.

Étape 2 : Utilisez le fichier de commentaires WPO généré

Pour appliquer réellement les options WPO, le programme (ou la bibliothèque) et tout ou partie des unités qu'il utilise, doivent être recompilés à l'aide de l'option :

-Fw/path/to/feedbackfile.wpo -Owselected_wpo_options

(Notez les petites majuscules dans le w). Cela indiquera au compilateur d'utiliser le fichier de commentaires généré à l'étape précédente. Le compilateur lira ensuite les informations collectées sur le programme lors de l'exécution précédente du compilateur et les utilisera lors de la compilation en cours des unités et/ou du programme/bibliothèque.

Les unités non recompilées lors de la deuxième passe ne seront évidemment pas optimisées, mais elles fonctionneront toujours correctement lorsqu'elles seront utilisées avec les unités et le programme/bibliothèque optimisés.

Remarque : Notez que les options doivent toujours être spécifiées sur la ligne de commande : il n'y a pas de directive source pour activer WPO, car il n'a de sens que d'utiliser WPO lors de la compilation d'un programme complet.

Optimisations WPO disponibles

Les options de ligne de commande -OW et -Ow nécessitent une liste d'options d'optimisation de l'ensemble du programme, séparées par des virgules. Ce sont des chaînes de caractères, chaque chaîne de caractères désigne une option. Voici une liste des options disponibles :

Option Description
all Cela permet toutes les optimisations disponibles du programme entier.
devirtcalls Transforme les appels de méthode virtuelle en appels de méthode normaux (statiques) lorsque le compilateur peut déterminer qu'un appel de méthode virtuelle ira toujours à la même méthode statique. Cela rend ce code à la fois plus petit et plus rapide. En général, il s'agit principalement d'une optimisation permettant d'autres optimisations, car elle rend le programme plus facile à analyser du fait qu'elle réduit le flux de contrôle indirect.

Il y a 2 limitations à cette option :
  1. La mise en oeuvre actuelle est insensible au contexte. Cela signifie que le compilateur examine uniquement le programme dans son ensemble et détermine pour chaque type de classe quelles méthodes peuvent être dévirtualisées, plutôt que d'examiner chaque instruction d'appel et le code environnant pour déterminer si cet appel peut ou non être dévirtualisé ;
  2. L'implémentation actuelle ne dévirtualise pas encore les appels de méthodes d'interface. Pas lors de leur appel via une instance d'interface, ni lors de leur appel via une instance de classe.
optvmts Cette optimisation examine quels types de classes peuvent être instanciés et quelles méthodes virtuelles peuvent être appelées dans un programme, et sur la base de ces informations, elle remplace les entrées de la table de méthodes virtuelles (VMT) ne pouvant jamais être appelées par des références à FPC_ABSTRACTERROR. Cela signifie que de telles méthodes, à moins qu'elles ne soient appelées directement via un appel hérité d'une classe/objet enfant, peuvent être supprimées par l'éditeur de liens. Cela a peu ou pas d'effet sur la vitesse, mais peut aider à réduire la taille du code.

Cette option présente 2 limitations :
  1. Les méthodes publiées, ou les getters/setters de propriétés publiées, ne peuvent jamais être optimisées de cette manière, car elles peuvent toujours être référencées et appelées via le RTTI (ce que le compilateur ne peut pas détecter).
  2. De telles optimisations ne sont pas encore effectuées pour les méthodes de classe virtuelle.
wsymbolliveness Ce paramètre n'effectue aucune optimisation à lui seul. Il indique simplement au compilateur d'enregistrer quelles fonctions/procédures ont été conservées par l'éditeur de liens dans le programme final. Lors d'une passe wpo ultérieure, le compilateur peut alors ignorer les fonctions/procédures supprimées en ce qui concerne WPO (par exemple, si un type de classe particulier n'est construit que dans une procédure inutilisée, alors ignorer cette procédure peut améliorer l'efficacité des deux précédentes optimisations).

Encore une fois, il existe certaines limites :
  1. Cette optimisation nécessite que l'utilitaire nm soit installé sur le système. Pour les binaires Linux, objdump fonctionnera également. À l'avenir, ces informations pourraient également être extraites de l'éditeur de liens interne des plateformes qu'il prend en charge.
  2. La collecte d'informations pour cette optimisation (à l'aide de -OWsymbolliveness) nécessite que la liaison intelligente soit activée (-XX) et que la suppression des symboles soit désactivée (-Xs-). Lorsque vous utilisez uniquement des informations collectées précédemment, ces limitations ne s'appliquent pas.

Format du fichier WPO

Ces informations sont particulièrement intéressantes si des données externes doivent être ajoutées au fichier de feedback WPO, par exemple à partir d'un outil de profilage. Pour une utilisation régulière de la fonctionnalité WPO, les informations suivantes ne sont pas nécessaires et peuvent être ignorées.

Le fichier est composé de commentaires et d'un certain nombre de sections. Les commentaires sont des lignes commençant par un #. Chaque section commence par "%" suivi du nom de la section (par exemple,% contextinsensitive_devirtualization).

Après cela, jusqu'à la fin du fichier ou jusqu'à la ligne suivante commençant par "%", suit d'abord une description lisible par l'homme du format de cette section (dans les commentaires), puis du contenu de la section elle-même.

Il n'y a pas de règles sur l'apparence du contenu d'une section, sauf que les lignes commençant par # sont réservées aux commentaires et les lignes commençant par % sont réservées aux marqueurs de section.



Dernière mise à jour : Dimanche, le 27 août 2023