Académique Documents
Professionnel Documents
Culture Documents
` la compilation Introduction a
Sylvain Conchon Cours 1 / 5 septembre 2013
Presentation du cours
cours le jeudi, 10h4512h45 en petit amphi (PUIO)
mais transparents disponibles pas de polycopie,
TD
le lundi, 14h0016h30, avec Sylvain Conchon le mercredi, 8h3011h00, avec Kim Nguyen
evaluation
continu + examen partiel + controle
http://www.lri.fr/~conchon/compilation/
Remerciements
Objectif du cours
` ma triser les mecanismes de la compilation, cest-a-dire de la transformation dun langage dans un autre comprendre les differents aspects des langages de programmation par le biais de la compilation
Programmation
ici on programme en cours en TD pour realiser le projet ` lexamen a on programme en Objective Caml
Un peu de lecture
Compilation
schematiquement, un compilateur est un programme qui traduit un programme dun langage source vers un langage cible, en signalant deventuelles erreurs
langage source
compilateur erreurs
langage cible
int main(int argc, char **argv) { int i, s = 0; for (i = 0; i <= 100; i++) s += i*i; printf("0*0+...+100*100 = %d\n", s); }
Langage cible
` la compilation dans ce cours, nous allons effectivement nous interesser a vers de lassembleur, mais ce nest quun aspect de la compilation un certain nombre de techniques mises en uvre dans la compilation ne a ` la production de code assembleur sont pas liees certains langages sont dailleurs es (Basic, COBOL, Ruby, etc.) interpret dans un langage intermediaire e compiles qui est ensuite interpret (Java, Caml, etc.) vers un autre langage de haut niveau compiles a ` la volee compiles
10
un compilateur traduit un programme P en un programme Q tel que x, la sortie de Q(x) soit la meme pour toute entree que celle de P (x)
P Q x...
un programme P et une ` est un programme qui, etant un interprete donne x, calcule la sortie s de P (x) entree
P x s...
11
dit autrement, le compilateur fait un travail complexe une seule fois, pour produire un code fonctionnant pour nimporte quelle entree ` effectue un travail plus simple, mais le refait sur chaque entree linterprete
est gen eralement autre difference : le code compile bien plus efcace que e le code interpret
12
<< \chords { c2 c f2 c } \new Staff \relative c { \time 2/4 c4 c g4 g a4 a g2 } \new Lyrics \lyricmode { twin4 kle twin kle lit tle star2 >>
2 4
twin kle twin kle lit tle star
13
14
15
Phase danalyse
source
analyse lexicale
analyse syntaxique
analyse semantique
16
` Phase de synthese
syntaxe abstraite
langage assembleur
assembleur (as)
langage machine
code executable
17
lassembleur MIPS
18
Un peu darchitecture
` schematiquement, tres un ordinateur est compose de calcul (CPU), contenant dune unite
un petit nombre de registres entiers ou ottants de calcul des capacites
19
Un peu darchitecture
RAM
CPU
$pc 0000052
$a0 0000012 $a1 0000040 $a2 0000022 $a3 0000000 $v0 0000000 ...
` a ` la memoire ` un milliard dinstructions par seconde, lacces coute cher (a ` ne parcourt que 30 centimetres ` la lumiere entre 2 instructions !)
20
Un peu darchitecture
e est bien plus complexe la realit es aux ottants plusieurs (co)processeurs, dont certains dedi un ou plusieurs caches une virtualisation de la memoire (MMU) etc.
21
Principe dexecution
schematiquement, lexecution dun programme se deroule ainsi ` executer un registre ($pc) contient ladresse de linstruction a ` cette adresse (fetch) on lit les 4 (ou 8) octets a ` ces bits comme une instruction (decode) on interprete on execute linstruction (execute) ` linstruction suivante on modie le registre $pc pour passer a ` sauf en cas de saut) (typiquement celle se trouvant juste apres,
22
Principe dexecution
RAM
CPU
$pc 0000052
$a0 0000012 $a1 0000040 $a2 0000022 $a3 0000000 $v0 0000000 ...
instruction : 000000 00001 00010 0000000000001010 decodage : add $a1 $a2 10 i.e. ajouter 10 au registre $a1 et stocker le resultat dans le registre $a2
23
Principe dexecution
prediction de branchement
pour optimiser le pipeline, on tente de predire les sauts conditionnels
24
25
Larchitecture MIPS
26
Simulateurs MIPS
en pratique, on utilisera un simulateur MIPS, MARS (ou SPIM) en ligne de commande
27
li lui
$a0, 42 $a0, 42
# copie a1 dans a0 !
28
add add
# a0 <- a1 + a2 # a2 <- a2 + t5
# a0 <- a1 + 42
neg
valeur absolue
$a0, $a1
# a0 <- -a1
abs
$a0, $a1
# a0 <- |a1|
29
not
$a0, $a1
# a0 <- not(a1)
and $a0, $a1, $a2 # a0 <- and(a1, a2) andi $a0, $a1, 0x3f # a0 <- and(a1, 0...0111111)
or ori
30
sra
$a0, $a1, 2
# a0 <- a1 / 4
srl
$a0, $a1, 2
rotation
rol ror
slt
32
lw
$a0, 42($a1)
par un registre et un decalage ladresse est donnee sur 16 bits signes ou non (lb, lh, lbu, lhu) variantes pour lire 8 ou 16 bits, signes
33
sw
$a0, 42($a1)
par un registre et un decalage ladresse est donnee sur 16 bits signes variantes pour ecrire 8 ou 16 bits (sb, sh)
34
on distingue branchement : typiquement un saut conditionnel, dont le sur 16 bits signes (-32768 a ` 32767 deplacement est stocke instructions) saut : saut inconditionnel, dont ladresse de destination est stockee sur 26 bits
35
branchement conditionnel
beq
variantes : bne, blt, ble, bgt, bge (et comparaisons non signees) variantes : beqz, bnez, bgez, bgtz, bltz, blez
36
label
jal
label
jr
$a0
syscall
le code de linstruction doit etre dans $v0, les arguments dans $a0$a3 ; dans $v0 le resultat eventuel sera place ` exemple : appel systeme print int pour afcher un entier
Assembleur MIPS
on ne programme pas en langage machine mais en assembleur : lassembleur fourni un certain nombre de facilites etiquettes symboliques globales allocation de donnees pseudo-instructions
39
Assembleur MIPS
la directive
.text
indique que des instructions suivent, et la directive
7FFFFFFC16
.data
suivent indique que des donnees a ` partir de ladresse 0x400000 le code sera charge a ` partir de ladresse 0x10000000 et les donnees une etiquette symbolique est introduite par
1000000016
(r eserv e)
label:
dans un registre et ladresse quelle represente peut etre chargee
la
$a0, label
40
main:
hw:
# # # #
"hello world\n"
41
de la compilation Le de
cest de traduire un programme dun langage de haut niveau vers ce jeu dinstructions en particulier, il faut (tests, boucles, exceptions, etc.) traduire les structures de controle traduire les appels de fonctions complexes (tableaux, traduire les structures de donnees enregistrements, objets, clotures, etc.) allouer de la memoire dynamiquement
42
Appels de fonctions
constat : les appels de fonctions peuvent etre arbitrairement imbriques ` les registres ne peuvent sufre pour les parametres / variables locales il faut allouer de la memoire pour cela ` ` les fonctions procedent selon un mode last-in rst-out, cest-a-dire de pile
43
La pile
tout en haut, et cro la pile est stockee t dans le sens des adresses decroissantes ; $sp pointe sur le sommet de la pile dynamiques (survivant aux appels de les donnees sur le tas (eventuellement fonctions) sont allouees par un GC), en bas de la zone de donnees, juste au dessus des donnees statiques ainsi, on ne se marche pas sur les pieds
44
Appel de fonction
lorsquune fonction f (lappelant ou caller ) souhaite appeler une fonction g ou callee), elle execute (lappele
jal
jr
$ra
` probleme : si g appelle elle-meme une fonction, $ra sera ecras e par g sera perdu pour f de meme, tout registre utilise ` il existe de multiples manieres de sen sortir, eral on saccorde sur des conventions dappel mais en gen
45
Conventions dappel
utilisation des registres a ` lassembleur et lOS $at, $k0 et $k1 sont reserv es pour passer les quatre premiers arguments (les $a0$a3 sont utilises sur la pile) et $v0$v1 pour renvoyer le resultat autres sont passes
$sp est le pointeur de pile, $fp le pointeur de frame $ra contient ladresse de retour
statiques (1000800016 ) $gp pointe au milieu de la zone de donnees
46
pour lappelant, juste avant lappel au debut pour lappele, de lappel a ` la n de lappel pour lappele, ` lappel pour lappelant, juste apres
au sommet de la pile appele le sorganisent autour dun segment situe entre $fp et $sp tableau dactivation, en anglais stack frame, situe
47
passe les arguments dans $a0$a3, les autres sur la pile sil y en a plus de 4 ` lappel sauvegarde les registres $t0$t9 quil compte utiliser apres (dans son propre tableau dactivation) execute
jal
appel e
48
addi
2
$fp
sw addi
49
a ` la n de lappel Lappele,
1 2 3
place le resultat dans $v0 (voire $v1) restaure les registres sauvegardes depile son tableau dactivation, par exemple
execute
jr
$ra
50
1 2
51
Exercice
52
Recapitulation
53
Un exemple de compilation
54
Clarication
int t(int a, int b, int c) { int d=0, e=a&~b&~c, f=1; if (a) for (f=0; d=(e-=d)&-e; f+=t(a-d, (b+d)*2, (c+d)/2)); return f; } int main() { int q; scanf("%d", &q); printf("%d\n", t(~(~0<<q), 0, 0)); }
55
Clarication (suite)
int t(int a, int b, int c) { int f=1; if (a) { int d, e=a&~b&~c; f = 0; while (d=e&-e) { f += t(a-d, (b+d)*2, (c+d)/2); e -= d; } } return f; } int main() { int q; scanf("%d", &q); printf("%d\n", t(~(~0<<q), 0, 0)); }
ce programme calcule le nombre de solutions ` du probleme dit des n reines
q q q q q
q q q
56
Comment c a marche ?
recherche par force brute (backtracking ) comme des ensembles : entiers utilises par ex. 13 = 0 011012 = {0, 2, 3} entiers ensembles
ab a b, quand a b = a\ b, quand b a a min (a), quand a = {0, 1, . . . , n 1} S (a) {i + 1 | i a}, note P (a) {i 1 | i a i = 0}, note
57
58
Signication de a, b et c
q q
? ? ? ? ? ? ? ?
59
Signication de a, b et c
q qqq q q
q q
59
Signication de a, b et c
q qq q q
59
Signication de a, b et c
q q q
q q
59
Signication de a, b et c
q q q q
59
court, mais contient un test (if) une boucle (while) une fonction recursive quelques calculs cest aussi une excellente solution ` au probleme des n reines
60
Compilation
commenc ons par la fonction recursive t ; il faut allouer les registres compiler
le test la boucle lappel recursif les differents calculs
61
Allocation de registres
dans $a0, $a1 et $a2 a, b et c sont passes dans $v0 le resultat est renvoye ` les parametres a, b, c, tout comme les variables locales d, e, f, ont car ils sont utilises apres ` lappel recursif besoin detre sauvegardes, on va utiliser des registres callee-save
a b c d e f
il faut donc allouer 7 mots sur la pile pour sauvegarder ladresse de retour $ra et ces 6 registres
62
# d esallocation
63
Compilation du test
$v0, $s5
64
$a0 # sauvegarde $a1 $a2 $s0 # e=a&~b&~c $s1 $s4, $t0 $s2 $s4, $t0 0 # f = 0
65
Compilation de la boucle
L1:
L2:
... ... calcul de test dans $t0 ... beqz $t0, L2 ... body ... j L1 ...
66
Compilation de la boucle
il existe cependant une meilleure solution
L2:
ainsi on fait seulement un seul branchement par tour de boucle ` part la toute premiere ` fois) (mis a
67
Compilation de la boucle
j body: sub add sll add srl jal add sub test: neg $t0, $s4 # d=e&-e and $s3, $s4, $t0 bnez $s3, body t return: ...
68
test $a0, $a1, $a1, $a2, $a2, t $s5, $s4, $s0, $s1, $a1, $s2, $a2, $s3 # a-d $s3 # (b+d)*2 1 $s3 # (c+d)/2 1
Programme principal
main: li $v0, syscall li $a0, not $a0, sllv $a0, not $a0, int main() { li $a1, int q; li $a2, scanf("%d", &q); jal t printf("%d\n", move $a0, t(~(~0<<q), 0, 0)); li $v0, } syscall li $v0, la $a0, syscall li $v0, syscall 5 # read_int
69
Optimisation
ce code nest pas optimal par exemple, dans le cas a = 0, on sauve/restaure inutilement les registres (y compris $ra), alors quon pourrait se contenter de
li jr
$v0, 1 $ra
70
Lec on
produire du code assembleur efcace nest pas chose aisee (observer le code produit avec gcc -S -fverbose-asm ou encore ocamlopt -S) maintenant il va falloir automatiser tout ce processus
71
La semaine prochaine
TD
eration gen de code pour un mini-langage dexpressions arithmetiques
Cours
analyse lexicale
72