Tp 4 : Codage des tests et itérations



L'objectif

Ce tp va nous permettre de voir dans un premier temps comment sont codés en langage d’assemblage x86, le test si-alors-sinon, et les itérations while et for. Dans un second temps, on verra qu’il est possible de modifier l’emplacement mémoire d’une variable très utilisée afin d’optimiser le programme. Nous verrons dans un tp ultérieur que cela permet d’avoir des programmes plus rapides.

Le temps imparti

1h30

Le sujet

Quand un programme utilise une boucle, il y a toujours comparaison d'une variable avec une valeur cible. Cette comparaison permet alors d'arrêter la boucle. De plus si un programmeur décide de mettre à l'intérieur d'une boucle une instruction qui ne sert à rien (et oui il y en a...), un compilateur optimisant va enlever cette instruction.

A faire

Première partie : analyse des tests et des boucles.

Dans les 3 programmes suivants, noter l'emplacement mémoire des variables.

test_if.c
  1. #include <stdio.h>
  2. int main2()
  3. {
  4. int i = 0;
  5. if (i < 10)
  6. {
  7. i++;
  8. printf ("valeur de i : %d\n",i);
  9. } else
  10. i--;
  11. return 0;
  12. }
  13. int main()
  14. {
  15. return main2();
  16. }
boucle_for.c
  1. #include <stdio.h>
  2. int main2()
  3. {
  4. int i,j;
  5. for (i=0; i<10; i=j+1)
  6. {
  7. printf ("valeur de i : %d\n",i);
  8. j = i;
  9. }
  10. return 0;
  11. }
  12. int main()
  13. {
  14. return main2();
  15. }
boucle_while.c
  1. #include <stdio.h>
  2. int main()
  3. {
  4. int i = 0,j;
  5. while(i < 10)
  6. {
  7. printf ("valeur de i : #d\n",i);
  8. j = i;
  9. i = j+1;
  10. }
  11. return 0;
  12. }
  13. int main()
  14. {
  15. return main2();
  16. }

Compiler ces 3 programmes à l’aide de la commande :

$gcc -Wall programme.c -o programme

Les lancer et voir ce qu'ils font (pas grand chose). Traduire ces programmes en langage d'assemblage à l'aide de la commande :

$gcc -Wall -S programme.c

Visualiser ces nouveaux fichiers sources assembleur et les analyser pour comprendre le codage du test if-else et des itérations while et for.

Remplacer le mot-clé int par unsigned int. Quels sont les changements dans les codes assembleur produits ?

Segmenter le code assembleur obtenu en blocs correspondant aux instructions du langage C.


Optimiser ces programmes à l'aide de la commande :

$gcc -Wall -O -S programme.c

Segmenter le code assembleur obtenu en blocs correspondant aux instructions du langage C. Retrouve-t'on les mêmes motifs ? La segmentation est-elle complète ?
Que sont devenues nos variables ?


Deuxième partie : déplacement de la variable i.

Reprendre les trois programmes précédents, les copier en les renommant : programme_reg.c.
Ajouter dans ces 3 programmes le mot clef register en préfixant les déclarations des variables.
Traduire en langage d’assemblage ces 3 programmes en faisant attention à avoir toujours _reg dans les noms des différents fichiers, de façon à pouvoir comparer les différents codes assembleurs. Ne pas activer l'optimisation !
Visualiser les 3 fichiers .s produits et noter l'emplacement mémoire des variables.
Conclure quant à la vitesse d’exécution attendue de ces nouveaux programmes par rapport aux anciens.

Traduire en langage d’assemblage ces 3 programmes en faisant attention à avoir toujours _regopt dans les noms des différents fichiers. Activer l'optimisation !
Visualiser les 3 fichiers .s produits et noter l'emplacement mémoire des variables.

Conclure sur l'efficacité relative du mot-clé register et de l'optimisation par gcc.


Troisième partie : Pour ceux qui veulent aller plus loin.

Nous avons vu dans les deux parties précédentes que gcc optimisait bien le code du programme... mais que l'on pouvait lui donner des conseils.
Nous allons voir que l'on peut aussi lui donner des ordres.

Modifier les programmes ci-dessus en déplaçant les variables locales en tête des fichiers. Elle deviennent donc globales.
Observer que les variables ne sont plus situées sur la pile.
Tester les optimisations ci-dessus et conclure.


Modifier les programmes en remplaçant les déclarations par :

  1. #include <stdio.h>
  2. register int i asm("ebx"),j asm("esi");

Attention : ce code n'obeït plus à la norme ANSI ! Il n'est donc plus portable...

Tester différentes compilations.
Comparer les résultats obtenus.
Tester différents registres.

Conclure sur ce TP.


Retour à la liste des TP