Vous êtes sur la page 1sur 27

Compilation

Chapitre 4 : Génération du code intermédiaire


SMI/S5
Compilation
Prof. : M. BENADDY
A.U. 2015-2016
Introduction

 Le code intermédiaire est un code entre le code


source et le langage objet, si le code objet est le
code d’assemblage, le code intermédiaire peut
être un code proche de l’assembleur mais dont
les instructions ne spécifient pas les registres.
Les trois formes principales du code intermédiaire
sont le code du post fixé, l’arbre abstrait et le
code à trois adresses.

Prof. M. BENADDY Compilation 2


Le code post fixé
 Dans un code de post fixé un opérateur suit toujours ses
opérandes. On peut définir le code post fixé comme suit :
 Si E est une constante ou une variable le code post fixé de E
est égale à E
 Si E est une expression de la forme E1 op E2 où op est un
opérateur binaire, le code post fixé de E est E1’ E2’ op où E1’
et E2’ sont respectivement les codes poste fixé de E1 et E2.
 Si E est une expression de la forme (E1), le code post fixé de E
est celui de E2.
 Exemples :
(a+b) * (c-d) => a b + c d - *
a+b*c => ab+c*

Prof. M. BENADDY Compilation 3


Le code post fixé
 Traduction des expressions arithmétiques en code post fixé:

E → E+E E.code = E1.code || E2.code || '+'

E → E*E E.code = E1.code || E2.code || '*'

E → id E.code= id.nom

 L’attribut E.code signifie le code post fixé de E id.nom est le nom


de la valeur de l’identificateur les || représentent la concaténation.

Prof. M. BENADDY Compilation 4


Le code post fixé
if( a>1 ) b = 0 ; if (g <=2 ) a = 0 ;
else c = 0 ; else if ( f >5 ) a = b + c * 6;
 Exemples : else a = c * 4 – 2 * b;

a 1 e1 bgt g 2 e1 ble
c 0 =; f 5 e2 bgt
e2 br ac4*2b*-=;
e1 : b 0 = ; e3 br
e2 : e2 : a b c 6 * + = ;
e3 br
e1 : a 0 = ;
e3:
s=0; s 0=;
for (i = 0 ; i<7 ; i++) i 0=;
if ( i % 2 == 0) e1 : i 7 e2 blt
s=s+i; e4 br
ce bout de code peut être écrit de la e2: i % 2 e3 bz
façon suivante : e5 br
s=0; e3: s s i + = ;
i = 0; e5: i i 1 + = ;
A : if (i = 0 ; i<7 ; i++) { e1 br
if ( i % 2 == 0) e4 :
s=s+i;
i = i+1;
Prof. M. BENADDY goto A; Compilation 5
}
Arbres abstraits
 Une structure de l’arbre abstrait peut être considérée comme une
des formes intermédiaire, l’arbre syntaxique résultant de l’analyse
syntaxique dans le cas où une chaîne à analyser est dépourvue
d’erreur syntaxique.
 Les nœuds de l’arbre sont constitués des symboles non-terminaux
de la grammaire qui accepte la chaîne d’entrée dans le code
intermédiaire, ces symboles ne présentent aucune nécessité. Il
serait plus commode de les éliminer. On obtient alors une
structure beaucoup plus économique appelée arbre abstrait.
Arbre syntaxique Arbre abstrait
 w : a +b * c E +
/ | \ / \
E + E a *
| / | \ / \
a E * E b c
| |
Prof. M. BENADDY
bCompilation
c 6
Code à trois adresses
 Le code à trois adresses est un code qui se rapproche du code
d’assembleur il est composé d’instruction qui contient en général 3
adresses, 2 pour les opérandes et un pour le résultat et un opérateur. Le
code est une séquence d’instruction de la forme x :=y op z où x, y, z
sont des variables ou des constantes.
 Exemple : L’expression x+y*z peut être traduite par la séquence
suivante :
t1 = y*z
t2 = x + t1
t1 et t2 sont des variables temporaires introduites par le compilateur.
 Une instruction à trois adresses est une forme abstraite du code
intermédiaire. Dans un compilateur les instructions peuvent être
implantées par des structures dont les champs contiennent les
opérateurs et les opérandes. On distingue trois types du code à trois
adresses ; les quadruplets, les triplets et les triplets indirectes.

Prof. M. BENADDY Compilation 7


Les instructions du code à trois adresses :

 Les instructions d'affectation de la forme x = y op z où op est un opérateur


binaire arithmétique ou logique.
 Les instructions d'affectation de la forme x = op y où op est un opérateur unaire
tels que le moins (-) unaire, la négation logique ou bien les opérandes de
conversion de type.
 Les instructions de copie de la forme x = y où la valeur de y est affectée à x.
 Le branchement inconditionnelle de la forme aller à L qui a pour effet de faire
exécuter l'instruction étiqueté par L.
 Les branchements conditionnelle de la forme, si x oprel y aller à L où oprel est
un opérateur relationnel (<,>,<=,>=,==,etc), l'application de oprel à x et y fait
exécuter l'instruction étiquetée par L si la relation est satisfaite. Sinon
l'instruction qui suit le branchement conditionnelle est exécuté.
 Les appelles des procèdures ou bien les fonctions de la forme p(x 1, x2 ,…,xn)
sont traitées par des séquences utilisant les instructions suivantes ;
param x1
param x2
 …
 param xn
 appeler p n /* où n est un entier qui indique le nombre de paramètres de p */
Prof. M. BENADDY Compilation 8
Les quadruplets

 La structure d'un quadruplet est une matrice A(n,4) à n lignes et 4


colonnes où n et le nombre de quadruplets. Un quadruplet est composé
de quatre champs appelés respectivement op, arg1, arg2 et résultat, le
champ op contient une interne pour l'opérateur.
 L'instruction x = y op z est représentée en plaçant y dans arg1 et z
dans arg2 et x dans resultat.
 Les instructions utilisant les opérateurs unaires tel que x = -y ou x = y,
n'utilise pas arg2.
 Des opérateurs tels que param n'utilise ni arg2 ni résultat.
 Les instructions de branchement conditionnelle et inconditionnelle
rangent leurs étiquettes dans résultat.

Prof. M. BENADDY Compilation 9


Les quadruplets

 Exemple : a = b * -c + d * -c

op arg1 arg2 res


t1 = minus c 0 minus c t1
t2 = b * t1
t3 = minus c 1 * b t1 t2
t4 = d * t3 2 minus c t3
t5 = t2 + t4 3 * d t3 t4
a = t5
4 + t2 t4 t5
5 = t5 a

● Les contenus des champs arg1, arg2 et resultat sont des pointeurs vers les
entrées de la table des symboles des noms représentés par ses champs. Les
variables temporaires doivent être rangées dans la table des symboles
lorsqu'ils sont crées.

Prof. M. BENADDY Compilation 10


Les triplets

 On peut éviter de ranger les variables temporaires dans la table des


symboles en remplaçant une valeur temporaire par la position de
l'instruction qui la calcule. Dans ce cas les instructions à trois adresses
sont représentées par les structures à trois champs : op, arg1 et arg2.
 Exemple : a = b * -c + d * -c
op arg1 arg2
0 minus c
* b 0
1
minus c
2
* d 2
3

4 + 3 1

5 = a 4

Prof. M. BENADDY Compilation 11


Les triplets indirectes

 La structure des triplets rend difficile l'optimisation du code. Le


processus d'optimisation nécessite le plus souvent à éliminer, à déplacer
et voire à décaler une partie du code. Ces opérations sont difficiles à
mettre au point car l'écriture des triplets dépend des autres triplets, pour
palier à ce problème, une structure appelée triplet indirecte est introduite.
 Les triplets indirectes consistes en une liste de pointeurs vers les triplets
eu lieu de lister les triplets eux-même. Par exemple on peut utiliser un
tableau de pointeurs vers les triplets dans l'ordre voulue. Reprenons
l'exemple précédent on aura alors :
op arg1 arg2
35 (0)
minus c
36 (1)
* b (0)
37 (2) minus c
38 (3) * d (2)
39 (4) + 3 (1)
40 (5) = a (4)
Prof. M. BENADDY Compilation 12
Compilation

Chapitre 5 : optimisation du code


SMI/S5
Compilation
Prof. : M. BENADDY
A.U. 2015-2016
Optimisation des sous expressions communes

 Une occurrence d’une expression E est appelée une sous expression


commune si E a été calculée précédemment et si les valeurs des variables
apparaissant dans E n’ont pas changées depuis le calcul précédent, nous
pouvons éviter de recalculer l’expression si nous utilisons la valeur
calculée précédemment.
 Exemple :
t6 = 4*i t6 = 4*i
x=a[t6] x=a[t6]
t7=4*i t8=4*j
t8=4*j t9=a[t8]
t9=a[t8] Optimisation a[t6]=t9
a[t6]=t9 ==========> a[t8]=x
t10=4*j aller à l2
a[t10]=x
aller à l2

Prof. M. BENADDY Compilation 14


Optimisation locale

 L’optimisation consiste généralement à substituer à plusieurs instructions


contiguës, un nombre plus restreint d’autres instructions en vue de
diminuer le temps d’exécution du code et l’espace occupé par ce dernier.
 Exemple :
if (a<b) goto l1 if (a >= b) goto l2
goto l2 l1
l1 : l1 :
l2: l3 br
l2:
l3 :

 De telles instructions sont produites non par le programmeur mais le plus


souvent par le compilateur et ceci pendant la phase de génération du
intermédiaire.

Prof. M. BENADDY Compilation 15


Optimisation des sous expressions communes

 Une occurrence d’une expression E est appelée une sous expression


commune si E a été calculée précédemment et si les valeurs des variables
apparaissant dans E n’ont pas changées depuis le calcul précédent, nous
pouvons éviter de recalculer l’expression si nous utilisons la valeur
calculée précédemment.
 Exemple : t6 = 4*i t6 = 4*i
x=a[t6] x=a[t6]
t7=4*i t8=4*j
t8=4*j t9=a[t8]
t9=a[t8] Optimisation a[t6]=t9
a[t6]=t9 ==========> a[t8]=x
t10=4*j aller à l2
a[t10]=x
aller à l2

 Les sous expressions 4*i et 4*j sont communes aux affectations t7 et t10.
Elles étaient éliminées en utilisant t6 à la place de t7 et t8 à la place de
t10.
Prof. M. BENADDY Compilation 16
Elimination du code inutile

 Une variable est en un point d’un programme si sa valeur peut être


utilisée ultérieurement sinon elle est inactive en ce point. Une idée
voisine est celle de code inutile ou inaccessible : instruction qui calcule
des valeurs qui ne sont jamais utilisées, alors que le programme n’est pas
censé introduire intentionnellement du code inutile, il peut en apparaître
dans le résultat de la transformation précédente.
 Exemple :
a =false a=false
if(a) Optimisation x=z;
x = y+z ; ==========>
else
x=z

Prof. M. BENADDY Compilation 17


Optimisation des boucles

 L’exécution d’un programme peut être améliorée si on diminue le


nombre d’instruction d’une boucle interne même si nous devons
augmenter la quantité du code à l’extérieur de cette boucle.
 Il a été vérifié que 90% du temps d’exécution d’un programme se passe
dans les 10% du code représentant généralement des boucles.
 Réduire le temps d’exécution d’une boucle influencera sur le temps total
d’exécution du programme.

Prof. M. BENADDY Compilation 18


Déplacement du code invariant

 Un code est invariant à l’intérieur d’une boucle lorsque pour toutes les
itérations de la boucle son calcul ne varie pas.
 Dans l’exemple ci-dessous, les valeurs répétitives de a et de b sont des
constantes, on peut donc déduire que le calcul des instructions x1=a-9 et
x5=b-12, ne changent pas lors des différentes itérations de la boucle.
Pour éviter de calculer à chaque itération de la boucle, et pour gagner le
temps d’exécution, il convient de déplacer ces instructions de l’itération,
créer un autre bloc former de ces deux instructions et le placer avant le
bloc de la boucle.

Prof. M. BENADDY Compilation 19


Déplacement du code invariant

 Exemple :
1 s=0 ; 1 s=0 ;
2 i=1 ; 2 i=1 ;
3 if (i<=n) goto 5 3 x2 = a -9;
4 goto 17 4 x5=b-12;
5 x1 = i*3; Optimisation 5 if (i<=n) goto 7
6 x2 = a -9; =========> 6 goto 17
7 x3=x10[x1]; 7 x1 = i*3;
8 x4=i*3; 8 x3=x10[x1];
9 x5=b-12; 9 x4=i*3;
10 x6=x11[x4]; 10 x6=x11[x4];
11 x7=x3*x6; 11 x7=x3*x6;
12 x8=s+x7; 12 x8=s+x7;
13 s=x8; 13 s=x8;
14 x9=i+1; 14 x9=i+1;
15 i=x6; 15 i=x6;
16 goto 3 16 goto 5
17 17

Prof. M. BENADDY Compilation 20


Les variables d’induction

 Deux variables x et y sont dites d’induction si on peut déduire les valeurs


de x à partir de celle de y et vice versas autrement dit, il existe des
expressions de type x= cte* y ou y=cte*x.
 Dans le code de l’exemple précédent on remarque que les variables x1,
x4 et i sont des variables d’induction :

x1 = i*3 x1=x4 X4=i*3


i=x1/3 x4=x1 I=x4/3

 Par conséquent on peut éliminer toutes les variables d’induction et ne


garder qu’une seule, cependant une précaution à prendre est de s’assurer
que dans la suite du code la variable à éliminer ne vie pas.

Prof. M. BENADDY Compilation 21


Génération du code objet

 La phase de génération du code consiste à générer le code objet à partir du code


intermédiaire du programme source.
 Le code intermédiaire peut être soit un code post fixé, soit un code à 3 adresses
soit un arbre abstrait. Le code objet appartient à une variante de langages tels
que l’assembleur ou un langage proche du langage machine.
 Si le langage objet est l’assembleur, le concepteur doit manipuler et maintenir
ce langage, en particulier, il doit connaître le répertoire des instructions et les
modes d’adressage.
 Par la suite nous envisageons de générer un code objet à partir des quadruplets
générer dans le code intermédiaire, le processus de génération du code est
simple en lui-même, il n’exige aucune solubilité de la part du constructeur.
 Par contre ce qui rend le processus complexe c’est le fait d’entreprendre en
parallèle les opérations d’optimisation.
 L’opération la plus intéressante est celle qui pose le plus de problèmes et
l’utilisation efficace des registres. Cette opération exige en un moment donné
une vue assez globale du code à traduire.

Prof. M. BENADDY Compilation 22


Forme du code objet et modèle de la machine

 Avant d’entamer la traduction du code intermédiaire en code objet, il est inévitable


de posséder un certain bagage en programmation dans le langage cible, et aussi une
parfaite connaissance de certaines spécificités de la machine.
 Le modèle de la machine qu’on va utiliser est celui d’une machine adressable par
octet contenant n registres R0 a Rn, elle possède des instructions de deux adresses
de la forme op src, dest.
 Les instructions les plus utilisées sont MOV A, B, cette opération consiste à mettre
la valeur de A à l’emplacement de B les emplacements A, B peuvent être soit des
registres soit des adresses mémoires, dans le cas où B est un registre l’opération est
équivalente est de charger le contenu de A dans B, si B est une adresse mémoire le
rôle de MOV est de stocker dans B la valeur qui se trouve dans A.
 ADD A, B : cette opération consiste à additionner le contenu de A et le contenu de
B et de stocker le résultat dans B.
 SUB A, B : permet d’effectuer les soustractions du contenu de A et le contenu de B
et de stocker le résultat dans B.
 Si dans une instruction A et B sont tous les deux des registres, l’instruction
occupera un seul mot formé du code de deux opérations et des numéros des
registres qui constituent respectivement la source et la destination.
Prof. M. BENADDY Compilation 23
Forme du code objet et modèle de la machine

 MOV R1, R2 ;
 MOV A, R2 ; si A n’est pas un registre l’instruction occupera 2 mots contiguës 1
pour l’opération et 1 pour la valeur de A
 MOV A, B ; où A et B ne sont pas des registres, cette instruction occupe 3 mots
contiguës 1 pour l’opération et les autres pour B et A
 L’exécution d’une instruction se fait en deux étapes : le fetch et l’exécution
 Le fetch consiste à charger l’instruction dans le registre d’instruction et de
l’interpréter. La 2ème étape consiste à l’exécution proprement dite. La première
étape est généralement plus lente que la deuxième si notre intérêt porte sur la
réduction du temps d’exécution il est recommandé de minimiser le nombre de
fetch, c-à-d le nombre de mots dans chaque instruction pour répondre à cet objectif.
Le processus de génération du code objet fera en sorte de produire des instructions
occupont le moins de mots et ceci en affectant le maximum de registres aux
instructions.
 On définit le coût d’exécution d’un mot par 1, par conséquent le coût d’exécution
d’une instruction est la somme des coûts d’exécution des mots qu’ils l’occupent.

Prof. M. BENADDY Compilation 24


Forme du code objet et modèle de la machine

 Exemple : B+C

MOV B,R1 ; coût = 2 MOV B, R1 ; coût = 2


MOV C, R2 ; coût =2 coût = 5 ADD C, R1 ; coût =2 coût = 4
ADD R1, R2 ; coût =1

Prof. M. BENADDY Compilation 25


Algorithme de génération du code objet

 Utilisations prochaines : Soit le quadruplet A = B op C se trouvant à


l’entrée ‘i’ de la table des quadruplets, l’utilisation de A à l’entrée ‘j’ de la
table des quadruplets doit satisfaire que l’instruction à l’entrée ‘j’ utilise A
comme opérande.
 Descripteur des registres : Lors du processus de génération du code objet,
il est nécessaire de connaître l’état de chaque registre c-à-d si le registre est
occupé et par quelle variable, ces renseignements seront stockées dans une
liste attachée à chaque registre.
 Descripteur d’adresses : On a besoin aussi le long du processus de
génération du code objet de connaître le support des valeurs attribuées à une
variable donnée. On crée donc une structure pour chaque variable pour
indiquer les registres qui contient éventuellement la valeur de cette variable
et la zone mémoire occupée par la même valeur. Ceci nous permettra de
réutiliser le même registre dans plusieurs opérations si ce dernier contient la
valeur de l’opérande.

Prof. M. BENADDY Compilation 26


Algorithme de génération du code objet

 Processus de génération du code :


 Pour chaque quadruplet A= B op C faire :
 L = donnerreg() ; le registre dans lequel le résultat de calcul de B op C
sera rangé.
 Consulter le descripteur de l’adresse de B pour déterminer B’
l’emplacement courant de B, choisir de préférence pour B’ un registre.
Si B’ ≠ L générer l’instruction MOV B’, L pour placer une copied de B
dans L.
 Générer l’instruction OP C’, L où C’est l’emplacement courant de C.
choisir de préférence un registre pour C’. modifier le descripteur
d’adresse de A pour indiquer qu’il contient la valeur de A.
 Si B et C occupent des registres et s’elles n’ont pas d’utilisation
ultérieures et ne sont pas actives à la sortie du bloc modifier le
descripteur de registres pour indiquer qu’il ne contient pas B et C.
 La traduction de A = op B est similaire sauf qu’il ne faut pas considérer
l’opérande C.
Prof. M. BENADDY Compilation 27