UE MAREP Cours 8 : La pile d’exécution (Fonctions imbriquées et fonctions récursives) Patricia Renault UPMC 2005/2006
2/27 Plan Somme des cases d’adresse paire d’un tableau Appels de fonctions imbriqués Fonctions récursives
3/27 Plan Somme des cases d’adresse paire d’un tableau Programme Transformation en fonction Que devient cette fonction si on n’a que 5 registres ? Que devient cette fonction sans passage par adresse du tableau ? Appels de fonctions imbriqués Fonctions récursives
4/27 Programme simple int tab[10]={5,4,3,2,1,6,4,2,0,8} ; int main(){ int i,cumul=0; int taille=10; for(i=0 ;i<taille ;i=i+2) { cumul = cumul +tab[i] ; } printf("%d\n",cumul);/*affichage de l'entier cumul*/ return 0; }
5/27 Programme simple.data tab :.word 5, 4, 3, 2, 1, 6, 4, 2, 0, 8.stack 256.text __start : ori $8, $0, 10# taille lui $5,tab>>16 ori $5, $5, tab & de tab[0] # corps xor $7, $7, $7# cumul = 0 xor $6, $6, $6# i = 0
6/27 Programme simple boucle : slt $9, $6, $8 # 1 si i<taille beq $9, $0, finadd lw $10, ($5)# tab[i] add $7, $7, $10# cumul = cumul + tab[i] addi $5, $5, 8 de tab[i+2] addi $6, $6, 2 i = i + 2 j boucle finadd : ori $4, $7, 0# affichage ori $2, $0, 1 syscall ori $2, $0, 10# fin syscall
7/27 Transformation en fonction int somme_cases_paires(int tab[], int taille) { int i,cumul=0; for(i=0; i<taille; i=i+2){ cumul = cumul +tab[i] ; } return cumul; }
8/27 Transformation en fonction somme_cases_paires : # 6 reg+$31+2 var loc addiu $29, $29, -36 sw $31, 32($29) sw $5, 28($29) sw $6, 24($29) sw $7, 20($29) sw $8, 16($29) sw $9, 12($29) sw $10, 8($29) lw $5, lw $8, 40($29)#taille # corps (cf. prog) finadd : ori $2,$7,0 # epilogue lw $31, 32($29) lw $5, 28($29) lw $6, 24($29) lw $7, 20($29) lw $8, 16($29) lw $9, 12($29) lw $10, 8($29) addiu $29, $29, -36 jr $31
9/27 Transformation en fonction i($29) cumul4($29) $108($29) $912($29) $816($29) $720($29) $624($29) ($31)32($29) ($29)tab36($29) 4($29)taille40($29) 8($29)//////////////
10/27 Avec 5 registres ? ($7 en moins) somme_cases_paires : # 5 reg+$31+2 var loc # prologue … xor $6, $6, $6 sw $6,($29) # i sw $6,4($29)# cumul boucle : slt $9, $6, $8 beq $9, $0, finadd lw $10, ($5) sw $6,($29)#i lw $6, 4($29)#cumul add $6, $6, $10 addi $5, $5, 8 sw $6, 4($29)#cumul lw $6, ($29)#i addi $6, $6, 2 j boucle finadd : lw $6, 4($29)#cumul ori $2, $6, 0 # épilogue …
11/27 Avec 5 registres ? ($7 en moins) Les espaces mémoires réservés dans la pile pour les variables locales ne sont utilisés que lorsque le nombre de variable locale est supérieur au nombre de registre disponible. Ces espaces réservés dans la pile permettent d’utiliser un même registre pour plusieurs variables locales (en sauvegardant et restaurant la valeur d’une variable locale dans la pile).
12/27 Passage par valeur du tableau ? Mise en œuvre La fonction appelante recopie le tableau dans la pile La fonction appelée utilise la copie du tableau de la pile Inconvénient Compliqué à coder Temps d’exécution très long Conclusion Un tableau est TOUJOURS passé par ADRESSE lors de l’appel de fonction
13/27 Plan Somme des cases d’adresse paire d’un tableau Appels de fonctions imbriqués Ajout d’une fonction supplémentaire pour effectuer la somme des cases d’adresse paire d’un tableau Fonctions récursives
14/27 Ajout d’une fonction supplémentaire int somme_cases_paires(int tab[],int taille){ int i,cumul=0; for(i=0; i<taille; i=i+2){ cumul = add_nb(cumul, tab[i]) ; } return cumul; } int add_nb(int a, int b){ return(a + b); }
15/27 Ajout d’une fonction supplémentaire somme_cases_paires : # prologue # corps avant cumul=… addiu $29, $29, -8 sw $10, 4($29) sw $7,($29) jal add_nb addiu $29, $29, 8 ori $7, $2, 0 # corps après cumul=… add_nb : # 2reg + $31 addiu $29, $29, -12 sw $31, 8($29) sw $4, 4($29) sw $5, ($29) lw $4, 12($29) # a lw $5, 16($29)# b add $2, $4, $5 #a+b lw $31, 8($29) lw $4, 4($29) lw $5, ($29) addiu $29, $29, 12 jr $31
16/27 Ajout d’une fonction supplémentaire cumul tab[i] i($29) cumul4($29) $108($29) $912($29) $816($29) $720($29) $624($29) ($29)tab 4($29)taille 8($29)////////////// $5($29) Dans main Dans somme_cases_paires après prologue Dans add_nb après prologue
17/27 Plan Rappels Appels de fonctions imbriqués Fonctions récursives Définition Exemples Suite récurrente : Fibonacci Factorielle Coefficient du binôme Algorithme
18/27 Définition Une fonction qui se rappelle elle-même 1 ou plusieurs cas d’arrêt un appel à la même fonction avec au moins un paramètre convergeant vers le(s) cas d’arrêt Le nombre de fois qu’une fonction s’appelle dépend des paramètres lors du lancement de la récursion.
19/27 Exemple : Fibonacci Suite de Fibonacci U n = U n-1 + U n-2 n>2 U 1 = 1 U 2 = 1 Exemple fib(4) = fib(3) + fib(2) fib(3) = fib(2) + fib(1) = = 2 D’où fib(4) = 3
20/27 Exemple : Factorielle
21/27 Exemple : Coefficient du binôme
22/27 Exemple : Coefficient du binôme
23/27 Algorithme Suite récurrente U n =2U n-1 +3 U 1 =5 int suite_recur(int n) { if (n-1 == 1) return 5; else return (2*suite_recur(n-1)+3); }
24/27 Algorithme.data n :.word 4 x :.word.stack 128.text __start : lui $3, n >> 16 ori $3, $3, n & 0xFFFF lw $4, ($3) # 4 dans $4
25/27 Algorithme addiu $29, $29, -4 # empilement de 4 sw $4, ($29) jal suite_recur# appel de suite_recur addiu $29, $29, 4 lui $3, x >> 16 ori $3, $3, x & 0xFFFF sw $2, ($3)# sauvegarde de u4 dans x ori $2, $0, 10# fin syscall
26/27 Algorithme suite_recur : addiu $29, $29, -8 # 1 reg+$31+0 var locale sw $31, 4($29) sw $3, 0($29) lw $3, 8($29)# $3 contient n addiu $3, $3, -1 bne $3, $0, branche_recur ori $2, $0, 5# cas terminal j fin_fonction
27/27 Algorithme branche_recur :# $3 contient n-1 addiu $29, $29, -4 sw $3, ($29) jal suite_recur addiu $29, $29, 4 sll $2, $2, 1# $2 contient 2* Un-1 addiu $2, $2, 3 # $2 contient 2*Un fin_fonction : lw $3, 0($29) lw $31, 4($29) addiu $29, $29, 8 jr $31