compilation e cace d'iter ateurs de tableaux lustre · 2006. 9. 7. · david, moussa et cyril...

120
Universit´ e Joseph Fourier U.F.R. Informatique & Math´ ematiques Appliqu´ ees Institut National Polytechnique de Grenoble ENSIMAG I. M. A. G. ECOLE DOCTORALE MATHEMATIQUES ET INFORMATIQUE DEA D’INFORMATIQUE : SYSTEMES ET COMMUNICATIONS Projet pr´ esent´ e par : Lionel MOREL Compilation efficace d’it´ erateurs de tableaux Lustre Effectu´ e au laboratoire : VERIMAG Date : 19 juin 2001 Jury : N. HALBWACHS C. COLLET F. MARANINCHI M-L. POTET

Upload: others

Post on 10-Mar-2021

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Universite Joseph Fourier

U.F.R. Informatique &Mathematiques Appliquees

Institut National Polytechniquede Grenoble

ENSIMAG

I. M. A. G.

ECOLE DOCTORALEMATHEMATIQUES ET INFORMATIQUE

DEA D’INFORMATIQUE :SYSTEMES ET COMMUNICATIONS

Projet presente par :

Lionel MOREL

Compilation efficace d’iterateurs de tableaux Lustre

Effectue au laboratoire : VERIMAG

Date : 19 juin 2001

Jury : N. HALBWACHSC. COLLETF. MARANINCHIM-L. POTET

Page 2: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Lustre est un langage flot de donnees pour la programmation des systemes reactifs. Ildoit donc permettre la production de programmes efficaces et srs, tout en offrant au pro-grammeur des constructions puissantes pour faciliter l’expression des calculs. Les tableaux,introduits dans le langage a partir de la version 4, sont parmi ces constructions. Plusieursinconvenients ont ete associes aux tableaux de Lustre-V4, notamment concernant l’effi-cacite du code qui est produit (les tableaux sont expanses en variables independantes). Denouveaux operateurs ont ete proposes par N. Halbwachs et F. Maraninchi. Ces construc-tions sont a la fois plus sres, plus elegantes et permettent l’obtention d’un code plusefficace. Le present rapport decrit la generation de code pour ces iterateurs, qui permetd’obtenir un code avec tableaux et boucles de type for parcourant ces tableaux. La solu-tion proposee permet de generer du code plus rapide et plus efficace en terme de memoireutilisee.

Page 3: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances
Page 4: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Table des matieres

1 Introduction 11.1 Cadre general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Approche synchrone . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3 Lustre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.3.1 Structures de donnees en Lustre . . . . . . . . . . . . . . . . . . . 31.3.2 Cas des tableaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.4 Plan du rapport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2 Lustre - Vers des iterateurs de tableaux 52.1 Lustre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

2.1.1 Un bref aperu du langage . . . . . . . . . . . . . . . . . . . . . . . . 52.1.2 Exemple de programme . . . . . . . . . . . . . . . . . . . . . . . . . 92.1.3 Methodes de compilation . . . . . . . . . . . . . . . . . . . . . . . . 10

2.2 Rapport espace/temps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162.3 Historique des tableaux en lustre - Motivations . . . . . . . . . . . . . . . . 17

2.3.1 Type tableau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172.3.2 Acces aux elements d’un tableau . . . . . . . . . . . . . . . . . . . . 182.3.3 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182.3.4 Genericite sur la taille . . . . . . . . . . . . . . . . . . . . . . . . . . 182.3.5 Recursivite statique . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.3.6 Exemple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192.3.7 Avantages et inconvenients . . . . . . . . . . . . . . . . . . . . . . . 20

2.4 Vers des iterateurs de tableaux . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Iterateurs de tableaux 253.1 Syntaxe et Semantique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.1.1 Le map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.1.2 Le red . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273.1.3 Le fill . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283.1.4 Le map red . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303.1.5 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

3.2 Retour sur le rapport espace / temps . . . . . . . . . . . . . . . . . . . . . . 333.3 Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

3.3.1 l’operateur mirror . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343.3.2 L’operateur transpose . . . . . . . . . . . . . . . . . . . . . . . . . 35

Page 5: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

iii TABLE DES MATIERES

3.3.3 Le map partiel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4 Etude Bibliographique 404.1 Sur la notion d’iterateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404.2 Sur les optimisations des enchanements d’iterateurs . . . . . . . . . . . . . . 42

4.2.1 Transformation automatique d’expressions “serielles” en boucles . . 424.2.2 Listlessness et deforestation . . . . . . . . . . . . . . . . . . . . . . . 424.2.3 Lien avec les iterateurs Lustre . . . . . . . . . . . . . . . . . . . . . 43

4.3 Aspect temporels des iterations - Le retiming . . . . . . . . . . . . . . . . . 444.3.1 Les Graphes Flots de Donnee synchrones . . . . . . . . . . . . . . . 444.3.2 Retiming d’un DFG synchrone . . . . . . . . . . . . . . . . . . . . . 464.3.3 Liens avec les iterateurs Lustre . . . . . . . . . . . . . . . . . . . . 47

5 Principes de compilation et optimisations 505.1 Schema general de generation de code . . . . . . . . . . . . . . . . . . . . . 50

5.1.1 Representation des programmes . . . . . . . . . . . . . . . . . . . . . 515.1.2 Algorithme de generation de code . . . . . . . . . . . . . . . . . . . 52

5.2 Imbrications d’iterateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 585.3 Enchanements d’iterateurs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

5.3.1 Problematique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615.3.2 Condition d’applicabilite . . . . . . . . . . . . . . . . . . . . . . . . . 635.3.3 Avantages et inconvenients . . . . . . . . . . . . . . . . . . . . . . . 635.3.4 Axiomatisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 655.3.5 Algorithme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

6 Introduction de la notion de temps 806.1 Application des techniques de retiming . . . . . . . . . . . . . . . . . . . . . 806.2 Structure du code desire . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

6.2.1 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 836.2.2 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89

6.3 Identification des cycles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 906.4 Compilation et Optimisation . . . . . . . . . . . . . . . . . . . . . . . . . . 91

7 Experimentation - Le prototype Lac 927.1 Aspects de Lustre utiles pour le prototype : mini-lustre . . . . . . . . . . 92

7.1.1 Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 927.1.2 Expressions, equations . . . . . . . . . . . . . . . . . . . . . . . . . . 927.1.3 Operateurs temporels . . . . . . . . . . . . . . . . . . . . . . . . . . 93

7.2 Le processus de compilation dans Lac . . . . . . . . . . . . . . . . . . . . . 937.2.1 Expansion des appels de noeuds . . . . . . . . . . . . . . . . . . . . 937.2.2 Implementation des axiomes d’optimisation d’enchanements . . . . . 977.2.3 Generation de code . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100

7.3 Exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1007.3.1 Produit scalaire de 2 vecteurs . . . . . . . . . . . . . . . . . . . . . . 1007.3.2 Calcul des 2 maxima d’un tableau . . . . . . . . . . . . . . . . . . . 1017.3.3 L’additionneur n bits . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

Page 6: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

TABLE DES MATIERES iv

7.4 Utilite de la solution presentee . . . . . . . . . . . . . . . . . . . . . . . . . 104

8 Conclusion 1068.1 Bilan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1068.2 Perspectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

A Calcul des 2 max 108A.1 Code C produit par Lac . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108A.2 Version originale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110A.3 Comparaison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111

Page 7: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

RemerciementsJe tiens a remercier vivement :Florence Maraninchi pour m’avoir encadre durant ce projet, pour avoir eu la patience

de repondre a mes (trop) nombreuses questions, pour avoir relu ce rapport attentivementet pour simplement etre quelqu’un avec qui j’aime travailler.

Nicolas Halbwachs et les autres membres de l’equipe synchrone a Verimag pourm’avoir acceuilli formidablement et pour etre toujours a l’ecoute. Merci a Yann pourses explications, ses “trucs” et ses chronogrammes.

David, Moussa et Cyril pour avoir supporte mes humeurs lorsque je travaille, mercipour les intenses seances de revisions communes qui n’ont pas toujours fait avance lascience.

Severine pour son epaule inconditionnelle et, elle aussi, pour avoir supporte mes hu-meurs lorsque je travaille (le soir).

Joseph Sifakis, directeur de Verimag, pour m’avoir accueuilli au sein de son labora-toire.

Page 8: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 1

Introduction

1.1 Cadre general

Le travail presente dans ces pages a ete effectue au sein du laboratoire Verimag,dirige par Joseph Sifakis. Verimag est un unite mixte de recherche du CNRS, de l’INPGet de l’UJF (Grenoble I). Les travaux qui y sont menes visent a etudier et developper desformalismes de modelisation et des techniques et outils de validation pour les systemes etlogiciels critiques. On y developpe notamment des langages de programmation dedies auxsystemes reactifs.

Les systemes reactifs ont une interaction constante avec leur environnement : leurtemps de reponse doit correspondre aux necessites de ce dernier. On les differencie no-tamment des systemes transformationnels qui disposent de toutes leurs entrees a leurinitialisation et delivrent leurs sorties a leur terminaison (comme un compilateur).

Beaucoup de systemes reactifs sont aussi critiques, leur dysfonctionnement ayant unimpact direct nefaste sur leur environnement. En particulier, toute erreur dynamique esta proscrire. Ces systemes sont utilises dans le domaine du transport (avions, trains, . . .)ou de l’industrie (centrales nucleaires).

1.2 Approche synchrone

La famille des langages et formalismes synchrones [Hal93] a represente un contributionimportante dans le domaine de la programmation des systemes reactifs. Cette approcheest a la base des langages Esterel [BG92], Signal[GAPT85] et Lustre[HCRP91]

Elle repose sur l’hypothese de synchronisme, qui etablit que le temps de reaction d’unsysteme est nul. D’un point de vue externe, cela veut dire que les sorties sont produites defaon simultanee avec la reception des entrees. Ceci est clairement impossible a implementer.Neanmoins, un systeme synchrone fonctionne parfaitement du moment qu’il reagit assezrapidement, par rapport a la vitesse “imposee” par son environnement. Par exemple, si lesmodifications significatives dans les entrees du systeme arrivent au plus toutes les secondes,alors le systeme doit pouvoir repondre en au plus une seconde.

Lorsqu’on specifie un systeme reactif a l’aide d’un langage synchrone, on doit donc

Page 9: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

1.3 : Lustre 2

verifier que le code produit par compilation execute bien une reaction suffisamment ra-pidement. On calcule donc un temps d’execution “au pire”. Ce calcul est habituellementrendu difficile par les constructions recursives ou de boucles presentes dans les langages deprogrammation. Mais ces constructions n’apparaissent pas dans les langages synchrones.La structure du code produit est telle qu’on peut toujours fournir une sur-approximationdu temps d’execution.

D’un point de vue interne, l’hypothese de synchronisme etablit que le delai de commu-nication entre les composants d’un programme est nul. La semantique de composition dansun langage synchrone est donc simple : on peut composer une multitude de programmessans changer le temps de reponse global.

On ne cherche pas a produire, a partir de programmes synchrones, des programmesparalleles, auquel cas cet aspect de l’hypothese de synchronisme serait en parfaite contra-diction avec la realite de l’execution du programme. Les langages synchrones sont aucontraire destines a etre compiles vers du code sequentiel centralise ; la composition pa-rallele et le mecanisme de communication entre composants ne sont que des mecanismes dedescription, au niveau du langage. Les programmes sont compiles vers du code sequentielet n’impliquent ni parallelisme explicite ni communication au moment de l’execution.

Enfin, les langages synchrones ne sont pas seulement des langages de specificationmais permettent reellement la programmation des systemes. Leurs environnements deprogrammation fournissent des compilateurs efficaces pour differentes cibles logicielles oumaterielles. Bases sur des semantiques bien definies formellement, il est facile de les connec-ter a des outils de validation tels que debogueurs, generateurs de cas de test, prouveurs.

Le code typique pour un programme synchrone est constitue d’une boucle infinie. Achaque tour de cette boucle, le programme reoit ses entrees, calcule ses sorties et memoriseles valeurs necessaires a la suite de son execution (voir figure 1.1).

<Initialiser la memoire>Pour toujours faire

<lire les entrees><calculer les sorties><mettre a jour la memoire>

Fig. 1.1 – code sequentiel pour un programme synchrone

1.3 Lustre

Lustre est un langage flot de donnees synchrone dedie a la programmation dessystemes reactifs. Il est developpe depuis le milieu des annees 80 a partir d’une idee dePaul Caspi et Nicolas Halbwachs. Le but est de fournir un cadre formel de developpementde logiciels srs et efficaces. A ce titre, certaines caracteristiques de langages plus generaux

Page 10: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3 1 : Introduction

ne sont pas inclus dans Lustre : manipulation explicite de la memoire, allocation dyna-mique de donnees, etc. On cherche ainsi a eviter tout erreur dynamique. Par contre, lelangage contient des mecanismes de description specifiques a la programmation synchroneflot de donnees, notamment la manipulation explicite des flots et des horloges.

La societe Telelogic commercialise un environnement de programmation, appeleTau-Scade base sur Lustre. De nombreuses applications industrielles ont lieu grce auxliens qu’entretient l’equipe avec des societes telles que Schneider Electrics, Aerospatiale,la RATP ou encore la SNCF.

1.3.1 Structures de donnees en Lustre

Lustre permet la manipulation de structures de donnees au travers de langages htes,comme C. La definition dans Lustre de types complexes ne semble pas toujours necessairepuisque ces types ne servent frequemment qu’a vehiculer des informations structurees.

L’inconvenient est que la manipulation de telles structures n’est pas matrisee par lesoutils Lustre. En particulier, on ne peut pas esperer prouver des proprietes liees a lastructuration des donnees si celle-ci n’est pas decrite en Lustre.

L’equipe synchrone a donc propose d’introduire dans Lustre les structures de donneesles plus frequemment utilisees telles que les types a champs multiples (appeles usuellement“records”) et les tableaux.

1.3.2 Cas des tableaux

Afin d’eviter toute erreur dynamique, l’introduction des tableaux dans le langage lui-meme doit repondre aux criteres de srete suivant :

– les tailles doivent etre connues statiquement– on ne doit pas pouvoir acceder a des elements d’un tableau par des indices dyna-

miquesLes tableaux ont ete introduits dans Lustre-V4 pour la description de systemes

materiels. Les techniques de compilation mises en place (expansion des tableaux en va-riables independantes) sont particulierement adaptees a la programmation de circuits.

Puis, Lustre a ete utilise pour le developpement de systemes logiciels. Il s’est avere,comme nous le verrons au chapitre 2, qu’a la fois l’expansion et les primitives de mani-pulation de tableaux (concatenation, extraction de tranches, recursivite statique) ne sontpas pratiques pour le developpement logiciel.

L’equipe synchrone de Verimag a alors propose des iterateurs de tableaux. Le butetait de fournir des outils plus srs, plus faciles a manipuler et pour lesquels le code genereserait plus efficace (code avec tableaux et boucles de parcours sur ces tableaux).

Le travail presente dans ce rapport concerne la generation de code efficace pour cesiterateurs de tableaux, ainsi que les optimisations des enchnements de ces iterateurs.

1.4 Plan du rapport

Au chapitre 2, nous presentons Lustre et les methodes de compilation habituellementutilisees. Nous reviendrons aussi sur les tableaux tels qu’ils sont definis dans Lustre-V4,

Page 11: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

1.4 : Plan du rapport 4

leurs avantages et inconvenients.Le chapitre 3 introduit les iterateurs de tableaux, initialement proposes par Nicolas

Halbwachs et Florence Maraninchi.

Les chapitres 4, 5, 6 et 7 decrivent le travail effectue durant ce projet.Tout d’abord, nous avons cherche dans la litterature des definitions de la notion

d’iterations, qui existe depuis longtemps dans le domaine de la programmation fonction-nelle. Nous y avons trouve aussi bien des definitions formelles de mecanismes d’iterationsque des methodes de compilation adaptees ou encore des possibilites d’optimisationsqu’offrent ces constructions. Cette etude bibliographique est rapporte au chapitre 4.

Puis, nous avons partage notre travail en deux. En premier lieu, nous avons laisse decte les aspects temporels de Lustre. Nous avons alors adopte, pour ce sous-ensemblefonctionnel avec iterateurs, une technique de compilation visant a obtenir, dans le codeC genere, des tableaux et des boucles parcourant ces tableaux. Cette etape est decrite auchapitre 5. On y presente aussi une technique d’optimisation visant a generer du code plusrapide et plus petit pour les enchanements d’iterations.

Ensuite, nous avons reintroduit les operateurs temporels du langage. A quelques res-trictions pres, nous avons pu utiliser les techniques presentees au chapitre 5. Le chapitre6 decrit cette generalisation.

Un prototype de compilateur Lustre a ete developpe dans le cadre de ce projet. Il apermis, tout au long du travail, d’evaluer les techniques et idees que nous avons eu. Nousnous sommes ainsi rendu compte des difficultes d’implementation qu’apporte l’introductiondes iterateurs et la mise en place des optimisations correspondantes. Le chapitre 7 presenteces difficultes ainsi que les choix que nous avons fait dans l’implementation.

Avec ce prototype de compilateur, nous avons pu ecrire beaucoup d’algorithmes usuelsmanipulant des tableaux (tels que tris, calculs de min/max, etc . . .). D’autre part, uneetude de cas importante fournie par Aerospatiale-Matra nous a donne beaucoup d’occasiond’eprouver notre proposition et de montrer qu’elle peut representer un gain en performancetres important. Des exemples significatifs sont presentes au chapitre 7.

En guise de conclusion (chapitre 8), nous indiquerons les perspectives qu’offre ce travailnotamment pour la preuve de programme.

Page 12: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 2

Lustre - Vers des iterateurs detableaux

Dans ce chapitre, nous presenterons tout d’abord Lustre. Nous reviendrons aussisur ce qu’on appelle le rapport espace / temps, qui etablit que l’on peut indifferemmentprivilegier le temps d’execution ou l’espace memoire pour effectuer n’importe quel calcul.

Nous rappellerons ensuite les mecanismes disponibles pour l’instant dans le langagepour la manipulation des tableaux. Nous verrons que ces constructions et les methodesde compilation qui y sont associees (initialement introduites pour la programmation desystemes materiels) presentent plusieurs inconvenients lorsque l’on veut programmer dessystemes logiciels.

2.1 Lustre

2.1.1 Un bref aperu du langage

2.1.1.1 Variables, expressions

En Lustre, toute variable ou expression designe un flot, c’est-a-dire une suite infiniede valeurs d’un type donne.

Une variable X est la suite de valeurs :

x0, x1, . . . , xn, xn+1, . . .

ou xi est la valeur de X a l’instant i.

Si c est une constante, c denote en Lustre la suite infinie de c ; par exemple, laconstante entiere 1 denote la suite (1,1,1,...).

Un operateur classique OP de τ1 × τ2 × . . . × τn dans τ (ou les τi et τ sont des types)opere point a point sur les suites infinies de ces types. Par exemple, l’expression X + Yest definie par :

Page 13: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.1 : Lustre 6

si X = (x1, x2, . . . , xi, . . .)et Y = (y1, y2, . . . , yi, . . .)alors X + Y = (x1 + y1, x2 + y2, . . . , xi + yi, . . .)

Tous les operateurs classiques arithmetiques et logiques usuels sont ainsi predefinis.

2.1.1.2 Operateur sur les suites

Il existe en Lustre un operateur pour faire reference au passe d’une expression. C’estl’operateur pre, qui est defini comme suit :

∀n > 0, pre(X)n = xn−1

Autrement dit, si X = (x1, x2, . . . , xi, . . .), alors pre(X) = (nil, x1, x2, . . . , xi, . . .), ounil denote une valeur indefinie.

L’operateur d’initialisation → permet de definir la valeur d’une suite a l’instant initial.Si X = (x1, x2, . . . , xi, . . .) et Y = (y1, y2, . . . , yi, . . .) sont 2 suites de meme type, alors :

X → Y = (x1, y2, . . . , yi).

2.1.1.3 quations

Une variable “id” peut etre definie a l’aide d’une equation de la forme : id =expression.

On peut ecrire des equations recurrentes comme n = 0 → pre(n) + 1, qui definit deproche en proche n comme la suite des entiers naturels :

pre(n) = (nil, 0, 1, 2, . . .)n = (0, 1, 2, 3, . . .)

Un systeme d’equations Lustre peut etre facilement represente graphiquement parun reseau d’operateurs. La figure 2.1 montre le reseau correspondant a l’equation n = 0→ pre(n) + 1.

0

n1 + −>

pre

Fig. 2.1 – representation graphique du compteur

Page 14: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7 2 : Lustre - Vers des iterateurs de tableaux

2.1.1.4 Horloges et flots

Il n’y a pour l’instant qu’une seule notion de temps dans les programmes Lustre :celle induite par la suite des valeurs (qui definit une horloge dite globale, denotee par laconstante true). Pour certaines applications, il est cependant interessant de faire evoluerdes sous-systemes a des rythmes differents.

Pour cela, il existe un operateur d’echantillonnage when et un operateur de projection(ou de surechantillonnage) current.

echantillonnage avec when

Si E est une expression et C une expression booleenne, E when C denote la suite devaleurs extraite de E quand C est vraie. Quand l’horloge C est fausse, la suite E when Cn’a pas de valeur(figure 2.2).

E = ( e1 e2 e3 e4 e5 . . . )C = ( true false true true false . . . )

X = E when C = ( x1 = e1 x2 = e3 x3 = e4 . . . )

Fig. 2.2 – l’operateur when

projection avec current

Si X denote un flot sur l’horloge C, current X denote un flot sur l’horloge H de C. Achaque instant de l’horloge H, si C est vrai, alors current X porte la meme valeur que X,sinon il porte la valeur prise par X au dernier instant ou C etait vraie (voir figure 2.3).

E = ( e1 e2 e3 e4 e5 . . . )C = ( true false true true false . . . )

X = E when C = ( e1 e3 e4 . . . )Y = current X = ( e1 e1 e3 e4 e4 . . . )

Fig. 2.3 – l’operateur current

Si aucune contrainte d’horloge n’est associee (par l’operateur when) a une variabledonnee, alors c’est l’horloge globale qui est utilisee.

2.1.1.5 Noeuds et reseaux

Les equations Lustre peuvent etre regroupees a l’interieur de programmes appeles“noeuds”. Un noeud possede des entrees, des sorties, des variables locales et des equationsdefinissant ses sorties et variables locales. Les noeuds peuvent etre, comme les operateurs,organises en reseaux, grce aux proprietes de compositionnalite des programmes synchrones.

Page 15: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.1 : Lustre 8

Remarque Il est important de noter que, comme Lustre est un langage declaratif,l’ordre des equations a l’interieur des noeuds n’a pas d’importance.

Un exemple tres simple (donne a la figure 2.4) est le programme qui calcule la sommede ses entrees successives. Au debut de l’execution, le resultat somme est initialise a 0grce a l’expression 0 -> .... Ensuite, a chaque instant, le noeud Accumulateur ajoute ala valeur precedente de somme (identifiee par l’expression pre(somme)) la nouvelle entreequ’on lui fournit (valeur actuelle dans le flot represente par la variable entree), calculantainsi la nouvelle valeur de somme.

node Accumulateur (entree : int) returns (somme : int);letsomme = 0 -> pre(somme) + entree;

tel

Fig. 2.4 – Le noeud Accumulateur

On donne une representation graphique du programme Accumulateur a la figure 2.5.

+ −> sortie

pre

0

entree

Fig. 2.5 – Le programme Accumulateur

2.1.1.6 Types Lustre

En Lustre, les types disponibles sont :– le type entier, note int– le type booleen, note bool– le type reel, note real– le type tableau : si τ est un type quelconque, alors τˆn (ou n est une constante

connue statiquement, voir 2.1.3.1) est le type tableau d’elements de type τ .

Page 16: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

9 2 : Lustre - Vers des iterateurs de tableaux

– le type structure : si τ1, τ2, . . ., τn sont de types, alors, le type τ = τ1, τ2, . . ., τnest un type. Chaque variable de type τ possede n champs : le i-eme champ etant detype τi. Si une variable S est de type int,bool,int alors les differents champs deS sont notes S.%0 (qui est ici un entier), S.%1 (un booleen) et S.%2 (un entier).

2.1.2 Exemple de programme

Dans cette partie, nous allons programmer un ’chien de garde’, c’est-a-dire un dispositifde surveillance de delais de reponse. Cet exemple est tire de [HCRP91].

Ce programme reoit en entree : armer, desarmer (qui sont 2 commandes du systeme) etdate limite (qui est un evenement). Les evenements et commandes sont representes pardes variables booleennes. La valeur vrai denote la presence d’un evenement ou l’executiond’une commande. La sortie alarme doit etre activee a chaque fois qu’une date limite estatteinte et que la derniere commande reue est armer.

alarme = date limite and est arme ;

Reste a definir est arme qui devient vrai a chaque fois que armer est vrai et quiredevient faux a chaque fois que desarmer est vrai :

est arme = armer -> if armer then true else if desarmer thenfalse else pre(est arme);

On propose donc le programme de la figure 2.6.

node chien_de_garde (armer, desarmer, date_limite : bool)returns (alarme : bool);

var est_arme : bool;let

alarme = date_limite and est_arme;est_arme = armer -> if armer

then trueelse if desarmer

then falseelse pre(est_arme);

tel.

Fig. 2.6 – Le programme du chien de garde

Page 17: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.1 : Lustre 10

Le deroulement d’un tel programme peut etre observe sur un chronogramme (voirfigure 2.7)1. Les methodes que nous presentons maintenant sont destinees a compiler untel programme vers du code sequentiel (en l’occurrence du C).

-1 2 31 4 5 6 7 8 9 10 11 12 13 14 15 16

desarmer

date limite

alarme

armer

Fig. 2.7 – chronogramme du chien de garde

2.1.3 Methodes de compilation

2.1.3.1 Verifications statiques

Avant de parler de generation de code imperatif a partir de programmes Lustre,nous allons aborder le probleme des verifications statiques. Celles-ci sont tres importantesa cause du cadre dans lequel les programmes Lustre sont generalement utilises. Dans unsysteme critique, on ne veut en effet avoir strictement aucune erreur dynamique. Il fautdonc que les verifications statiques soient tres efficaces afin de refuser tout programme quipourrait occasionner des erreurs dynamiques.

Ces verifications sont les suivantes :– absence d’appels recursif de noeuds : un noeud ne peut pas s’appeler lui-meme, sauf

dans le cas tres precis de la recursivite statique, dans laquelle l’arret de la recursivitepeut etre assuree statiquement (voir 2.3.5). En effet, si l’arret de la recursion n’estpas assure, on a des programmes qui vont prendre un temps potentiellement infinipour calculer une valeur de leur flot de sortie.

– le calcul d’horloge (detaille ci-dessous) ;– absence d’expressions non-initialisees : on veut eviter les nil comme dans l’expressionpre(X) sans utilisation de → ;

– absence de definitions cycliques : tout cycle dans un reseau (d’operateur ou denoeuds) doit contenir au moins un pre. Une equation telle que X = 3*X + 1 estdonc interdite ;

– definition statique des tailles des tableaux. Aucune allocation dynamique de memoiren’est autorisee. Les tableaux doivent donc etre de taille connue a la compilation. Onverifie aussi que les acces aux elements des tableaux se font par indice statique.

1Ce chronogramme, comme tous ceux apparaissant dans ce rapport, a ete genere automatiquement parl’outil sim2chro de Y. Remond http ://www-verimag.imag.fr/~remond/SIM2CHRO/index.html

Page 18: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

11 2 : Lustre - Vers des iterateurs de tableaux

Calcul d’horlogeConsiderons les equations suivantes dont l’execution est representee a la figure 2.8 :

b = true -> not pre b ;y = x + (x when b) ;

x 1 2 3 4 5b true false true false true

x when b 1 3 5

Fig. 2.8 – exemple de calcul d’horloge impossible a satisfaire

Il s’avere que x et x when b n’ont pas la meme horloge : x a une valeur a tout instantde l’horloge globale, alors que x when b a une valeur seulement quand b est vrai (c’est-a-dire que x when b est basee sur une horloge 2 fois moins rapide que l’horloge globale).Or, on ne sait pas ajouter un entier a une valeur inexistante. Il en resulte une incoherencedans le calcul de l’expression x + x when b.

Definition 2.1 Le calcul d’horloge consiste donc a associer une horloge a chaque expres-sion d’un programme et a verifier (entre autres) la containte suivante : n’importe queloperateur de plus de 1 argument est applique a des operandes qui partagent la meme hor-loge.

L’operation decrite ci-dessus (x + (x when b)) est donc en ce sens interdite enLustre.

Remarquons que les restrictions imposees par le calcul d’horloge peuvent amener arefuser des programmes qui n’aboutiraient pas forcement a des erreurs dynamiques. Sila verification statique accepte le programme, alors on est sr que le programme sera sanserreur dynamique. Si le programme est rejete, il se peut qu’il y ait des erreurs dynamiques.

2.1.3.2 Processus de compilation

Un programme Lustre peut etre compile en plusieurs etapes vers du code sequentiel.Celui-ci est constitue d’une boucle infinie (la boucle de temps), a l’interieur de laquelleon trouve le code correspondant a l’execution d’un passage dans le noeud principal : leprogramme lit ses entrees, puis calcule ses sorties avant de memoriser les valeurs qui luiseront necessaires aux instants suivants. Tout au long du rapport, nous ne nous interessonsqu’a deux parties dans ce code : le calcul des sorties et la mise a jour des memoires. Lespropositions que nous faisons ne concernent que ces 2 parties. De ce fait, dans tous lesexemples presentes, nous ne donnons que ces 2 parties.

2 cheminements de compilation sont possibles (voir la figure 2.10).

Page 19: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.1 : Lustre 12

Le premier consiste a compiler le programme Lustre en un programme EC (pourexpanded code). Un programme EC est en fait un programme Lustre constitue d’un seulnoeud. Les appels de noeud ont ete expanses. Par exemple, soit le noeud plusUn de lafigure 2.9. Soit maitenant, dans le noeud principal du programme considere, l’equation A= plusUn(B). Dans le code EC, cette equation aura ete remplacee par l’equation : A = B+ 1. L’appel du noeud plusUn a ete expanse. A partir du programme EC, on peut genererle code C correspondant a l’aide de l’outil ec2c.

Le second consiste a compiler le programme Lustre en un programme DC, grce al’outil lus2dc. Le langage DC[Ver99] est aussi un langage declaratif qui sert de formatintermediaire pour plusieurs langages synchrones. La caracteristique principale du pro-gramme DC est que le calcul d’horloge decrit ci-dessus a ete effectue. Grce a l’outil drac,on peut compiler le programme DC en un programme C.

node plusUn(in : int) returns (out : int);let

out = in + 1;tel

Fig. 2.9 – le noeud plusUn

EC est le format intermediaire qui a ete developpe en premier pour compiler Lustre.Les outils de verifications pour Lustre travaillent principalement avec ce format. Leformat DC a ete introduit dans le cadre des projets SYNCHRON2 et SYFR3 pour tenterde donner un format interne commun a plusieurs langages synchrones (Lustre, Signal etEsterel).

Des outils sont disponibles pour traduire des programmes EC en programmes DC etinversement.

2voir http ://www.inria.fr/rapportsactivite/RA95/epatr/node26.html3Synchronous Reactive Formalisms, voir http ://www-verimag.imag.fr//SYNCHRONE/SYRF/syrf.html

Page 20: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

13 2 : Lustre - Vers des iterateurs de tableaux

.lus

.dc .ec

.c .h .c .h

ec2c

lus2dc lus2ec

drac

Fig. 2.10 – Compilation de Lustre

Code genere pour le chien de gardeRevenons sur l’exemple du chien de garde. Nous pouvons compiler le programme

donne a la figure 2.6 avec les outils lus2ec ou drac. On obtient le code decrit ci-dessous(on ne donne que le calcul des sorties et des memoires).

Voici tout d’abord la definition des entrees-sorties du programme reunies au sein d’unememe structure. f5 sert a identifier le debut de l’execution (il vaut vrai a l’instant initialet faux dans la suite de l’execution) et f6 sert a memoriser la valeur courante de est armepour le coup d’apres.

typedef struct boolean armer;boolean desarmer;boolean date limite;boolean alarme;boolean est arme;boolean f5;boolean f6;void* client data;

chien de garde ctx;

La fonction chien de garde step contient le code necessaire a un passage dans laboucle de temps. On trouve y le calcul des variables locales et des sorties (ici est arme etalarme)

Page 21: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.1 : Lustre 14

void chien de garde step(chien de garde ctx ptr ctx)

/******** equ:, equcase:, actioncall: and proccall: ********/

ctx-> est arme = (ctx->f5 ? (ctx-> armer) :((ctx-> armer ? (true) :((ctx-> desarmer ? (false) : (ctx->f6))))));

ctx-> alarme = ctx-> date limite && ctx-> est arme;

Puis, les sorties sont emises et les valeurs necessaires a l’execution dans l’instant d’apressont memorisees.

/************ Output ************/

chien de garde O alarme(ctx->client data, ctx-> alarme);

/******* memo:, memocase: *******/

ctx->f5 = false;ctx->f6 = ctx-> est arme;

2.1.3.3 Remarques

le calcul des sorties et la partie “memorisation” doivent etre separes.Soit l’equation X = 0 -> pre(X) + 1 ;. Si X est utilisee seulement dans cette

equation, alors le calcul et la memorisation peuvent etre effectuees en meme temps. Iln’est pas necessaire d’utiliser une variable auxiliaire comme on utilise la variable f6 pourmemoriser la valeur de est arme dans le programme du chien de garde.

Par contre, si on a, en plus, une equation comme Y = 0 -> pre(X) + ... (commedans le noeud de la figure 2.11), alors on se retrouve dans le meme cas que dans lechien de garde. On doit generer 2 equations de calcul de sortie : X = X’ + 1 et Y =X’ + ... ; ainsi qu’une equation de memorisation : X’ = X. qui doit etre effectuee aprestoutes les equations de calcul de sortie. X’ represente en fait la valeur a l’instant suivantde la variable X.

La semantique de l’equation Y = 0 -> pre(X) + A ; est la suivante : “A tout instantsuivant l’instant initial, Y doit prendre pour valeur la somme de la valeur courante de A etde la valeur de X a l’instant precedent.” Si on se contente de generer les equations X = X +1 et Y = X + 1 (dans cet ordre), alors il parat evident que Y n’aura pas la valeur desiree :il vaudra la somme de la valeur courante de A et de la valeur courante (et non-pas celle al’instant precedent) de X. Au moment ou l’on modifie Y avec Y=X+1, X a deja ete modifiea X+1.

Page 22: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

15 2 : Lustre - Vers des iterateurs de tableaux

node N (A : int) returns (X,Y : int);let

X = 0 -> pre(X) + 1;Y = 0 -> pre(X) + A;

Fig. 2.11 – Un noeud Lustre necessitant l’utilisation, lors de la generation de code, devariables intermediaires correspondant aux pre

Quant a l’ordre des equationsL’ordre des equations dans un programme Lustre n’a pas d’importance. Mais l’ordre

des actions correspondantes dans le programme cible sequentiel a, evidemment, de l’impor-tance. Il faut donc proceder a un tri des equations Lustre afin d’obtenir un programmeimperatif coherent. Pour cela, on construit un graphe de dependance des variables du pro-gramme et on fait un tri topologique de ce graphe qui nous donne l’ordre des actions dansle code sequentiel.

Page 23: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.2 : Rapport espace/temps 16

2.2 Rapport espace/temps

Imaginons que l’on veuille calculer la somme de 4 entiers.Une premiere version consiste a definir un noeud qui prend 4 entrees entieres et qui

calcule, en un coup d’horloge, la somme de ces 4 entiers. Ce noeud s’ecrit de la manieresuivante :

node sum (x1, x2, x3, x4 : int) returns (sum : int);let

sum = x1 + x2 + x3 + x4;let

L’avantage de cette solution est que le calcul voulu ne prend qu’un instant. Evidem-ment, il faut 4 “cases” memoires pour les 4 entiers.

Une seconde version consisterait a etaler ce calcul dans le temps. C’est ce qui estfait dans le noeud SumTps decrit ci-dessous. Celui-ci n’a qu’une entree correspondant al’element que l’on considere dans l’instant present. Au bout de 4 instants, on rend lasomme calculee et on recommence a en calculer un nouvelle.

node SumTps (x : int) returns (sum : int);var sum_current : int;

rang : int;letsum_current = x -> if(pre(rang)=4)

then xelse pre(sum_current) + x;

rang = 1 -> if(pre(rang)=4)then 1else pre(rang) + 1;

sum = if(rang=4) then sum_current else 0;tel

L’execution de ce dernier programme se deroule comme suit (voir le chronogrammefigure 2.12) :

– La variable sum vaut toujours 0 sauf lorsqu’on vient de voir 4 elements. A ce momentprecis, sum vaut la somme des 4 dernieres valeurs de X ;

– sum current sert d’accumulateur : il memorise la somme des 1 a 4 dernieres valeursde X deja vues ;

– rang sert de compteur.

Dans cette seconde solution, on privilegie l’espace : a chaque instant, au lieu d’avoir be-soin des 4 elements d’un coup, on n’a besoin que d’un. L’inconvenient est qu’evidemment,on a besoin de 4 instants pour obtenir le resultat.

Page 24: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

17 2 : Lustre - Vers des iterateurs de tableaux

sum_current

x

rang

sum

1 2 3 4 5 6 7 8 9 10 11 12

1 2 3 4 5 6 7 8 9 10 11 12

12

34

12

34

12

34

3 510

16

16

1425

10

2545

60

0 0 0

16

0 0 0

25

0 0 0

60

10 203 2 5 6

1 5 811 15 15

Fig. 2.12 – Chronogramme du programme SumTps

La premiere solution realise un additionneur parallele alors que la seconde implementeun additionneur serie. Ces deux versions du meme calcul nous montrent qu’il est possible,en Lustre, de “choisir” quelle ressource on veut privilegier, l’ espace ou le temps.

2.3 Historique des tableaux en lustre - Motivations

Les tableaux ont ete introduits dans Lustre-V4 pour la description de systemesmateriels (circuits reguliers) (voir notamment [HR92, FN91]). Ils sont actuellement ex-panses par le compilateur : celui-ci traduit un tableau de n elements en n variablesindependantes.

Cette technique de compilation est inevitable pour la programmation de systemesmateriels et pour la verification de programme telle qu’on sait la faire pour l’instant.Malheureusement, elle n’est plus du tout adaptee pour la programmation de systemeslogiciels.

Dans un premier temps, nous decrivons les techniques de manipulation de tableauxdisponibles dans Lustre-V4. Ensuite nous montrons en quoi ces techniques ne sont pasadaptees pour la programmation de logiciels. Enfin, nous presentons les objectifs de laproposition d’iterateurs de tableaux qui a ete faite en 1999 par l’equipe synchrone deVerimag, proposition elle-meme detaillee dans le prochain chapitre.

2.3.1 Type tableau

Si τ est un type et si n est une constante entiere connue statiquement, alors τˆn est letype tableau d’elements de type τ .

Page 25: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.3 : Historique des tableaux en lustre - Motivations 18

Par exemple, les definitions suivantes sont acceptees pour declarer un tableau de taille42, un type registre, “tableau de booleens de taille 16” et une variable R du typeregistre.

T : int^42;const TAILLE = 16;type registre = bool^TAILLE;R : registre;

Comme nous l’avons souligne plus haut, nous ne pouvons pas admettre d’erreur dy-namique dans des systemes critiques. On n’accepte donc pas la definition de donnee dontla taille serait inconnue statiquement, et ce pour eviter, par exemple, de declarer dynami-quement un tableau de taille trop grande par rapport a la memoire disponible.

2.3.2 Acces aux elements d’un tableau

Soit A un tableau de taille n. Ses elements sont : A[0], A[1], ..., A[n-1].L’expression A[i] est acceptee, du moment que i est une constante connue a la com-

pilation (pour eviter les debordements de tableaux) et que 0 ≤ i ≤ n-1.

2.3.3 Expressions

On peut utiliser les constructeurs suivants :– [0,2,3] represente le tableau d’elements 0,2,3.– true^3 = [true,true, true]– constructions par tranches. On a, de maniere generale :

A[i..j] =

[A[i], A[i + 1], . . . , A[j]] si i ≤ j[A[i], A[i− 1], . . . , A[j]] si j < i

– Concatenation : A|B = [A[0], A[1], . . . , A[n− 1], B[0], B[1], . . . , B[m− 1]]

videmment, tous les operateurs polymorphiques de Lustre (if ...then ...else..., pre, →) s’appliquent au tableaux. Par exemple, on peut ecrire :

A = true^4→ if c^4 then B[4..7] else pre(A) ;

2.3.4 Genericite sur la taille

En Lustre, la taille d’un tableau T peut etre un parametre generique du noeud danslequel T est defini.

node main<<n : int>>(A : int^n) returns (B : int^n);let...tel

Fig. 2.13 – Exemple d’en-tete d’un noeud generique

Page 26: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

19 2 : Lustre - Vers des iterateurs de tableaux

La valeur des parametres generiques doit toujours etre connue a la compilation, et cepour eviter l’allocation de structure de donnees trop grande pour la memoire disponiblelors de l’execution du programme.

Il faut donc instancier un noeud generique par une equation de type :

size = 10;

node ...(T : int^10) returns (T’ : int^10);let

T’ = main<<size>>(T);tel

qui applique le noeud main a des tableaux de taille 10.On peut ecrire des algorithmes manipulant des tableaux de taille quelconque et les ins-

tancier sur les tableaux que l’on manipule reellement. La genericite permet la reutilisabilitedes programmes.

2.3.5 Recursivite statique

Il existe en Lustre un mecanisme de recursivite statique qui autorise l’appel d’unnoeud par lui-meme a condition que l’arret de la recursivite puisse etre assure statiquement.

Imaginons que l’on veuille programmer un algorithme qui prend 2 entrees A et B quisont des tableaux de n booleens et qui rende une matrice carree AB (de taille n×n) definiepar l’equation :

∀i, j ∈ [0, n], AB[i, j] = A[i] and B[j]

Le noeud Lustre correspondant (issu d’un programme calculant un produit d’entiersrepresentes par des vecteurs de booleens) est le suivant :

node prod(const n,i : int;a,b : bool^n) returns(ab : bool^n^(n-i));let

ab = with i=n-1 then [b and a[i]^n] else[b and (a[i])^n]|prod(n,i+1,a,b);

tel;

A chaque appel de prod, i augmente (car on appelle prod(n,i+1,a,b)). La conditioni=n-1 est alors forcement assuree lors des appels recursif de prod. Lorsqu’elle l’est, ab neprend plus la valeur rendue par un nouvel appel de prod (la recursion s’arrete) mais prendla valeur de l’expression [b and a[i]^n]. L’arret de la recursion peut donc etre evaluerstatiquement, le programme prod est donc accepte par le compilateur Lustre-V4.

2.3.6 Exemple

La description de systemes materiels grce aux tableaux V4 est assez satisfaisante etelegante. On peut, par exemple, definir un additionneur N bits par le programme suivant(voir figure 2.14) :

Page 27: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.3 : Historique des tableaux en lustre - Motivations 20

const n=10;

node FULL_ADD(ci,a,b : bool) returns (co,s : bool);let

s = a xor (b xor ci);co = (a and b) xor (b and ci) xor (a and ci);

tel

node ADD(A,B : bool^n) returns (S : bool^n ; overflow : bool);var CARRY : bool^n;let

(CARRY,S) = FULL_ADD([false] | CARRY[0..n-2],A,B);overflow = CARRY[n-1];

tel

A[n-1]B[n-1]

A[j+1] A[j]B[j]

A[1] A[0]B[0]B[1]

S[n-1] S[j+1] S[j] S[1] S[0]

B[j+1]

ADD FULL false

overflow

CA

RRY

[0]

CA

RRY

[1]

CA

RRY

[j]

CA

RRY

[n-1]

CA

RRY

[j+1]

Fig. 2.14 – un additionneur n bits

Les solutions proposees plus loin sont plus adaptees a la programmation de systemeslogiciels. Elles se rapprochent plus des constructions generalement fournies dans le domainede la programmation fonctionnelle.

2.3.7 Avantages et inconvenients

Le compilateur V4 expanse les tableaux en variables independantes. Par exemple,on peut compiler le programme ADD avec la commande lus2ec et on obtient le code in-termediaire (en Lustre) de la figure 2.15. Les appels de noeuds ont aussi ete expanses(on n’a donc plus qu’un seul noeud Lustre).

Comme on peut l’observer a la figure 2.15, on a perdu la structuration des donneessous forme de tableaux. A la place du tableau de booleens A (qui etait de taille n), on amaintenant n variables booleennes independantes. Le code C genere pour ce programmeaura donc aussi des variables independantes a la place des tableaux.

Lorsque l’on compile pour une cible materielle (comme des circuits programmables),cette methode est tout a fait adequate. Elle permet egalement d’appliquer les outils deverification sans difficulte, puisque l’on se ramene au cas des programmes sans tableaux.

Page 28: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

21 2 : Lustre - Vers des iterateurs de tableaux

node ADD(A_0: bool; A_1: bool; A_2: bool; A_3: bool; A_4: bool;A_5: bool; A_6: bool; A_7: bool; A_8: bool; A_9: bool;B_0: bool; B_1: bool; B_2: bool; B_3: bool; B_4: bool;B_5: bool; B_6: bool; B_7: bool; B_8: bool; B_9: bool)

returns(S_0: bool; S_1: bool; S_2: bool; S_3: bool; S_4: bool;S_5: bool; S_6: bool; S_7: bool; S_8: bool; S_9: bool;overflow: bool);

varV59_CARRY_0: bool; V60_CARRY_1: bool; V61_CARRY_2: bool;V62_CARRY_3: bool; V63_CARRY_4: bool; V64_CARRY_5: bool;V65_CARRY_6: bool; V66_CARRY_7: bool; V67_CARRY_8: bool;

letS_0 = (A_0 xor (B_0 xor false));S_1 = (A_1 xor (B_1 xor V59_CARRY_0));...S_9 = (A_9 xor (B_9 xor V67_CARRY_8));

overflow = (((A_9 and B_9) xor (B_9 and V67_CARRY_8))xor (A_9 and V67_CARRY_8));

V59_CARRY_0 = (((A_0 and B_0) xor (B_0 and false))xor (A_0 and false));

V60_CARRY_1 = (((A_1 and B_1) xor (B_1 and V59_CARRY_0))xor (A_1 and V59_CARRY_0));

...V67_CARRY_8 = (((A_8 and B_8) xor (B_8 and V66_CARRY_7))

xor (A_8 and V66_CARRY_7));tel.

Fig. 2.15 – code Lustre intermediaire produit pour le programme ADD

Page 29: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.3 : Historique des tableaux en lustre - Motivations 22

Mais Lustre est de plus en plus utilise pour programmer des systemes logiciels. L’ex-pansion de code est alors inutile et le code obtenu n’est pas satisfaisant. En effet, il est :

– lent. Lustre est conu pour programmer des systemes reactifs dont le temps dereponse est, comme nous l’avons vu plus haut, impose par l’environnement. Enexpansant un tableau en autant d’elements qu’il possede, on obtient dans le codeproduit, autant d’affectations qu’il y a d’elements dans le tableau, et donc autantd’acces memoire. Nous verrons qu’en conservant une structure de tableaux, avecboucles de parcours, on peut n’obtenir qu’un seul acces memoire pour le debut dutableau plus des decalages plus rapides a effectuer pour chacun des elements.

– trop gros, et c’est le point le plus important : La manipulation de tableaux, dansle code imperatif produit, permettrait l’utilisation de boucle les parcourant, ce quireduirait considerablement la taille du code. On pourrait compiler le programmeADD en un programme C comme celui-ci4 :

for(i=0;i<n;i++)S[i] = A[i] xor (B[i] xor C[i]);CARRY[i] = (A[i] && B[i])

|| (B[i] && CARRY[i-1])|| (A[i] && CARRY[i-1];

overflow = CARRY[n-1];

Un autre probleme lie aux tableaux en V4 est leur difficulte de manipulation et ladifficulte de generer du code avec boucle a partir des operateurs disponibles. Par exemple,soient X et Y 2 tableaux de taille 6. On peut ecrire les equations suivantes (representeesdans la figure 2.16) :

X[0] = Y[0];X[1..2] = Y[4..5];X[3..5] = Y[1..3];

2

6

10

12

8

43

7

11

9

5

1

X Y

Fig. 2.16 – Calculs de tableaux par tranches

4On peut noter simplement que le code ci-dessus est un code a 2 boucles. En effet, nous n’avons pasecrit le code complet qui comprend la boucle de temps (reactivite) et la boucle d’espace donnee ci-dessus.

Page 30: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

23 2 : Lustre - Vers des iterateurs de tableaux

Il est difficile de generer du code avec boucle de parcours (comme decrit ci-dessus)pour un tel programme. En effet, on ne peut arriver facilement a definir le i-eme elementde X en fonction du i-eme element de Y (ou de n’importe quel element repere par uneexpression fonction de i).

2.4 Vers des iterateurs de tableaux

Pour resoudre les problemes evoques ci-dessus, l’equipe Lustre a propose d’introduiredes iterateurs de tableaux dans le langage. Ces operateurs sont largement inspires de ceuxque l’on trouve pour la manipulation des listes dans les langages fonctionnels. Il s’agitdu map, du red, du fill et du map red, decrits dans le chapitre suivant. Des methodesde compilation adaptees permettront de generer du code C avec tableaux et boucles. Lesavantages attendus sont les suivants :

• Taille du code C produit : Dans tous les cas ou l’on applique n fois un calculCalc (potentiellement identifie comme un noeud), on reduit n copies du code deCalc a une seule (voir exemple ADD ci-dessus). Le code sans iterateurs de tableauxest beaucoup plus gros, aussi bien en C que dans tout assembleur que l’on obtientpar compilation du programme C.

• Temps d’execution du code C produit : Considerons un programme C P1constitue de n affectations explicites en sequence ; un programme C P2 constitued’une boucle comportant une seule affectation ; la boucle est executee n fois. P1 esten general un peu plus lent que P2. Cela depend beaucoup du processeur cible, etdes optimisations du compilateur C (dans n affectations, il y a n calculs d’adressesen memoire, alors que dans une boucle d’acces a un tableau, le code assembleurproduit peut en general ne contenir qu’un vrai calcul d’adresse, plus des decalagesplus rapides a effectuer).

• Taille memoire necessaire a l’execution du code C produit : Il n’y a pasde difference intrinseque entre n variables et un tableau de taille n. Toutefois, si lestraitements de tableaux sont exprimes en iterateurs, il est possible de reperer lescas de variables intermediaires inutiles (voir chapitre 5) . Par exemple, deux “map”enchanes necessitent un tableau intermediaire (le resultat du premier map et ladonnee du second). On sait transformer le programme, en gardant son comportementintact, de maniere a faire disparatre cette structure de donnees intermediaire (voirchapitre 5). On obtient un gain de place et un certain gain en temps (il faut bienaffecter et relire chacun des elements de cette structure intermediaire, quand elle estpresente).

• Genericite sur la taille : les programmes sont naturellement ecrits sous formede manipulations de tableaux de taille n, et il n’est pas indispensable de connatrela valeur de n pour ecrire le programme. Il faut simplement fixer une valeur pourobtenir un programme executable.

• “structuration”, prouvabilite : Identifier explicitement des tableaux partout ouun ensemble de donnees vont etre traitees de maniere tres similaire (meme s’il ya quelques exceptions), permet de mieux structurer les specifications. Cela a pourconsequences (entre autres) : une meilleure lisibilite du code, une meilleure prise

Page 31: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

2.4 : Vers des iterateurs de tableaux 24

en compte de la structure par les outils avals comme un simulateur, un debogueurou des outils de preuve. Par exemple, meme si aujourd’hui on ne sait realiser lespreuves automatiques de programmes a tableaux qu’en expansant les tableaux, onpeut imaginer tirer partie de la structure des donnees des programmes pour aider aleur preuve.

Un autre avantage des iterateurs de tableaux tels qu’ils ont ete proposes pour Lustreest la facilite d’utilisation et de reutilisabilite. Les modifications apportees aujourd’huiau langage seront ensuite proposees pour les outils de developpement bases sur Lustre(notamment Scade, developpe par la societe Telelogic). On proposera a terme des bi-bliotheques de programmes ecrits pour la manipulation de tableaux (programmes clas-siques de calcul de minimum, de maximum, programmes de tris, etc.). L’aspect degenericite de la taille, presente plus haut, est dans ce cadre tres important. De meme,les optimisations proposees au chapitre 5 (de type enchanements de maps) seront tresutiles.

Lustre-V6(version avec les iterateurs que nous allons presente par la suite) ne cherchepas a remplacer Lustre-V4pour la programmation de circuits. On cherche juste a donnerdes outils assez puissants et expressifs pour la programmation de systemes logiciels.

Page 32: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 3

Iterateurs de tableaux

3.1 Syntaxe et Semantique

Nous donnons ici une description syntaxique et semantique des 4 iterateurs Lustre.Cette description est celle qui a ete introduite par Nicolas Halbwachs dans [Hal99].

Pour chaque iterateur, nous donnons une description independante de la syntaxe quimanipule non pas des noeuds mais des fonctions purement mathematiques. Cette notationsera aussi utilisee pour presenter les axiomes d’optimisation du chapitre 5. Puis le lecteurtrouvera la syntaxe et la semantique de l’implementation Lustre. Enfin, nous donnons,pour chaque cas, le code C qui devrait etre genere pour l’equation donnee en exemple.

NotationsPar la suite, n denote un entier dont la valeur doit etre, en Lustre, connue stati-

quement.T et T’ denotent des tableaux de taille n. Les τ denotent n’importe quel typeLustre. Rappelons que si τ denote un type quelconque, alors τˆn est le type tableau deτ .

Nous manipulons des fonctions sous la forme de λ-termes a plusieurs parametres. Parexemple, soit le λ-terme suivant : λxλy.x+y. Pour representer un tel terme, nous ecrirons,λx, y.x + y, notation qui correspond a la syntaxe Lustre.

3.1.1 Le map

L’operation de mapping consiste a appliquer la meme fonction g = λt.t′ a tous leselements d’un ou plusieurs tableaux (T, dans notre exemple). Les resultats sont les elementsd’ autres tableaux (T’).

La syntaxe abstraite de l’operateur map est la suivante :

T ′ = map(g, T ).

En Lustre, les syntaxe et semantique exactes Lustre sont donnees ci-dessous. Nousne parlons plus de fonction, mais de noeud ou d’operateur.

Si N (resp., O) est un noeud Lustre (resp., un operateur) de profile :

τ1 × τ2 × . . .× τl → τ ′1 × τ ′2 × . . .× τ ′k,

Page 33: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.1 : Syntaxe et Semantique 26

Et si n est une constante statique, alors mapN,n (resp. map0,n) est considerecomme un noeud (resp. un operateur) 1 de profile :

τ1ˆn×τ2ˆn× . . .× τlˆn→ τ ′1ˆn×τ ′2ˆn× . . .× τ ′lˆn.

ExempleLe schema 3.1 montre un map simple, avec un tableau en entree et un tableau en sortie.

Le schema 3.2 montre plus en detail le noeud mappe. Le code du programme correspondantest donne ci-dessous.

Voici le noeud itere :

node N(elt : τ1) returns (elt’ : τ1’);letelt’ = ...;

tel

Et l’iteration de ce noeud grce a un map a l’interieur d’un noeud test :

node test(T : τ1^n) returns (T’ : τ1’^n);letT’ = map<<N,n>>(T);

tel

T T’

N

Fig. 3.1 – L’operation map

elt elt’N

Fig. 3.2 – le noeud itere

Code C correspondantLe code que l’on produit pour l’equation Lustre T’ = map N,n(T) est :

1Dorenavant, nous ne ferons plus la difference entre noeud et operateur

Page 34: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

27 3 : Iterateurs de tableaux

for(i=0;i<n;i++)T’[i] = N(T[i]);

3.1.2 Le red

La reduction, frequemment appelee foldl [GLP93], permet de calculer un accumulateuren parcourant un ou plusieurs tableau(x) . Soit la fonction g = λt, accu.accu′. La reductionr d’un tableau T a l’aide de cette fonction peut etre calculee de la maniere suivante :

r = red(init, T, g),

ou init est une expression d’initialisation de la reduction.En Lustre, on utilise l’operateur red qui a la syntaxe suivante : si N est un noeud de

profile :

τ × τ1 × τ2 × . . .× τl → τ ′

et si n est une constante statique, alors redN,n est un noeud de profile :

τ × τ1ˆn×τ2ˆn× . . .× τlˆn→ τ ′

ExempleLe schema 3.3 montre un red simple, avec un tableau en entree. Le schema 3.4 montre

plus en detail le noeud itere. Le code du programme correspondant est donne ci-dessous.Voici le noeud itere :

node N(accu : τ ; elt : τ1) returns (accu’ : τ’);letaccu’ = ...;

tel

Et l’iteration de ce noeud grce a un red a l’interieur d’un noeud test :

node test(init : τ ; T : τ1^n) returns (res : τ’);letres = red<<N,n>>(init,T);

tel

Code C correspondantLe code que l’on produit pour l’equation Lustre T’ = red N,n(init,T) est :

res = init;for(i=0;i<n;i++)res = N(res,T[i]);

Page 35: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.1 : Syntaxe et Semantique 28

T

Ninit

res

Fig. 3.3 – L’operation de reduction

accu

accu’

eltN

Fig. 3.4 – le noeud itere

Remarque 3.1 (Concernant le noeud itere) Un noeud itere par un red aura tou-jours la structure suivante :

– Au moins 2 entrees : la premiere correspondant a l’accumulateur, les suivantes cor-respondant aux elements des tableaux donnes en parametre au red

– Toujours une seule sortie : celle correspondant a l’accumulateur.

Ceci ne limite en rien les possibilites offertes : en effet, on peut utiliser des accumu-lateurs a type structure, avec autant de champs que desire. Nous verrons cela dans lesexemples en 7.3.

3.1.3 Le fill

L’operateur fill permet de remplir un ou plusieurs tableaux. Cet operation consistea calculer iterativement la valeur de chaque element du ou des tableaux a remplir, enprenant en compte une valeur initiale. Le i-eme element du tableau est donc le resultatde la fonction iteree, appliquee i fois a la valeur initiale de l’”accumulateur”.

Soit la fonction g= λaccu.accu′, elt. Le tableau T peut etre ’remplit’ avec l’equationsuivante :

T = fill(a, g),

ou a est une expression d’initialisation du remplissage.En Lustre, on utilise l’operateur fill qui a la syntaxe suivante : si N est un noeud

de profile :

τ → τ × τ ′1 × τ ′2 × . . .× τl

Page 36: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

29 3 : Iterateurs de tableaux

et si n est une constante statique, alors fill N,n est un noeud de profile :

τ → τ ′1ˆn×τ ′2ˆn× . . .× τlˆn

ExempleLe schema 3.5 montre un fill simple, avec un tableau en sortie. Le schema 3.6 montre

plus en detail le noeud itere. Le code du programme correspondant est donne ci-dessous.Voici le noeud itere :

node N(accu : τ) returns (accu’ : τ ; elt’ : τ1’);letaccu’ = ...;elt’ = ...;

tel

Et l’iteration de ce noeud grce a un red a l’interieur d’un noeud test :

node test(init : τ) returns (T : τ1’^n);letT = fill<<N,n>>(init);

tel

T’

initN

Fig. 3.5 – L’operation de remplis-sage

elt’

accu’

accu

N

Fig. 3.6 – detail

Code C correspondantLe code que l’on produit pour l’equation Lustre T = fill N,n(init) est :

Page 37: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.1 : Syntaxe et Semantique 30

evolution = init;for(i=0;i<n;i++)evolution,T[i] = N(evolution);

Notons l’utilisation dans le code genere d’une variable non definie dans le programmeLustre qui sert d’accumulateur durant le remplissage.

Remarque 3.2 (Concernant le noeud itere) Comme pour le red, le noeud utilise parun fill doit respecter certaines contraintes :

– Toujours une seule entree : celle correspondant a l’accumulateur ;– Au moins 2 sorties : la premiere correspondant a l’accumulateur, les suivantes cor-

respondant aux elements des tableaux que l’on remplit par le fill.

3.1.4 Le map red

L’operation de map red constitue en fait l’operateur general duquel tous les autrespeuvent etre deduits. Si T et T’ sont deux tableaux et si g est une fonction definit par : g= λaccu, t.accu′, t′, alors on peut avoir :

(T ′, b) = map red(b, T, g)

En Lustre, les syntaxe et semantique exactes sont donnees ci-dessous.Si N est un noeud lustre :

τ × τ1 × τ2 × . . .× τl → τ × τ ′1 × τ ′2 × . . .× τ ′k,

et si n est une constante statique, alors map redN,n est considere comme un noeudde profile :

τ × τ1ˆn×τ2ˆn× . . .× τlˆn→ τ × τ ′1ˆn×τ ′2ˆn× . . .× τ ′lˆn.

ExempleLe schema 3.7 montre un map red simple, avec un tableau en entree et un tableau

en sortie. Le schema 3.8 montre plus en detail le noeud itere. Le code du programmecorrespondant est donne ci-dessous.

Voici le noeud itere :

node N(accu : τ ; t : τ1) returns (accu’ : τ ; t’ : τ1’);lett’ = ...;

tel

Et l’iteration de ce noeud grce a un map red a l’interieur d’un noeud test :

node test(accu_in : τ ; T : τ1^n) returns (accu_out : τ ; T’ : τ1’^n);letaccu_out,T’ = map_red<<N,n>>(accu_in,T);

tel

Page 38: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

31 3 : Iterateurs de tableaux

T’T

Naccu in

accu out

Fig. 3.7 – L’operation map red

accu

N elt’elt

accu’Fig. 3.8 – detail

Code C correspondantLe code que l’on produit pour l’equation Lustre T’ = map red N,n(T) est le

suivant :

accu_out = accu_in;for(i=0;i<n;i++)accu_out,T’[i] = N(accu_out,T[i]);

Remarque 3.3 (Concernant le noeud itere) Au moins 2 entree et 2 sorties :– la premiere entree et la premiere sortie correspondent a l’accumulateur ;– les autres entrees/sorties correspondent aux elements des tableaux

consommes/produits par l’iteration.

3.1.5 Exemples

3.1.5.1 L’additionneur n bits

Dans 2.3.6, nous avons presente un additionneur n bits. Nous l’avons alors programmeavec les outils permettant de manipuler des tableaux dans Lustre-V4. Nous allons decrirea present le meme programme mais ecrit avec des iterateurs de tableaux (voir figure 3.9).

Nous avons besoin du meme noeud de base FULL ADD.

node FULL_ADD(ci,a,b : bool) returns (co,s : bool);let

s = a xor (b xor ci);co = (a and b) xor (b and ci) xor (a and ci);

tel

Page 39: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.1 : Syntaxe et Semantique 32

S

0

scal

B

ADD

ADD

ADDA

Fig. 3.9 – l’additionneur n bits programme avec les iterateurs de tableaux

Mais maintenant, nous pouvons utiliser un map red pour iterer le noeud FULL ADD surles tableaux A et B. On ecrit :

const n=10;

node ADD(A,B : bool^n) returns (S : bool^n; overflow : bool);let

overflow,S = map_red<<FULL_ADD,n>>(0,A,B);tel

On trouvera au chapitre 7, le code que l’on peut obtenir par compilation du programmeADD.

3.1.5.2 Reduction de plusieurs tableaux

Soit 2 tableaux B et C de n entiers. Soit A un tableau de booleen de taille n. On veutprogrammer le calcul de la valeur res definie par l’equation :

res =n∑

i=0

si A[i] alors B[i] sinon C[i]

Il nous faut ecrire un programme choix qui choisit un entier parmi deux selon unevaleur booleenne et qui ajoute l’entier ainsi choisi a un autre entier.

Page 40: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

33 3 : Iterateurs de tableaux

node choix (accu_in : int ; a : bool; b,c : int) returns (accu_out : int);let

accu_out = if a then accu_in + b else accu_in + c;tel

Si on itere ce noeud choix sur les tableaux A, B et C , on calcul la valeur res.Ce programme s’ecrit :

const n=10;

node Somme_Choix(A : bool^n ; B, C : int^n) returns (res : int);let

res = red<<choix,n>>(0,A,B,C);tel

3.2 Retour sur le rapport espace / temps

Revenons a present sur le rapport espace temps dont nous avons parle plus haut(2.2).Nous avions presente le programme qui calcul la somme de 4 entiers. Nous en avionsdonne 2 versions : une utilisait l’espace et economisait le temps alors que l’autre faisaitl’inverse.

Dans la premiere version, les 4 elements n’etait pas regroupe dans un tableau. C’etaittout a fait faisable, mais laborieux a programmer avec les tableaux a la V4. En effet, ilaurait fallu ecrire :

const taille=4;

node sumTab(X : int^taille) returns (sum : int);var S : int^(taille+1);let

sum = S[taille];S = [0] | (S[0..taille-1] + X);

tel

Grce aux iterateurs de tableaux proposes, le calcul se fait tres facilement a travers lenoeud suivant :

const taille=4;

node SumIt (Tab : int^taille) returns (res : int);letres = red<<+,taille>>(0,Tab);

tel

L’ecriture de SumIt est nettement plus intuitive que celle de SumTab. Les iterateursfacilite l’utilisation de l’espace et peuvent ainsi pousser le programmeur a economiser le

Page 41: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.3 : Extension 34

temps d’execution. Comme nous le verons plus loin, le code genere pour ce programmesera aussi nettement plus efficace que le code expanse produit a partir de SumTab, grce ala conservation des tableaux et a l’utilisation de boucles de parcours.

3.3 Extension

Les iterateurs tels qu’ils viennent d’etre presentes sont encore limites. Certains calculs,comme la transposition de matrice, sont en effet impossible a ecrire.

Il a paru essentiel de proposer quelques operateurs supplementaires pour accrotre lafacilite de programmation.

On introduit donc 2 nouveaux operateurs : le mirror et le transpose. Nous lespresentons maintenant succinctement. Leur compilation ne presentant pas de problemeparticulier nous n’y reviendrons pas par la suite.

3.3.1 l’operateur mirror

3.3.1.1 Tableaux a une dimension

Soit T un tableau (ou plus generalement une expression) de type τˆn. Alors, mirror(T)est une variable de type τˆn definit par :

∀ k ∈ [0, n− 1], mirror(T )[k] = T [n− k − 1].

Par exemple, si n = 5, τ = int et que T est le tableau suivant :18503

Alors, mirror(T) est le tableau :

30581

L’operateur mirror peut etre utilise :

forme 1 directement dans une equation : X = mirror(Y). (ou X et Y sont des tableaux dememe taille et de meme type d’elements)

forme 2 comme parametre d’une iteration : X = map<<+,n>>(mirror(Y),Z) ;

L’operateur mirror a ete implemente dans le prototype presente au chapitre 7. Sontraitement est simple. Dans sa forme 1, il suffit de generer une boucle, comme on le faitpour les 4 iterateurs. L’equation iteree est simple :

Page 42: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

35 3 : Iterateurs de tableaux

for(i=0;i<n;i++)X[i] = Y[n-i-1];

Dans sa forme 2 (comme parametre d’une iteration), il necessite le marquage du pa-rametre auquel il est applique. A chaque fois qu’on doit generer ce parametre, on le faiten utilisant l’indice inverse (dans l’exemple, on ecrit n-i-1 au lieu de i) :

for(i=0;i<n;i++)X[i] = Y[n-i-1] + Z[i];

3.3.1.2 Cas des tableaux a plusieurs dimensions

On peut evidement appliquer l’operateur mirror a des tableaux a plusieurs dimensions.Par exemple, si T est une expression de type τˆnˆm, alors mirror(T) est une expressionde type τˆnˆm, definie par :

∀k, l ∈ [0, n− 1]× [0,m− 1],mirror(T )[k, l] = T [k, m− l − 1].

L’operateur mirror n’agit, en definitive, que sur la derniere dimension du tableauauquel il est applique.

Par exemple si A est defini comme :3 4 20 5 05 2 48 7 21 4 3

alors mirror(A) est :

2 4 30 5 04 2 52 7 83 4 1

3.3.2 L’operateur transpose

3.3.2.1 Cas des tableaux a une dimension

Si T est une expression de type τˆn, alors la transposition de T, notee transpose(T)est du meme type que T est est definie par :

∀k ∈ [0, n− 1], transpose(T )[k] = T [k].

Page 43: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.3 : Extension 36

3.3.2.2 Cas des tableaux a plusieurs dimensions

Si T est de type τˆnˆm, alors transpose(T) est de type τˆmˆn et est definie par :

∀k, l ∈ [0, n− 1]× [0,m− 1], transpose(T )[k, l] = T [l, k]

Si A est la matrice definit ci-dessus, alors transpose(A) est : 3 0 5 8 14 5 2 7 42 0 4 2 3

Comme pour le mirror, on distingue 2 cas selon que transpose est utilise comme

expression dans une equation, ou parametre d’une iteration.Si transpose est utilise dans une equation de type :

M : int^10^15;MM : int^15^10;M = transpose(MM);

on genere le code suivant :

for(i=0;i<10;i++)for(j=0;j<15;j++)

M[i][j] = MM[j][i];

Si transpose est utilise dans une iteration, comme :

MMM : int^10^15;...M = map<<Plus,15>>(transpose(MM),MMM);

...node Plus(T1,T2 : int^10) returns (Sum : int^10);let

Sum = map<<+,10>>(T1,T2);tel

On doit generer le code :

Page 44: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

37 3 : Iterateurs de tableaux

for(i=0;i<15;i++)for(j=0;j<10;j++)

M[i][j] = MM[j][i] + MMM[i][j];

3.3.3 Le map partiel

On veut ecrire un noeud Lustre existe implementant l’operateur ∃. Soient les deuxentrees de ce noeud : T un tableau de n entiers et soit x un entier (on utilisera par exemplex= 3). Soit ex sa seule sortie definit par l’equation :

ex = (T[1] = x) or (T[2] = x) or ... (T[n] = x)

En utilisant un langage purement fonctionnel, on aurait :soit f la fonction qui teste si 2 entiers sont egaux :

f = λx. (λy. y=x)

f(3) est encore une fonction definie par :

f(3) = λy. y=3

f(3) permet de tester si son argument est egal a 3. (c’est le mecanisme d’applicationpartielle disponible dans les langages fonctionnels generaux).

On pourrait alors iterer f(3) sur T dans l’equation : ex = map(T,f(3)). ex est alorsvrai si et seulement si un il existe un element de T qui est egal a 3.

Mais cette application partiel d’une fonction n’est pas possible en Lustre. On estdonc oblige de choisir entre les deux solutions suivantes.

Utilisation de l’operateur mapIl nous faut, dans ce cas, un tableau dont tous les elements sont egaux a x.On ecrirait par exemple :

node f(x,y : int) returns (res : bool);let

res = x=y;tel

node existe (T : int^10, x : int) returns (ex : bool);var

tab x : int^10;let

tab x = fill<<id,10>>(x);

Page 45: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

3.3 : Extension 38

ex = map<<f,10>>(T,tab x);tel

ou l’equation tab x = fillid,10(x) permet de remplir le tableaux tab x avec xpour valeur de chacun de ses elements.

L’inconvenient de cette solution est qu’on utilise un tableau tab x d’autant d’elementsque T. Il faut alors de la memoire supplementaire et du temps suppelementaire pourremplir ce tableau avec l’operateur fill. Par contre, un tel programme, contrairement acelui presente ci-dessous, est assez intuitif et facile a ecrire.

Utilisation d’un redL’utilisation du red necessiterai une restrucutation du programme. Dans l’accumula-

teur, de la reduction, on a besoin de deux valeurs : celle de x (qui n’est jamais modifie)et celle de ex, qui evolue au cours du parcours de T. Ces valeurs sont representes dans lenoeud itere par les accumulateurs d’entree et de sortie :

– accu in.%0 (respectivement accu out.%0) correspondent a x.– accu in.%1 (respectivement accu out.%1) correspondent a l’evolution du booleenex au cours de l’iteration.

node f(accu in : int,bool; elt in : int) returns (accu out : int,bool);let

accu out.%0 = accu in.%0;accu out.%1 = (accu in.%0=elt in);

tel

node existe (T : int^10, x : int) returns (ex : bool);var

out : int;let

out,ex = red<<f,10>>(x,false,T);tel

Cette version est plus efficace aux points de vue memoire et temps d’execution, maiselle est plus difficile a ecrire.

L’iteration de fonction partielle est donc possible avec les iterateurs Lustre. Uneetude plus approfondie serait neanmoins necessaire afin d’evaluer les possibilites offertespar nos iterateurs quant a la facilite de programmation d’operations usuelles des langagesfonctionnels.

Page 46: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

39 3 : Iterateurs de tableaux

Page 47: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 4

Etude Bibliographique

Nous presentons dans ce chapitre les travaux qui nous ont paru les plus interessantsconcernant les 3 points suivants :

– La notion d’iterateurs dans les langages fonctionnels generaux ou plus specialises– Les optimisations possibles sur ces iterateurs. Nous nous sommes notamment penche

sur l’elimination des structures intermediaires lors d’enchanements d’iterations.– Les techniques de “retiming”, qui nous interessent pour l’extension des techniques

de compilation aux noeuds Lustre “a memoire”.

4.1 Sur la notion d’iterateurs

La notion meme d’iterateurs est tres etroitement liee a celle de fonctions d’ordresuperieur et plus generalement au style fonctionnel. Parmi les premieres apparitions de cesidees, on trouve les travaux de John Backus [Bac78]. Celui-ci donne deja des operateurspour manipuler des listes tels que les Insert ou Apply to all (correspondant respectivementa la reduction gauche et au mapping), et des idees sur la simplification des compositionsde telles fonctions.

Des les origines, le but annonce etait de fournir des outils puissants, permettantune reflexion “haut-niveau” plus mathematique que celle habituellement trouvee dansles methodes de programmation imperative.

Ces points representent exactement ce qui etait une des motivations pour l’introductiond’iterateurs en Lustre : proposer au programmeur des constructions simples, claires etpour lesquelles on sache produire un code efficace et sr.

Il est important de souligner que dans la majorite des travaux presentes ici, les objetsmanipules sont essentiellement des listes. D’autre part, dans les travaux ou l’on parleexplicitement de tableaux ([Bir88] par exemple), les operations fournies (notamment lespossibilites de construction de tableaux) sont beaucoup plus puissantes que les possibilitesde Lustre.

Il faut comparer les techniques presentees dans ces articles et nos propres propositionsen gardant toujours a l’esprit ces quelques remarques :

– nos tableaux sont toujours de taille fixe et connue statiquement. Ce n’est pas le caspour les listes qui peuvent etre infinies ;

– il ne nous est pas possible de construire des tableaux par concatenation ;

Page 48: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

41 4 : Etude Bibliographique

– en Lustre, aucune creation dynamique de tableau n’est possible.

Le formalisme de Bird-MeertensCe formalisme (note BMF) a ete introduit par Richard Bird dans [Bir88]. Le but est de

fournir une theorie mathematique complete pour l’utilisation de l’approche fonctionnelledans la specification des programmes. Cette theorie est basee sur des notations qui per-mettent de manipuler plus facilement des listes, des tableaux et des arbres. Des operationstelles que le ’mapping’, la reduction gauche et droite, les accumulations (qui correspondenta nos map red) sont definies.

Bird propose aussi differentes methodes de compilation pour BMF, notamment une quiconsiste a traduire ces programmes directement en code imperatif. La reduction gauchepeut traduite en une boucle for.

En ce qui nous concerne, BMF est une bonne base pour comprendre les mecanismesfonctionnels que nous manipulons. Les schemas de compilation vers des boucles de typefor que suggere Bird sont identiques a ceux que nous avons adoptes dans la generationde code C pour nos iterateurs (voir chapitre 2). Enfin, les regles d’optimisation que nousproposons au chapitre 5 sont comparables au regles de promotion de Bird.

Les operateurs proposes pour manipuler les tableaux sont cependant plus complets queceux que nous proposons pour Lustre. Cela vient principalement du fait que Bird travailavec une semantique purement fonctionnelle. La semantique de Lustre est plus reduite :on n’a pas de lambda explicite, ni d’evaluation partielle (voir notamment les problemespour les definition de maps partiels, en 3.3.3).

On retrouve aussi dans [Bir88] (ainsi que dans [JV99]) la notion de catamorphisme quicorrespond exactement a la reduction que nous proposons :

Definition 4.1 (Catamorphisme) 1 Une fonction sur des structures infinies est un ca-tamorphisme si elle peut etre calculee de haut en bas en remplaant les constructeurs parune fonction d’evaluation.

Par exemple, la somme des elements d’une liste d’entiers est un catamorphisme :on remplace les elements de la liste par leur valeur et les constructeurs de listes(concatenation) par le + (l’addition sur les entiers).

Mis a part le fait que l’on manipule, en Lustre, des tableaux de taille finie (et nonpas des listes infinies), l’operateur red Lustre est un catamorphisme.

De telles operations (map, reduce, . . .) ont ete inclus dans des langages plus specialisestels que 81/2[OM92], Alpha [AC97] ou ID[Nik91].

Les deux premiers implementent des approches flots de donnee, mais dans le but deresoudre des problemes d’architecture materielle (parallelisme de calcul). ID est un langagefonctionnel general.

Les methodes appliquees pour ces langages sont assez differentes de celle qu’on trouvepour Lustre : les notions de synchronisme et de reactivite en sont completement absentes.

1Cette definition est donnee par Eelco Visser, surhttp ://losser.st-lab.cs.uu.nl/~visser/cgi-bin/twiki/view/Transform/CataMorphism

Page 49: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

4.2 : Sur les optimisations des enchanements d’iterateurs 42

4.2 Sur les optimisations des enchanements d’iterateurs

Les optimisations que nous presentons au chapitre 5 sont issues du domaine de laprogrammation fonctionnelle. Les principales references portent sur la notion de listlessnesset de deforestation de Wadler[Wad88]2 et sur les travaux de Richard Waters.

4.2.1 Transformation automatique d’expressions “serielles” en boucles

Celui-ci souligne dans [Wat91] les avantages de la programmation a l’aide d’expressions“serielles”, et des techniques d’optimisations qui peuvent etre utilisees dans ce cadre. Lesobjets qu’il manipule sont a nouveau des listes, et la difference est assez importante car lescontraintes qu’apporte l’aspect “infini” des listes n’apparaissent pas pour nos tableaux.

Waters presente les avantages considerables qu’il y a a utiliser des fonctions d’ordresuperieur. Cette technique favorise un separation claire des calculs, de potentiellesverifications et modifications etant ainsi plus facile a effectuer sur le programme.

D’autre part, ces methodes ne sont pas beaucoup utilisees, et ce pour deux raisons :– les constructions proposees au programmeur ne sont pas faciles d’emploi– les methodes de compilation utilisees ne sont que tres rarement efficaces

D’apres Waters, la principale source d’inefficacite reside dans la creation de structureintermediaires lors d’enchanements de fonctions serielles, alors que cela pourrait etre evitedans de nombreux cas.

Il propose a la fois des schemas de compilation de ces iterations vers du code sequentielavec boucle et des optimisations qui visent a diminuer le nombre de ces listes in-termediaires. Ces optimisations sont assez similaires aux axiomes que nous proposonsau chapitre 5. Les schemas de compilation proposes sont a peu pres ceux que nous avonsadoptes.

4.2.2 Listlessness et deforestation

La deforestation a ete introduite en 1988 par Philip Wadler [Wad88]. L’auteur y decreteque les structures intermediaires sont le fardeau de la programmation fonctionnelle. Le butdu travail presente dans cet article est de fournir des techniques pour deforester les pro-grammes, c’est-a-dire supprimer les structures intermediaires lorsqu’elles sont inutiles.Wadler definit 2 formes de programme, dont la seconde, appelee tree-less form est uneforme dans laquelle on garantit l’absence de structures intermediaires inutiles dans les pro-grammes. Tout programme ecrit dans la premiere forme est traduisible en un programmede la seconde forme et toute composition de fonction “tree-less” peut etre traduite enune seule fonction “tree-less”. L’algorithme de deforestation donne est un parcours destructure qui isole les enchanements optimisables et applique les axiomes donnes.

La notion de deforestation est une version etendue de celle de listlessness ([Wad85,Wad84])puisqu’on ne considere plus simplement des listes intermediaires, mais tout typede structures (notamment les arbres abstraits dans un processus de compilation).

2une bonne introduction peut aussi etre trouvee dans [GLP93]

Page 50: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

43 4 : Etude Bibliographique

Une implementation des techniques de deforestation peut etre trouvee dans [GLP93].Une technique derivee, appelee warm fusion (presentee dans [LS95]) est implementee dansl’outil de transformation de programme Stratego ([JV99]) que nous avons utilise dansl’implementation de nos axiomes de transformation (voir chapitre 7).

Dans les travaux de Wadler, on traite n’importe quelle fonction recursive. Cettegeneralite pose certains problemes notamment quant a la preuve de terminaison des algo-rithmes de deforestation. Dans les travaux cites ci-dessus, l’etude est restreinte a l’etudedes catamorphismes

4.2.3 Lien avec les iterateurs Lustre

L’elimination des structures intermediaires est aussi un des objectifs du travail presenteici. En effet, comme nous le verrons plus loin (voir chapitre 5) , un iterateur donne lieu ala creation d’un ou plusieurs tableau(x). Mais peut-etre que ces tableaux ne servent qu’aetre consomme par un autre iterateur. Ces structures intermediaires ressemblent de presaux listes intermediaires de Wadler et pourraient etre elimines. Voyons comment on peutcomparer les 2 approches.

Au lieu de manipuler des listes, nous manipulons des tableaux. En quelque sorte, aulieu de travailler dans le temps, nous travaillons dans l’espace, puisqu’au lieu d’avoir aattendre les elements les uns apres les autres dans le temps, nous les avons tous en memetemps, mais “etales” dans l’espace sous forme de tableaux (rapport espace/temps, discuteen 2.2).

L’idee de Wadler etait de ne pas attendre qu’une liste soit produite completement pourcommencer a la consommer, mais de consommer ses elements au fur et a mesure qu’ilssont disponibles.

Pour nos iterateurs, s’il s’avere que le tableau produit par un map doit etre consommeimmediatement apres par un reduce, alors rien ne sert d’attendre qu’il soit produitcompletement. On peut consommer chaque element de ce tableau “intermediaire” avantque le suivant ne soit produit.

Plus besoin alors d’un tableau intermediaire. La composition des fonctions ’mappee’et ’reduite’ peut-etre directement iteree sur le tableau de depart.

L’economie en place memoire et en temps d’execution et alors significative.

De maniere generale, les travaux presentes ci-dessus nous ont servi de reference pourl’ecriture de nos axiomes d’optimisations d’enchanements d’iterateurs. Un algorithme aete ecrit pour appliquer ces axiomes (voir en 5.3), mais nous avons implemente ces optimi-sations dans le prototype grce au langage Stratego et aux outils proposes par Eelco Visser.L’interet de la methode appliquee dans Stratego est qu’elle est basee sur une semantiquede systemes de reecriture, qui est particulierement adaptee aux optimisations presenteesen 5.3.

Il faut aussi remarquer que les techniques proposees dans ces travaux visent a traiterdes programmes dans lesquels l’identification des enchanements est evidente. Nous ver-rons plus loin (en 5.3) que cette identification n’est pas si facile en Lustre puisque 2

Page 51: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

4.3 : Aspect temporels des iterations - Le retiming 44

iterations optimisables peuvent etre eloignees dans le programme source et qu’il faut alorsde developper une technique permettant de localiser les enchanements optimisables.

4.3 Aspect temporels des iterations - Le retiming

Nous avons etudie le retiming, qui est une technique definie par Leiserson et Saxe dans[LS86]. Ces travaux ont ete beaucoup utilises dans le domaine de la programmation deVLSI. Le retiming permet de modifier le nombre de “delais” (tampons qui permettent dememoriser des valeurs en vue d’utilisations ulterieures) a certains endroit dans un circuitsynchrone afin de minimiser le temps de parcours du chemin d’execution critique. On veutbien sr a conserver la semantique du programme considere.

Pour appliquer les algorithmes de retiming, on doit representer les circuits sous formede graphes synchrones.

4.3.1 Les Graphes Flots de Donnee synchrones

Un DFG synchrone G est un triplet < V, E, δ, ω > ou V est l’ensemble des sommetsde G (qui sont des sous-programmes), E est l’ensemble des arcs de G et δ est la fonctionqui associe a tout sommet v de V son delai de propagation δ(v) qui est egal au tempsnecessaire au sous-programme V pour fournir ses sorties, une fois qu’il a reu toutes sesentrees. G contient aussi un certain nombre de registres (sortes de tampons memoires : unregistre fournit en sortie la valeur precedente de son entree) repartis sur les arcs de G. Leregistre est l’equivalent de l’operateur pre de Lustre. En Lustre, chaque sommet v esttel que δ(v) = 0.

Soit par exemple un programme, appele correlateur, a 1 entree x, et la compare avec kconstante a0, a1, ... ak−1 Apres chaque nouvel xi (i ≥ k), le correlateur produit une sortiey qui est le nombre de correspondance definit par : :

yi =k∑

j=0

ρ(xj−i, aj)

ou ρ est la fonction de comparaison suivante :

ρ(x, y) =

1 : si x = y0 : sinon

La figure 4.1 montre le circuit correspondant et la figure 4.2 montre le DFG synchrone.On supposera, comme cela est fait dans [LS86] que le delai de propagation de chaque ρest de 3 unites de temps et que celui des + est de 7 unites de temps. k = 3.

Soit e un element de E (donc un arc du graphe G). On definit une valeur, notee ω(e)qui est le nombre de registres presents sur l’arc e.

On definit des chemins dans G, et on definit la fonction ω sur les chemins :

Page 52: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

45 4 : Etude Bibliographique

+ + +yi

xi

a0 a1 a2 a3

ρ ρ ρ ρ

Fig. 4.1 – Le circuit du correlateur

0

7 000 7

3

000

3 3 3 1111

7

0

Vh

V2V1 V3 V4

V5V7 V6

Fig. 4.2 – DFG synchrone

Definition 4.2 ω(p) est le nombre de registres sur le chemin p. Si p =v0

e0−→v1e1−→v2

e2−→ . . .ek−1−→vk alors :

ω(p) =k−1∑i=0

ω(ei)

De la meme faon, on peut definir le delai de propagation sur un chemin d’operateur.

Definition 4.3 δ(p) est le delai de propagation du chemin p. Si p =v0

e0−→v1e1−→v2

e2−→ . . .ek−1−→vk alors :

δ(p) =k∑

i=0

δ(vi)

Dans l’exemple du correlateur, on a : ω(V1, V4) = 3 et δ(V1, V4) = 12.

Le but des techniques proposees dans [LS86] est de minimiser le temps d’executiond’un parcours du graphe. La seule modification que l’on peut faire consiste a deplacer ousupprimer des registres. En effet, on ne peut pas modifier le temps de calcul d’un noeudsdu graphe. C’est ce qu’on appelle le retiming.

La periode d’un graphe donne est le delai de propagation maximum pour les cheminsde ce graphe qui ne contiennent aucun registre. C’est en quelque sorte la borne superieurdu temps d’execution optimal, en dessous de laquelle on ne pourra descendre, en modifiantla repartition des registres. La periode Φ(G) est definie par :

Φ(G) = maxδ(p) : ω(p) = 0

La periode du graphe de la figure 4.2, est : Φ(G) = 24.

Nous venons de definir les Graphes Flots de Donnes Synchrones (DFG) qui sont ma-nipules dans les differents travaux sur le retiming. Nous allons maintenant presenter leretiming lui-meme.

Page 53: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

4.3 : Aspect temporels des iterations - Le retiming 46

4.3.2 Retiming d’un DFG synchrone

Soit G un DFG. On cherche a optimiser le temps d’execution du systeme representepar G. Le retiming realise cette optimisation en rajoutant ou en enlevant des registres surcertains arcs de G.

On definit r la fonction de de retiming de V dans Z qui va nous permettre d’evaluer lesmodifications de placement des registres par rapport aux sommets du graphe. A chaquesommet v du graphe G, r fait correspondre le nombre de registre qu’on enleve de chaquearc entrant dans v et qu’on place sur chaque arc sortant de v. On note Gr le grapheequivalent a G obtenu par le retiming r.

Ainsi, si ωr est la fonction qui associe a chaque chemin du graphe le nombre de registrequ’il contient apres retiming, on a :

∀u p−→v, ωr(p) = ω(p) + r(v)− r(u).

ProprieteSi p est un cycle, on a evidement r(v) = r(u) (puisque u = v). et donc ωr(p) = ω(p).

L’algorithme de retiming donne dans [LS86] consiste, etant donne un DFG G, a mi-nimiser Φ(G). Pour cela, on va se donner 2 nouvelles fonctions Ω et ∆ qui vont nouspermettre d’evaluer Φ. Soient :

Ω(u, v) = minω(p) : up−→v

et

∆(u, v) = maxδ(p) : up−→v et ω(p) = Ω(u, v)

Ω represente le nombre minimum de registres sur les chemins reliant les sommets u etv. ∆ est le temps d’execution maximal non-optimisable, c’est -a-dire le temps necessairepour executer un parcours du chemin entre 2 sommes u et v tels que ω(u, v) = Ω(u, v).

On donne maintenant le theoreme sur l’existence d’un retiming d’un graphe G.

Theoreme 4.1 Soit G = < V, E, δ, ω > un DFG synchrone, soir c un nombre reel positifquelconque, et soir r une fonction de retiming, de V dans Z. Alors r est un retiming deG tel que Φ(Gr) ≤ c si et seulement si :

1. r(u) - r(v) ≤ ω(e) ∀u e−→v ∈ G

2. r(u) - r(v) ≤ Ω(u, v)− 1 ∀u, v ∈ V tels que ∆(u, v) > c.

La premiere condition stipule en fait que, par retiming, on ne doit pas augmenter lenombre de registre entre 2 sommets quelconques de G. La seconde condition signifie quel’on diminue forcement le temps minimum necessaire a relier 2 sommets du graphe G, enutilisant n’importe quel chemin les reliant. Les inequations de ce theoreme peuvent etreresolues grce a l’algorithme de Bellman-Ford (voir [Law76]).

Page 54: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

47 4 : Etude Bibliographique

L’algorithme presente dans [LS86] se base sur le theoreme ci-dessus. Il permet dedonner la fonction r pour un circuit G donne de faon a ce que la periode du graphe obtenupar r soit minimale.

Algorithme 4.1 (Minimisation de la periode d’un DFG synchrone) Soit unDFG synchrone G =< V, E, δ, ω >, cet algorithme determine un retiming r tel que Φ(Gr)est aussi petite que possible.

1. calculer Ω et ∆

2. trier les couples < u, v >de sommets du graphe selon ∆

3. Rechercher la periode minimale atteignable parmi les ∆(u, v). Pour tester si uneperiode c est atteignable, appliquer l’algorithme de Bellman-Ford pour verifier si lesconditions dans le theoreme 4.1 sont verifiees

4. pour la periode minimale atteignable trouvee en etape 3, le retiming optimal est lavaleur minimale trouvee par l’algorithme de Bellman-Ford

A partir de l’exemple de la figure 4.2, on obtiendrait le DFG synchrone de la figure4.3.

0

7 110 7

3

001

3 3 3 1010

7

0

r(V4) = −2

r(Vh) = 0

r(V3) = −2

r(V5) = −2r(V6) = −1

r(V2) = −1r(V1) = −1

r(V7) = 0

Fig. 4.3 – graphe retime du programme

4.3.3 Liens avec les iterateurs Lustre

Comme il a ete explique plus haut, on peut considerer les programmes Lustre commedes reseaux d’operateurs, des DFG synchrones, ou les registres sont les occurrences del’operateur pre. L’application du retiming a Lustre revient a appliquer les equivalencessur les pre : pre(a+b) est equivalent a pre(a) + pre(b). Dans le premier cas, on n’a amemoriser qu’une seule valeur, celle de a+b, au lieu de memoriser les valeurs pour a etpour b.

Dans les cas d’iterations de noeuds a memoires comme nous le verrons au chapitre 6,on devrait pouvoir “sortir” les occurrences de pre en dehors des noeuds iteres (donc auniveau des programmes iterants). On appliquerait alors les techniques qu’on a developpepour les cas d’iterateurs de noeuds sans memoires.

videmment, le but n’est pas d’optimiser le temps d’execution de parcours du graphed’un programme Lustre, mais de pouvoir faire sortir les occurrence de pre d’une certainepartie de ce graphe, pour rendre la compilation plus facile et efficace.

Page 55: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

4.3 : Aspect temporels des iterations - Le retiming 48

Nous verrons, au chapitre 6, qu’en fait le retiming est en general trop coteux pourl’appliquer a la compilation des iterateurs Lustre a memoire.

Page 56: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

49 4 : Etude Bibliographique

Page 57: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 5

Principes de compilation etoptimisations

Nous presentons dans ce chapitre la premiere partie du travail qui a ete effectue durantce projet. Elle concerne l’etude de la compilation des iterateurs de noeuds non temporels(c’est-a-dire ne contenant aucun appel aux operateurs tels que pre), ainsi que les optimi-sations qui y sont liees.

Nous donnons dans un premier temps le schema de compilation general, utilise dansle prototype defini au chapitre 7. Ensuite, nous verrons le cas interessant de l’imbricationd’iterations. Enfin, nous nous interessons a l’optimisation des enchanements d’iterateurs

5.1 Schema general de generation de code

L’objectif est donc de proposer un schema de compilation pour traduire des pro-grammes Lustre avec iterateurs en du code C avec boucle et tableaux. Nous ne noussommes pas interesse a des problemes de verification statique habituellement necessaires(voir 2.1.3.1). Nous supposons donc que le programme Lustre a compiler est syntaxique-ment correct et qu’il ne contient pas d’expressions semantiquement incorrectes du pointde vue de la manipulation des types. Nous supposons aussi que les appels de noeuds sontexpanses, ce qui est effectivement le cas en pratique, un algorithme etant applique enamont de la generation de code pour traiter ce probleme. Lors de la generation de code,on ne parcourt qu’un seul noeud (le noeud principal). Les seuls autres noeuds que nousinspectons sont les noeuds iteres dans le noeud principal.

La boucle de reactivite habituellement necessaire a l’execution du programme n’est pasproduite. Nous avons choisi ce processus de compilation simplifie pour etudier directementles problemes de generations de code avec boucles et tableaux.

Ce schema de compilation a ete implemente dans le prototype Lac presente au chapitre7.

Soit le programme ADD, vu aux chapitres precedents (voir figure 5.1). Nous nousservirons de cet exemple pour illustrer les mecanismes de generation de code.

Page 58: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

51 5 : Principes de compilation et optimisations

node FULL_ADD(ci,a,b : bool) returns (co,s : bool);let

co = (a and b) or (b and ci) or (a and ci);s = a xor (b xor ci);

tel

const n=10;

node ADD(A,B : bool^n) returns (S : bool^n; overflow : bool);let

overflow,S = map_red<<ADD,n>>(0,A,B);tel

Fig. 5.1 – Additionneur n bits avec iterateurs

5.1.1 Representation des programmes

Les noeuds d’un programme Lustre sont representes sous forme d’arbres abstraits(de type AA Noeud). Ils sont reunis dans une liste indicee notee ListeNoeuds. Parmi cesnoeuds, on identifie le noeud principal, note NPrincipal, son arbre abstrait etant noteANPrincipal.

Chaque arbre A a pour racine le nom du noeud, note A.nom et pour branches :– La liste des entrees du noeud, notee A.Entrees– La liste des sorties du noeud, notee A.Sorties– La liste des variables locales du noeud, notee A.Vars Locales– La liste des equations du noeud, notee A.ListeEquations

Toutes les listes manipulees sont indicees.Les listes A.Entrees, A.Sorties, A.Locales sont des listes de couples <nom,type>.

Ces trois listes seront aussi regroupees sous le nom A.Parametres Formels, pour les dis-tinguer des parametres effectifs lors des iterations de noeuds. La liste A.ListeEquationsest une liste de couples <variable, expression>. Si Eq est une equation, on noteEq.variable et Eq.expression ses composantes. Eq.variable peut aussi etre une listede variables.

Representation des expressionsUne expression E peut etre de differents types :

type 1 Une simple variable, E.nom designe son nom.

type 2 Une operation arithmetique ou booleenne, potentiellement parenthesee. On definitalors E par E.Operande1, E.Operateur et E.Operande2 s’il s’agit d’une operationbinaire et par E.Operateur et E.Operande s’il s’agit d’une operation unaire, ouE.Operande1, E.Operande2 et Operande sont a leur tour des expressions de type 1ou de type 2.

type 3 Une liste d’expressions. On peut, en Lustre definir plusieurs variables avec une seuleequation. crire a,b = (a’+1, b’+1) ; equivaut a ecrire a = a’+1 et b = b’+1. Leselements de la liste d’expressions peuvent etre de n’importe quel type (1 a 5). On

Page 59: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.1 : Schema general de generation de code 52

identifie par E.ListEx, la liste des expressions. E.taille est le nombre d’expressionsdans la liste.

type 4 Une expression conditionnelle. E est decrite par E.Condition, E.Alors, E.Sinon quisont forcement des expressions (E.Condition etant une expression booleenne).

type 5 Une iteration, qui est alors accompagnee de toutes les informations utiles (voir ci-dessous).

Representation des iterationsSoit E une expression de type 5 (iteration). Quel que soit le genre d’iteration, E com-

prend toujours : E.nom (le nom du noeud itere), E.taille (la taille de l’iteration, qui estun entier). Dans les cas du map, du red et du map red, on donne aussi les parametres“tableaux” de l’iteration. Il s’agit d’une liste de noms, notee E.Parametres. Dans les casdu fill, du red et du map red, on trouve aussi la valeur d’initialisation de l’iteration,notee E.init.

A titre d’exemple, on trouvera a la figure 5.2 l’arbre abstrait du programme ADD.

A.nom = "ADD"A.Entrees = [<A,bool^10>,<B,bool^10>]A.Sorties = [<S,bool^10>,<overflow,bool>]A.Variables Locales = ∅A.ListeEquations = [<[overflow,S],E>]

avecE.type = map redE.nom = FULL ADDE.taille = 10E.init = 0E.Parametres = [A,B]

Fig. 5.2 – Arbre abstrait du noeud ADD

Nous donnons ci-dessous l’algorithme general de parcours de l’arbre du noeud principal(ANPrincipal) pour generer le code C correspondant.

5.1.2 Algorithme de generation de code

5.1.2.1 Generation de l’en-tete de la fonction principale

Le but est de generer une fonction qui regroupe les actions correspondant a un coupd’horloge du programme synchrone (calcul des sorties, pour l’instant).

Cette fonction porte le nom du noeud principal et a pour parametres ses entrees-sorties.On y definit aussi les variables locales du noeud.

Ensuite, on parcourt ANP.ListeEquations et on genere le code correspondant a chaqueequation.

Page 60: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

53 5 : Principes de compilation et optimisations

Generer Code, decrite a la figure 5.3, est la fonction principale du generateur de codequi implemente ces actions.

Generer Code(ANPrincipal : AA_Noeud)Ecrire("void ", ANPrincipal.name, "(");Generer Declarations(ANPrincipal.Entrees);Generer Declarations(ANPrincipal.Sorties);Ecrire(")");Generer Declarations(ANPrincipal.Variables_Locales);Pour chaque E dans ANPrincipal.ListeEquations faire

Generer Equation(ANPrincipal.Parametes Formels,ANPrincipal.Parametres Formels,E,0); //niveau d’imbrication

Ecrire("");

Fig. 5.3 – Fonction principale du generateur de code

5.1.2.2 Generation des equations

La fonction Generer Equation genere le code correspondant a une equation E en fonc-tion des parametres effectifs qui sont appliques au noeud courant (cela a de l’importancepour les iterations). Afin de pouvoir generer le bon indice des tableaux lorsqu’on genere lecode d’un iterateur, on utilise un parametres entier note niveau. Celui-ci vaut 0 tant quel’on genere du code du noeud principal. Il vaut 1 a chaque fois que l’on genere du codeitere. Dans le cas d’iterations imbriquees (voir 5.2), niveau vaut le nombre d’imbricationa l’interieur desquelles on se trouve.

Exemple Au moment de la generation du code pour l’equation s = a xor (b xor ci),niveau vaut 1. Pour chaque occurence de s, comme S est un tableau, on ecrit a chaquefois : S[i0].

La fonction Generer Equation est decrite a la figure 5.4. Les differents cas decritscorrespondent aux differents types d’expressions decrits plus haut.

Page 61: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.1 : Schema general de generation de code 54

Generer Equation(For : Parametres,Eff : Parametres,E : Equation,niveau : entier)

switch(E.expression.type)case (1 or 2) :

Generer SimpleEquation(For,EffE,niveau);

case 3 :Pour i entre 0 et E.expression.taille faire

Generer Equation(For,Eff,<E.var[i],E.expression.ListEx[i]>,niveau);

case 4 :

Generer Equation Conditionnelle(For,Eff,E,niveau);

case 5 :Generer Iteration(For,

Eff,E,niveau+1);

Fig. 5.4 – Generation du code pour une equation

Page 62: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

55 5 : Principes de compilation et optimisations

5.1.2.3 Cas d’une equation simple (type 1 ou 2)

On appelle “equation simple” une equation dont l’expression est de type 1 ou de type2. Pour generer une telle equation, on utilise la fonction Generer SimpleEquation qui estdonnee a la figure 5.5 ou on utilise la fonction Generer Expression definie a la figure 5.6.

Generer SimpleEquation(For : Parametres,Eff : Parametres,E : Equation,niveau : entier)

variable effective = Correspondance(E.variable, Eff);Ecrire(variable effective);Pour k de 0 a niveau Ecrire("[i",k,"]");Ecrire("=");Generer_Expression(For, Eff, E.expression, niveau);

Fig. 5.5 – Generation d’une equation du type 1 ou 2

Generer Expression(For : Parametres,Eff : Parametres,E : Expression,niveau : entier)

switch(E.type)case 1 : variable effective = Correspondance(E.nom, Eff);

Ecrire(variable effective);for(k de 0 a niveau) Ecrire ("[i",k,"]");

case 2 : si Est unaire(E)alors Ecrire(Operateur);

Generer Expression(For, Eff, E.Operande, niveau);sinon Generer Expression(For, Eff, E.Operande1, niveau);

Ecrire(Operateur)Generer Expression(For, Eff, E.Operande2, niveau);

Fig. 5.6 – Generation d’une expression simple (type 1 ou 2)

Notons que l’on genere les indices correspondant au niveau d’imbrication ou l’on setrouve.

La correspondance etablie entre la variable rencontree dans une expression ou en partiegauche d’une equation et le parametre effectif associee est utile lors de la generation ducode d’un noeud itere. Par exemple, lors du traitement du programme ADD, on a a genererle code correspondant a l’equation s = a xor (b xor ci) ;. On va retrouver la variablea generer effectivement. Par exemple, pour l’occurrence de s, il faut generer la variable S.

Page 63: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.1 : Schema general de generation de code 56

La fonction Correspondance sert donc a etablir ces liens entre variables formelles (commes, ici) et parametre effectif (ici S).

5.1.2.4 Cas d’une equation conditionnelle (type 4)

Un equation conditionnelle Lustre est de la forme : var = if ex bool then ex1else ex2. Or, le code sequentiel correspondant est de la forme : if ex bool then var =ex1 else var = ex2. En C, on ecrit exactement if(ex bool)var = ex1elsevar =ex2. Il faut donc generer a partir d’une equation dans l’arbre abstrait, 2 equations. Lafonction Generer Equation Conditionnelle donnee a la figure 5.7 implemente cette idee.

On commence donc par stocker ces 2 equations dans E Alors et E Sinon. Puis, ongenere la condition et enfin, on rappelle la fonction Generer SimpleEquation sur E Alorset E Sinon. En effet, on ne peut trouver que des expressions de type 1 ou 2.

Generer Equation Conditionnelle(For : Parametes,Eff : Parametres,E : Equation,niveau : entier)

E Alors : Equation;E Sinon : Equation;E Alors.variable = E.variable;E Alors.expresion = E.expression.Alors;E Sinon.variable = E.variable;E Sinon.expresion = E.expression.Sinon;Ecrire("if(");Generer Expression(For, Eff, E.Condition, niveau);Ecrire(")");Generer Equation(For, Eff, E Alors, niveau);Ecrire("else");Generer Equation(For, Eff, E Sinon, niveau);Ecrire("");

Fig. 5.7 – Generation de code pour une equation conditionnelle

5.1.2.5 Generation des equations d’un noeud itere (equation de type 5)

La generation des equations du noeud itere se deroule de la maniere suivante. On com-mence par generer des declarations pour les variables locales du noeud itere. Si necessaire(dans tous les cas sauf celui du map), on genere une initialisation de la variable d’accumu-lation. On genere ensuite l’en-tete de la boucle de parcours et enfin chaque equation enprenant garde de remplacer chaque occurrence d’une variable par le parametre effectif cor-respondant (voir 5.1.2.3). Il faut faire attention a l’utilisation de niveau : on doit genererpour chaque niveau d’imbrication un nouvel indice.Celui-ci est fabrique en accolant a lalettre i, le niveau d’imbrication courant.

l’algorithme de generation du code pour une iteration est donne a la figure 5.8.

Page 64: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

57 5 : Principes de compilation et optimisations

Generer Iteration(For : Parametes,Eff : Parametres,E : Equation,niveau : entier)

Noeud Itere : AA Noeud;AA Noeud = Charger Noeud(E.nom, ListNoeuds);

Ecrire("");

//Generation des variables locales du noeud itereGenerer Declaration Variables(AA Noeud.Variables Locales);

// Si Red, Fill, ou Map Red, generation de l’initialisation de l’accu.si(E.expression.type=(map red or red or fill))alors Generer Equation Initialisation(E.expression.init, niveau);

//Generation de l’entete de la boucleEcrire("for(i",niveau,=0",";i",niveau,"=",E.expression.taille,";i0++)")

//Generation de l’interieur de la bouclePour chaque equation Eq dans Noeud Itere faire

Generer Equation(Noeud Itere.Parametes Formels,E.Parametres,Eq,niveau);

Ecrire("");

Ecrire("");

Fig. 5.8 – Generation du code correspondant a une iteration

Page 65: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.2 : Imbrications d’iterateurs 58

ResultatPour le noeud ADD, on obtient le programme suivant :

typedef int Boolean;typedef int Integer;

void _ADD(Boolean _A[10],Boolean _B[10],Boolean *_S[10],Boolean *_overflow)

Integer i0;Boolean mem_overflow;*_overflow = 0;for(i0=0;i0<10;i0++)mem_overflow = *_overflow;

*_S[i0] = _A[i0] ^ (_B[i0] || mem_overflow);*_overflow = (_A[i0] && _B[i0])

^ (_B[i0] && mem_overflow)^ (_A[i0] && mem_overflow);

5.2 Imbrications d’iterateurs

Les iterateurs Lustre, permettent de travailler facilement avec des tableaux a plusieursdimensions. Nous allons voir un exemple d’un tel calcul, puis nous verrons le code que l’onpeut produire pour ce programme grce a l’algorithme de generation de code que nousvenons de presenter.

Le code obtenu est constitue d’imbrications de boucle de type for et manipule destableaux a plusieurs dimensions.

Multiplier tous les elements d’une matrice a 3 dimensions par un entier i

On commence par implementer le noeud qui multiplie par m son entree (on fixe icii=2).

const i = 2;

node Mult(a : int) returns (b : int);let

b = a * i;tel

Page 66: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

59 5 : Principes de compilation et optimisations

Ensuite, on itere ce noeud (voir figure 5.9) sur un vecteur d’une taille quelconque(disons n, qui sera un parametre generique du noeud Mult UneDim). Ainsi, le tableau B estdefinit par l’equation :

∀i ∈ [0..n], B[i] = A[i] ∗ 2

node Mult_UneDim<<n : int>>(A : int^n) returns (B : int^n);let

B = map<<Mult,n>>(A);tel

BA

Mult

Fig. 5.9 – Le noeud Mult UneDim

Incrementalement, on construit le programme Mult DeuxDim (voir figure 5.10), quieffectue la meme operation, mais sur des tableaux a 2 dimensions (n et l) :

node Mult_DeuxDim<<m,n : int>>(AA : int^m^n) returns (BB : int^m^n);let

BB = map<<Mult_UneDim,n>>(AA);tel

Et, enfin (figure 5.9), le programme qui effectue le calcul sur des matrices a 3 dimensionsest le noeud Mult TroisDim :

Page 67: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.2 : Imbrications d’iterateurs 60

Mult UneDim

BBAA

Fig. 5.10 – Le noeud Mult DeuxDim

node Mult_TroisDim<<m,n,l : int>>(AAA : int^m^n^l returns (BB : int^m^n^l);let

BBB = map<<Mult_DeuxDim,l>>(AAA);tel

AAA BBBMult DeuxDim

Fig. 5.11 – Le noeud Mult TroisDim

On instancie le noeud Mult TroisDim en ecrivant un noeud main (par exemple) :

node main(Tab_in : int^10^10^10) returns (Tab_out : int^10^10^10);let

Tab_out = Mult_Trois<<10,10,10>>(Tab_in);tel

Page 68: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

61 5 : Principes de compilation et optimisations

Code obtenu pour le programme mainL’algorithme presente plus haut, permet de traiter des tableaux et iterations a plusieurs

dimensions. En effet, lorsqu’on genere le code d’une iteration, si une equation du noeuditere est une iteration, alors, l’appel a la fonction Generer Equation execute un nouvelappel a la fonction Generer Iteration en incrementant le niveau d’imbrication. Onobtient le code suivant pour le programme main.

void main(int Tab_in[10][10][10], int *Tab_out[10][10][10])

int i0;for(i0=0;i<10;i0++)

int i1;for(i1=0;i1<10;i1++)

int i2;for(i2=0;i2<10;i2++)

Tab_out[i0][i1][i2] = Tab_in[i0][i1][i2] * 2;

5.3 Enchanements d’iterateurs

La principale optimisation que l’on peut envisager est celle liee a l’enchanementsd’iterations au sein d’un noeud.

5.3.1 Problematique

Commenons par un exemple.Soit le programme Lustre defini a la figure 5.12.

En d’autre terme, T’ est definit par :

∀i ∈ [0..n], T ′[i] = f(T [i]), (5.1)

et T’’ par :

∀i ∈ [0..n], T′′[i] = g(T′[i]). (5.2)

D’apres 5.1 et 5.2, on a :

∀i ∈ [0..n], T′′[i] = g(f(T[i])). (5.3)

Page 69: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 62

node main(T : int^10) returns (T’’ : int);var T’ : int^10;letT’ = map<<f,n>>(T);T’’ = map<<g,n>>(T’);

tel

node f(in_f : int) returns (out_f : int);letout_f = in_f + 1;

tel

node g(in_g : int) returns (out_g : int);letout_g = in_g + 2;

tel

Fig. 5.12 – Un exemple d’enchanement d’iteration

Il faut remarquer aussi que dans le programme decrit ci-dessus, la seule utilite dutableau T’ est de rendre le programme plus clair. T’ n’est en effet pas une sortie duprogramme et n’est utilisee nulle part ailleurs dans le noeud main.

On peut alors concevoir de remplacer ce programme par le programme de la figure5.13, semantiquement equivalent.

node main(T : int^10)returns(T’’ : int);let

T’’ = map<<a_0,n>>(T );tel

node h(in_f : int)returns(out_g : int);var

in_g : int ;out_f : int ;

letout_f = in_f + 1;in_g = (out_f);out_g = in_g + 2;

tel

Fig. 5.13 – Version optimisee du programme main

ou h est un nouveau noeud, inexistant auparavant, correspondant a la composition desnoeuds f et g.

Page 70: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

63 5 : Principes de compilation et optimisations

5.3.2 Condition d’applicabilite

Il faut bien noter que le tableau T ′ doit etre inutile pour le reste du programme.On ne pourrait pas supprimer des variables qui serait des sorties d’un programme ni quipermettrai de calculer directement ou indirectement des sorties. On peut facilement definircette notion d’inutilite :

Definition 5.1 (Variable inutile vis-a-vis de l’enchanement des iterateurs) Ondit qu’une variable V est inutile dans un noeud Lustre, vis-a-vis de l’enchanement desiterateurs, si toutes les conditions suivantes sont verifiees :

– V est locale au noeud considere– V n’apparat que dans 2 equations :

– dans la premiere comme resultat d’une iteration– dans la seconde comme parametre d’une autre iteration

– Ces 2 iterations sont optimisables par les axiomes introduits dans ce chapitre.

Une autre condition pour que de telles optimisations soient applicables est que les 2iterations concernees soient evidement de meme taille.

5.3.3 Avantages et inconvenients

Cette optimisation represente, comme nous l’avons dit plus haut, deux avantages :– On economise la place memoire normalement allouee a la variable T’– On produit un code plus rapide puisque ne contenant qu’un seule boucle for, cor-

respondant a l’unique map du programme obtenu.Les figures 5.14 et 5.15 montrent les 2 codes produit pour le programme main ci-dessus :

avec ou sans optimisation.

L’implementation des iterateurs dans les produits finaux (comme l’atelier Scade) sefera vraisemblablement sout la forme de bibliotheques. Ces bibliotheques contiendront desprogrammes generiques implantant des algorithmes classiques sur les tableaux (commeles calculs de maximum, minimum, tris, etc.). L’utilisateur final n’aura generalement pasa se poser des questions d’optimisation : il manipulera les programmes fournies, en lesarrageant pour programmer ses propres algorithmes.

C’est cette methode d’utilisation qui nous permet d’affirmer que ces optimisations se-ront utiles. L’utilisateur creera sans meme sans rendre compte, en utilisant les programmesfournie dans la bibliotheque, des enchanements potentiellement abondants d’iterations.

Le compilateur Lustre prendra lui-meme en charge, sans en aviser le programmeur,ces optimisations.

5.3.3.1 Lien avec la fusion de boucle

La fusion de boucle (en anglais “loop fusion”) est une technique introduite dans[Muc97] qui consiste a fusionner des boucles de type for qui se suivent dans un programmesequentiel. Les indices de ces boucles doivent evidement parcourir les memes ensemblesde valeurs. C’est une technique que l’on aurait pu utiliser pour trater les enchanements

Page 71: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 64

typedef int Boolean;typedef int Integer;

void _main(Integer _T[10],Integer *_T’’[10])

Integer _T’[10];

Integer i0;for(i0=0;i0<n;i0++)_T’[i0]=_T[i0] + 1;

Integer i0;for(i0=0;i0<n;i0++)*_T’’[i0]=T’[i0] + 2;

Fig. 5.14 – Code produit pour l’enchane-ment de 2 maps sans optimisation des en-chanements

typedef int Boolean;typedef int Integer;

void _main(Integer _T[10],Integer *_T’’[10])

Integer i0;Integer _ing;Integer _outf;for(i0=0;i0<n;i0++)_outf=_T[i0] + 1;_ing=_outf;*_T’’[i0]=_ing + 2;

Fig. 5.15 – Code produit pour l’enchane-ment de 2 maps avec optimisation des en-chanements

d’iterateurs. On aurait alors optimise le code C genere et non pas le programme Lustrelui-meme. Pour le programme main ci-dessus, on obtiendrait le meme resultat.

L’incovenient de l’application d’un telle technique pour Lustre est qu’il se peut que 2iterations optimisables ne soient pas directement l’une apres l’autre dans le code Lustre.Elles ne le seront pas non-plus forcement dans le code sequentiel produit et l’optimisationn’aura pas lieu. En manipulant directement les equations Lustre, dont l’ordre dans leprogramme n’a pas d’importance, on va pouvoir rapprocher des iterations potentiellementoptimisables.

5.3.3.2 Perte de traabilite

La mise en place de l’optimisation des enchanements d’iterateurs entrane une perte detraabilite du programme. En effet, on supprime des variables et on modifie la structurationfine du programme. Dans sa globalite, il garde la meme semantique, mais la methodeprogrammee par l’utilisateur n’est plus apparent. Cela peut avoir une incidence importantesur la correction des programmes (verification, debogage).

Pour cette raison, ces optimisations ne doivent pas etre implementee dans les outils decorrection de programme (interpretes, logiciels de test et debogeur1).

1Un debogeur pour Lustre (LuDiC) est actuellement developpe a Verimag par F. Gaucher. Cet outildevrait rapidement prendre en compte les iterateurs de tableaux.

Page 72: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

65 5 : Principes de compilation et optimisations

5.3.4 Axiomatisation

Nous allons maintenant presenter les differents cas d’optimisations d’enchanements.Le tableau suivant les rassemble les cas possibles et chacun d’eux est developpe en detaildans les paragraphes suivants.

map fill red map-redmap ? ? ?

fill ? ? ?

redmap-red ? ? ?

La premiere case de la deuxieme ligne du tableau se lit comme suit : ”l’enchanementmap(fill) est optimisable par les axiomes decrit ici”.

Page 73: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 66

5.3.4.1 map suivi de map

Soient 2 fonctions f = λt.t′ et g = λt.t′′. t′ et t′′ representent en fait des expressionsqui dependent de t.

L’enchanement (voir figure 5.16) des map de ces 2 fonctions est tout a fait habituel, etcorrespondant a l’exemple que nous avons presente en introduction de ce chapitre.

On a :

map(map(T, f), g)≡

map(T, λt. let x = f(t) in g(x)).

T T”

g ff g

T T’ T”

⇐⇒

Fig. 5.16 – map(map)

Page 74: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

67 5 : Principes de compilation et optimisations

5.3.4.2 map suivi de red

Supposons que l’on veuille mapper une fonction f = λt.t′ sur un tableau T. Le resultatobtenu (voir figure 5.17) est alors reduit par le noeud g = λa,< t.a′ > grce a l’operateurred. Cet enchanement est optimisable vers une unique reduction, et ce grce a l’equivalencesuivante :

red(i,map(T, f), g)≡

red(i, T, λa, t . let x = f(t) in g(a, x)).

rT

ig i

rT’T

f

⇐⇒

Fig. 5.17 – red(map)

Page 75: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 68

5.3.4.3 map suivi de map red

Si la fonction iteree par le map est f = λt.t′ et celle iteree par le map red est g =λa, t. < a′, t′′ >, alors, on peut appliquer l’axiome suivant :

map red(i,map(T, f), g)≡

map red(i, T, λa, t . let x = f(t) in g(a, x)).

gf

r

i

T’T T”

⇐⇒

i

T T”r

Fig. 5.18 – mapred(map)

Page 76: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

69 5 : Principes de compilation et optimisations

5.3.4.4 fill suivi de map

Soit f = λa.a′ la fonction utilise dans le map et soit g = λa. < a′, t > la fonction deremplissage.

L’enchanement fill(map) peut etre optimise en le remplaant par un remplissage al’aide d’un noeud, combinaison de f et de g(voir figure 5.19).

map(fill(i, T, g), f)≡

fill(i, T, λa . let < x, y > = g(a) in let z = f(y) in< x, z >).

i

T’

⇐⇒

g

i

T’T

f

Fig. 5.19 – map(fill)

Page 77: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 70

5.3.4.5 fill suivi de red

ExempleSoit le programme Lustre suivant :

node main(i : int) returns (r : int);var T : int^10;let

T = fill<<f,n>>(i);r = red<<g,n>>(T);

tel

node f(Accu_in_f : int) returns (Accu_out_f : int ; Elt_out_f : int);let

...tel

node g(Accu_in_g : int ; Elt_in_g : int) returns (Accu_out_g : int);let

...tel

Cet enchanement n’est pas optimisable en une autre forme itere (avec tableau). Mais onretrouve la notion de producteur / consommateur : l’algorithme de remplissage (representepar l’iterateur fill) produit des elements dans le tableau T ; l’algorithme de reduction(l’iterateur red) consomme ces elements.

Dans le programme ci-dessus, on remplit d’abord T pour ensuite le parcourir a nouveau.On s’aperoit alors que le tableau T est inutile (on sens de la definition 5.1). Ene ffet, sil’on se refere au schema 5.20, on voit bien que que le calcul de r pourrait se faire sansmemoriser tous les elements de T.

Soit le code produit pour l’equation T = fillf,n(i) ; :

s = i;for(i0=0;i0<n;i0++)x,y = f(s);T[i0] = y;s = x;

Et soit le code produit pour l’equation r = red<<g,n>>(T) :

r = j;for(i0=0;i0<n;i0++)r = g(r,T[i0]);

On peut remplacer le code obtenu precedemment par le code ci-dessous (equivalent),obtenu par des techniques de fusion de boucle (voir [Muc97]).

Page 78: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

71 5 : Principes de compilation et optimisations

r = j;s = i;for(i0=0;i0<n;i0++)x,y = f(s);r = g(r,y);s = x;

Il faut bien noter que l’on ne peut pas optimiser le code lustre, et que cette optimisationdoit donc se faire directement lors de la generation de code.

i j

T r

gf

Fig. 5.20 – Le cas tres particulier de l’enchanement red(fill)

Page 79: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 72

5.3.4.6 fill suivi de map red

Soit f = λa.(a′, t) la fonction utilisee dans le fill et soit g = λa, t.(a′, t′) la fonctionutilisee dans le map red. Alors on a (voir figure 5.21) :

map red(i1, fill(i2, f), g)≡

fill(i1, i2, λa1, a2 . let < x, y >= f(a1) in let< x′, y′ > = g(a2, y) in < x, x′, y′ >)

i

fg

j

TrT’

rT’

⇐⇒

j

Fig. 5.21 – map red(fill)

Page 80: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

73 5 : Principes de compilation et optimisations

5.3.4.7 map red suivi de map

Soit f = λ(a, t).(a′, t′) la fonction utilise dans le premier map red et soit g =λ(a, t).(a′, t′) la fonction de remplissage. On a (voir figure 5.22) :

map(map red(i, T, f), g)≡

map red(i, T, λ a, t . let < x, y > = f(a, t) in< x, g(y) >).

f g

rT T’ T”

i

rT

i

T”

⇐⇒

Fig. 5.22 – map(map red)

Page 81: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 74

5.3.4.8 map red suivi de red

Soient f = λa, t.a′, t′ le noeud itere par map red et g = λa, t.a′ le noeud itere par red.Une condition necessaire pour que cet enchanement soit optimise est :

Condition Necessaire 5.1 Si r1 est le resultat du map red, et si i2 est la valeur d’ini-tialisation du red, alors il faut que i2 ne dependent pas de r1.

En effet, dans le cas ou i2 depend de r1, il faut appliquer le map red de f avant depouvoir appliquer le red de g.

Si la condition 5.1 est verifiee, alors on peut appliquer la regle suivante (voir la figure5.23) :

red(i2,map red(i1, T, f))≡

red(i1, i2, T, λ a1, a2, t . let < x, y > = f(a1, t)in let x′ = g(a2, y) in x, x′)

r2r1

i1 i2i2i1

r1 r2

gf

T T’ T

⇐⇒

Fig. 5.23 – red(map red)

Page 82: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

75 5 : Principes de compilation et optimisations

5.3.4.9 map red suivi de map red

Pour optimiser cet enchanement il faut verifier que :

f = λa, t.(a′, t′)

et g = λa, t.(a′′, t′′),

Alors on peut appliquer la regle suivante (voir la figure 5.24) :

map red(i2,map red(i1, T, f), g)≡

map red(i1, i2, T, λa1, a2, t . let < x, y > =f(a2, t) in let < x′, y′ > = f(a2, y) in

< x, x′, y′ >).

On doit verifier la meme condition que precedemment quant a une dependance hy-pothetique entre i2 and r1.

i2i1

r1 r2r2r1

i2i1 gf

T T’ T” T T”

⇐⇒

Fig. 5.24 – map red(map red)

Page 83: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 76

5.3.4.10 Remarque

Les axiomes donnes ci-dessus sont des equivalences entre differentes formes de pro-grammes. Nous les utilisons, evidement, en choisissant le ’sens’ d’application qui minimisele nombre de tableaux intermediaires.

5.3.5 Algorithme

Nous avons presente les axiomes de transformation de programmes que nous appliquonspour optimiser les enchanements d’iterations. Nous presentons dans cette partie le principede l’algorithme d’application de ces axiomes qui est implemente en amont de la generationde code.

Il est tout d’abord important de revenir sur la notion de determination des enchane-ments optimisables. En effet, il est possible que les iterateurs optimisables ne soient pasdirectement ecrits les uns a cotes des autres dans le programme source.

L’ordre des equations dans un noeud Lustre n’ayant aucune importance, il se peutmeme, comme nous l’avons deja fait remarquer, qu’un grand nombre d’equations separentces 2 iterations. Il faut alors penser a analyser le programme dans son ensemble, en re-cherchant pour chaque iteration, si ses parametres sont calcules par une autre iteration,n’importe ou dans le noeud. Si elle existe, on est sr de trouver cette seconde iteration dansle noeud courant : au moment ou l’optimisation est appliquee, les appels de noeuds ontete expanses (voir 5.1)et il n’y a donc plus qu’un seul noeud Lustre.

Si cette seconde iteration existe, et si les variables qui connectent les 2 sont des variablesinutiles au sens de la definition 5.1, et enfin si on peut optimiser l’enchanement par un desaxiomes ci-dessous, alors on le fait en creant un nouveau noeud que l’on itere, exactementcomme decrit dans les axiomes.

Nous decrivons l’algorithme d’optimisation en utilisant les notations et structurespresentees en 5.1.1.

Une premiere passe va consister a identifier et marquer les variables qui sont obtenuepar des iterations. La seconde partie optimise les enchanements. Notons qu’une fois que lesoptimisations ont ete effectuees sur le noeud principal, il faut encore optimiser les noeudsitere dans celui-ci. Tous ces traitements sont regroupes dans la fonction de la figure 5.25.

La fonction optimiser Enchanements est elle-meme decrite a la figure 5.26. Sonderoulement est le suivant. On regarde comment chaque variable locale ou de sortie duprogramme est calculee. Si une variable est calculee par une iteration, alors on regardecomment les parametres de cette iteration (notes LP) sont calcules.

On s’interesse au cas ou ils sont tous generes par une meme iteration(c’est lasemantique de la condition sur ObtenusParMemeIteration(LP)). Il faut aussi que cesparametres soient tous inutile vis-a-vis de l’optimisation des enchanements d’iterations(Inutiles(LP)) et que l’enchanement trouve soit optimisable au sens des axiomes donnesplus haut(Optimisable(It2,It1)).

Si et seulement si toutes ces conditions sont verifiees, on peut optimiser l’ enchanement.Dans tous les autres cas, l’optimisation n’est pas possible.

Pour appliquer l’enchanement, on cree un noeud “fusion” des 2 noeuds iteres, et onremplace les 2 equations iterantes de depart par l’iteration de ce noeud fusion.

Page 84: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

77 5 : Principes de compilation et optimisations

optimiser(N : AA_Noeud)optimisable=true;tantque optimisable faire

marquer_variablesObtenues_parIt\’eration(N);optimiser_Enchanements(N);

Pour chaque noeud NIt\’er\’e it\’er\’e dans N faire

optimiser(NIt\’er\’e);Nettoyer(N);

Fig. 5.25 – l’algorithme general regroupant tous les traitements necessaires a l’optimisationdes enchanements

optimiser Enchanements(N : AA Noeud)optimisable=false;Pour chaque V dans (N.Sorties

⋃N.Var Locales) faire

si (ObtenuParIteration(V))alorsIt1 = IterationcCalculant(V);LP = It1.Parametressi (ObtenusParMemeIteration(LP)

et Inutiles(LP))alorsIt2 = IterationCalculant(LP);si (Optimisable(It2,It1))alors NewN : AA Noeud;

It1 N : AA Noeud;It2 N : AA Noeud;optimisable=true;It1 N = ChargerNoeud(It1.nom);It2 N = ChargerNoeud(It2.nom);NewN = CreerNoeud Fusion(It2 N,It1 N);newIt Type = Type Fusion(It2.type,It1.type);AA Noeud.ListeEquations = AjouterEquation Iteration(V,newN.nom,

newIt Type,It1 N.Parametres);AA Noeud.ListeEquations = Supprimer Equations(<V,It1>,<LP,It2>);

sinon ∅// Ce type d’enchanement n’est pas optimisable

sinon ∅// Les parametres des iterations ne permettent pas// l’optimisation (ce sont des sorties ou ils ne sont// obtenus par une meme iteration)

sinon ∅// V n’est pas obtenu par une iteration

Fig. 5.26 – La fonction d’optimisation des enchanements

Page 85: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

5.3 : Enchanements d’iterateurs 78

Nous decrivons maintenant l’algorithme de fusion de noeuds, utilise ci-dessus pourcree le noeud NewN. Nous n’avons pas presentes tous les details specifiques a chaque typed’enchanements. En effet, certaines operations specifiques sont a effectuer selon les cas(comme la distinction de la premiere entree et de la premiere sortie d’un noeud itere dansune reduction). Nous nous sommes contentes de donner une presentation generale (voirfigure 5.27) de l’algorithme de fusion.

CreerNoeud Fusion(N1 : AA Noeud; N2 : AA Noeud) → NewN : AA Noeud

NewN.Entrees = N1.Entrees;NewN.Sorties = N2.Sorties;NewN.Variables Locales = N1.Sorties⋃

N2.Entrees⋃N1.Variables Locales⋃N2.Variables Locales;

NewN.ListeEquations = N1.ListEquations⋃N2.ListEquations⋃Equations deBranchement(N1.Sorties,N2.Entrees);

Fig. 5.27 – Algorithme de creation d’un noeud de fusion de deux noeuds

Page 86: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

79 5 : Principes de compilation et optimisations

Page 87: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 6

Introduction de la notion de temps

Dans les chapitres precedents, nous avons presente la partie du travail concernant lesous-langage fonctionnel de Lustre. Nous allons a present reintroduire les operateurstemporels du langage.

Nous avons dans un premier temps cherche a appliquer des techniques de retiming,dont nous avons parle plus haut. Nous verrons dans le paragraphe 6.1 que cette techniquene represente pas un solution satisfaisante.

Nous avons ensuite tente (a la section 6.2) de montrer que les techniques developpeessur la partie fonctionnelle de Lustre pouvaient etre etendues aux aspects temporels dulangage, sans avoir a modifier les programmes, comme on le fait dans 6.1.

tant donne un programme Lustre iterant des noeuds a memoires, on peut facilementecrire une version aplatie de ce programme, c’est-a-dire n’utilisant ni iterateurs ni memedes tableaux. Ensuite, il est facile de compiler de tels programmes grce aux outils Lustre.On genere du code sequentiel qui manipule des variables independantes au lieu de tableaux.

A partir de cette derniere forme, nous avons pu avoir une bonne idee du code qu’ilserait interessant d’obtenir en generant tableaux et boucles.

Nous avons pu etablir l’organisation du code a generer et montrer qu’on peut reutiliser(sous certaines contraintes presentees en section 6.3) le schema de compilation habituel deLustre en generant du code avec tableaux et boucles a la fois pour le calcul des sortieset pour la mise a jour des memoires.

6.1 Application des techniques de retiming

Soit une iteration d’un noeud N contenant des appels a l’operateur pre (voir figure6.1).

node N(accu_in : int ; elt_in : int) returns(accu_out : int);let

accu_out = 0 -> elt_in + pre(accu_in);tel

node main(init : int^10; Tab_in : int^10) returns (res : int);let

res = red<<N,10>>(init,Tab_in);tel

Page 88: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

81 6 : Introduction de la notion de temps

Ninit

resTab_in

+

+

+

+

+

pre

pre

pre

pre

pre

Fig. 6.1 – Iteration d’un noeud a memoire

En retimant N, on pourrait arriver a donner un noeud sans appels a l’operateur pre.Ces appels seraient en quelque sorte ’repousses’ a l’exterieur du noeud pour etre appliquesur les arguments de l’iteration. La figure 6.2 montre le retiming effectue sur 2 etages duprogramme N.

Si on peut ainsi ’sortir’ les operateurs temporels, alors iterer le noeud N sur un tableauxT revient a iterer le noeud N’ sur des memoires du tableau T (voir la figure 6.3). On seramene alors a des cas d’iterations de noeud sans memoire, pour lesquelles nous avonsmontre au chapitre 5, des solutions efficaces.

Malheureusement, cette technique est assez lourde a appliquer. Il faut en effet parcourirtout le graphe d’operateurs obtenu par mise-a-plat des instances du noeud itere, afin dedeterminer les occurrences de pre et de les faire ’remonter’ en dehors de ces instances. Enl’occurrence, l’hors d’enchanements d’iteration, il faudrait effectuer ces ’remontees’ (quiseraient alors tres longue) afin de voir apparatre des enchanements optimisables.

D’autre part, Cette methode necessite une restructuration totale des programmes. Nonseulement on n’est pas certains de savoir automatiser cette restructuration mais dans laplupart des cas on obtient un resultat qui est moins efficace en terme de memoire utilisee.

Dans la version de la figure 6.3, on voit bien qu’on a besoin de plus de cases memoires(il y a plus d’occurrence de l’operateur pre, exactement 15) que dans la version de la figure6.1 (ou l’on ne decompte que 5 occurrences de pre).

Page 89: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

6.1 : Application des techniques de retiming 82

pre

pre

pre

+

pre

+

Tab in[i]

Tab in[i+1]

Fig. 6.2 – Premiere etape du retiming

Tab_in

res

init

+++++

pre

preprepre

preprepreprepre

pre prepreprepre

pre

Fig. 6.3 – Resultat du retiming d’un red

Page 90: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

83 6 : Introduction de la notion de temps

Qui plus est, l’iteration obtenue par retiming manipule des tableaux de memoires.Vraisemblablement, ces tableaux doivent etre cree par des iterations de noeuds a memoires.On ne fait donc que repousser le probleme.

En fait, on applique les equivalences pre(a+b)≡pre(a)+pre(b), mais dans le mauvaissens : on augmente le nombre de memoires necessaires. Le retiming ne semble donc pasrepresenter une solution raisonnable pour la compilation d’iterateur a memoire.

6.2 Structure du code desire

6.2.1 Exemples

Nous donnons ici quelques exemples de programmes iterant des noeuds a memoire.Nous montrons comment on peut reecrire ces programmes en n’utilisant ni iterateurs nitableaux.

6.2.1.1 Mapper un noeud contenant un pre

Soit par exemple le programme de la figure 6.4. Le noeud principal (SommeTab) iterele noeud somme sur le tableau IN.

node somme(entree : int) returns (sortie : int);let

sortie = 0 -> entree + pre(sortie);tel.

node SommeTab(IN : int^4) returns (OUT : int^4);let

OUT = map<<somme,4>>(IN);tel

Fig. 6.4 – Le noeud Accumulateur

Afin d’etudier le code produit par le compilateur V4, on peut re-ecrire ce programmeen expansant les tableaux et en appliquant a chaque element le noeud somme. La figure6.5 donne ce programme.

Page 91: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

6.2 : Structure du code desire 84

node SommeTab(IN_1: int; IN_2: int; IN_3: int; IN_4: int)

returns(OUT_1: int; OUT_2: int; OUT_3: int; OUT_4: int);

letOUT_1 = (0 -> (IN_1 + (pre OUT_1)));OUT_2 = (0 -> (IN_2 + (pre OUT_2)));OUT_3 = (0 -> (IN_3 + (pre OUT_3)));OUT_4 = (0 -> (IN_4 + (pre OUT_4)));

tel.

Fig. 6.5 – Le noeud SommeTab en version expansee

Voici a present le code C produit par le compilateur. Tout d’abord, on trouvela declaration des variables du programmes (voir figure ci-dessous). Les declarationsprecedees de la mention //REGISTER concernent des definitions de variables generees parle compilateur.

La variable M5 est tres importante : elle represente l’horloge globale. C’est sur elleque seront effectues les test pour savoir si on se trouve dans l’instant initial. a l’instantinitial, M5 vaut true, puis elle vaut false pour le reste de l’execution du programme. Lesautres variables M.. representent les memorisations des sous-expressions auxquelles preest applique dans le programme source.

typedef struct void* client_data;//INPUTS_integer _IN_1;_integer _IN_2;_integer _IN_3;_integer _IN_4;//OUTPUTS_integer _OUT_1;_integer _OUT_2;_integer _OUT_3;_integer _OUT_4;//REGISTERS_integer M21;_integer M17;_integer M13;_integer M9;..._boolean M5;

SommeTab_ctx;

Voici a present le code qui est execute a chaque tour de l’horloge globale. Dans cettefonction, appelee SommeTab step, on trouve tout d’abord la declaration de variables localesutilisees par le compilateur.

Page 92: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

85 6 : Introduction de la notion de temps

void SommeTab step(SommeTab ctx* ctx)//LOCAL VARIABLES

integer L8;integer L4;...integer L20;integer L19;

integer T21;integer T17;integer T13;integer T9;

Ces variable sont en quelque sorte, regroupees par 2. Chaque “couple” sert a calculerles sous-expressions et expressions utilses au calcul d’une sortieou variable locale donnee.

Par exemple, comme on peut le voir dans le corps de la fonction decrit ci-dessous,L8 contient la valeur de l’expression IN 1 + (pre OUT 1). L4 contient la valeur de OUT 1.celle-ci est calculee avec L8, selon que M5 est vraie ou non (donc selon que l’on se trouvedans l’instant initial ou non). L4 est ensuite emise comme valeur courante de la sortieOUT 1, grce a la fonction SommeTab 0 OUT 1.

On trouve les meme calculs pour les 3 autres sorties du noeud SommeTab. Ensuite, ontrouve la memorisation des valeurs courantes des expressions auxquelles l’operateur preest applique dans le programme Lustre (par exemple ctx->M21=T21

Page 93: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

6.2 : Structure du code desire 86

//CODEL8 = (ctx->_IN_1 + ctx->M9);if (ctx->M5)

L4 = 0; else

L4 = L8;SommeTab_O_OUT_1(ctx->client_data, L4);...L20 = (ctx->_IN_4 + ctx->M21);if (ctx->M5)

L19 = 0; else

L19 = L20;SommeTab_O_OUT_4(ctx->client_data, L19);

T21 = L19;..T9 = L4;

ctx->M21 = T21;...ctx->M9 = T9;ctx->M5 = ctx->M5 && !(_true);

La derniere equation permet de mettre a jour la variable M5 qui, rappelons-le, est vrailorsqu’on est dans l’instant initial et fausse dans tous les autres cas.

La reunion des donnees sous forme de tableaux (proposees dans le chapitre 2) peutetre appliquee sur cet exemple. On obtient ainsi le programme suivant :

Page 94: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

87 6 : Introduction de la notion de temps

typedef structvoid* client data;//INPUTSinteger IN[4];//OUTPUTSinteger OUT[4]//REGISTERSinteger MEM[4];

boolean M5;SommeTab ctx;

void SommeTab step(SommeTab ctx* ctx)//LOCAL VARIABLES

integer LOC1[4]; //Contient L8, L12, L16, L20integer LOC2[4]; //Contient L4, L11, L15, L19integer TMP[4]; //Contient T21, T17, T13, T9

//CODE//Calcul des sortiesfor(i=0;i<4;i++)LOC1[i] = ctx->IN[i] + ctx->MEM[i];if(SommeTab ctx->M5) LOC2[i] = 0;else LOC2[i] = LOC1[i];

//Emission des sortiesSommeTab 0 OUT(SommeTab ctx->client_data, LOC2);

//Mise a jour des memoiresfor(i=0;i<4;i++)TMP[i] = LOC2[i];SommeTab ctx->MEM[i] = TMP[i];

SommeTab ctx->M5 = ctx->M5 && !(_true);

Les memoires M21, M17, M13, M9 peuvent etre regroupees dans un tableau MEM. On faitde meme pour les variables locales L8, . . .qui peuvent etre groupees dans deux tableauxLOC1 et LOC2. En somme on genere un tableau pour chaque sous-expression dans le noeuditere e tpour chacune de ses variables a laquelle pre est applique.

Pour calculer chacune des sorties OUT[i], on se sert donc de LOC1[i], LOC2[i], IN[i]et MEM[i], dans une boucle. Pour memoriser les elements de MEM, on trouve une autreboucle assignant la valeur de chaque TMP[i] au MEM[i] correspondant. TMP regroupe lesvaleurs correspondant a T21, T17, T13 et T9.

6.2.1.2 Reduction d’un noeud a memoire

Nous allons voir maintenant que cette repartition du code genere entre calcul dessorties et mise a jour des memoires peut etre facilement maintenue dans des exemples pluscomplexes.

Page 95: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

6.2 : Structure du code desire 88

Soit le programme Lustre-V6 de la figure 6.6. Le programme main itere un noeud na l’aide d’un map red. La semantique de l’exemple n’a pas d’importance.

node n(a in, el in1, el in2 : int) returns (a out, el out : int);let

el out = 0 -> if(el in2>pre(el out))then pre(a in + el in1)else pre(el out) + el in1;

a out = 0 -> pre(a in + el in1);tel

node main(T in1, T in2 : int^10) returns (accu_out : int; T out : int^10);let

accu out,T out = map red<<n,10>>(0,T in1,T in2);tel

Fig. 6.6 – map red d’un noeud a memoire

En suivant la meme demarche que dans l’exemple precedent, on identifie le code sou-haite comme le suivant :

typedef struct void* client data;//INPUTSinteger T in1[5];integer T in2[5];//OUTPUTSinteger accu out;integer T out[5];//REGISTERinteger MEM1[5];integer MEM2[5];integer M11;

main ctx;

void main step(main ctx* ctx)//LOCAL VARIABLESboolean LOC1[5];integer LOC2[5];integer LOC3[5];integer LOC4[5];integer LOC5[5];integer LOC6[5];

//CODE/*calcul des sorties et des variables locales*/for(i=0;i<5;i++)/*La i-eme sortie*/LOC1[i] = ctx->T in2[i] > MEM2[i];

Page 96: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

89 6 : Introduction de la notion de temps

LOC2[i] = MEM2[i] + T in2[i];if(LOC1[i])LOC3[i] = MEM1[i];

else LOC3[i] = LOC2[i];

if(ctx->M11)LOC4[i] = 0;

else LOC4[i] = LOC3[i];

/*Les variables locales*/if(ctx->M11)LOC5[i] = O;

else if(i=0)LOC5[i] = 0;

else LOC5[i] = MEM1[i];

LOC6[i] = LOC5[i] + T_in1[i];

//emission sortiesmain 0 accu out(ctx->client data, LOC6[4]);main 0 T out(ctx->client data, LOC4);

//memorisationfor(i=0;i<5;i++)/*pour les ’pre(el out)’*/MEM2[i] = LOC4[i]

/*pour les ’pre(a in + el in1)’*/MEM1[i] = LOC5[i];

Les tableaux MEM1 et MEM2 representent les valeurs dans l’ instant precedent des va-riables auxquelles est applique l’operateur pre.

Les tableaux LOC1 a LOC6 servent a calculer les sous-expressions des equations Lustre.

6.2.2 Conclusion

Grce aux deux exemples que nous avons presente, nous avons montre que la generationdu code pour des iterateurs a memoires est assez simple.

Le code obtenu pour un programme manipulant des iterateurs a memoire sera constituedes 3 parties suivantes :

– calcul des sorties, sous la forme de boucle parcourant les tableaux de memoires etd’entrees

– emission des sorties

Page 97: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

6.3 : Identification des cycles 90

– memorisation des valeurs necessaires dans l’instant d’apres, qui se fait aussi sousforme de boucle parcourant des tableaux.

Ce schema de compilation est celui habituellemet utilise pour Lustre, en tenantcompte des structurations des donnees sous forme de tableaux.

La phase amont de localisation des memoires et de definitions des variables leur cor-respondant se fait par les techniques presentees dans [Ray91].

On commence par identifier les memoires necessaires (correspondant aux occurrencede l’operateur pre). Ensuite, on ajoute autant de variables au programme cible (ici ce sontles tableaux MEM1 et MEM2). Enfin, on remplace chaque expression qui est parametre d’unpre par la variable correspondante.

6.3 Identification des cycles

ExempleSoit le programme suivant :

node n(a, e : int) returns (t : int);let

t = 0 -> pre(a) + e;tel

On peut iterer un ce programme avec l’operateur red :

node main(E : int^10) returns (s : int);let

s = red<<n,10>>(0,E);tel

Mais on pourrait aussi ecrire :

node main bis(E : int^10) returns (s : int);let

s = red<<n,10>>(s,E);tel

En regardant seulement le programme main bis, la verification statique rejetterai leprogramme. En effet, on a une definition cyclique de s (voir chapitre 2).

Pourtant, si on analyse le noeud itere, on s’aperoit que s depend en fait de la valeurqu’il avait 10 instants auparavant. Ce programme a donc une semantique correcte etdevrait donc etre accepte.

Page 98: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

91 6 : Introduction de la notion de temps

6.4 Compilation et Optimisation

Ce genre d’analyse est cependant impossible a effectuer lorsqu’on applique desmethodes de compilation separee [Ray88].

Ces techniques permettent de generer le code de chaque noeud sans analyser les noeudsqu’il utilise (par appel ou iteration). On genere des appels au fonction correspondant auxnoeuds appeles.

On exige alors qu’il n’existe aucune definition cyclique, c’est a dire qu’une equation x= f(x) ou f contient l’unique equation x = pre(x), est interdite, meme si l’analyse de fpermettrait de l’autoriser.

Dans notre cas, on exigera qu’il n’existe pas de dependance cyclique directe entre lesparametres effectifs d’une iteration. C’est une contrainte qui peut paratre forte mais quiest utilisee dans l’atelier Scade (realisation industrielle basee sur Lustre), et qui semblecorrespondre aux methodes des utilisateurs terminaux.

Le programme main bis est donc refuse.

Une fois cette restriction adoptee, on peut utiliser le schema de compilation et lesaxiomes d’optimisations presentes au chapitre 5.

Pour les calculs specifiques au noeud a memoires, on utilisera les techniques developpeesdans [Ray91] et generant du code avec tableaux et boucles de parcours a la fois pour lescalculs des sorties et les memorisations.

Page 99: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 7

Experimentation - Le prototypeLac

Nous presentons ici une implementation qui a ete realisee durant ce projet. Un proto-type de compilateur appele Lac (pour Lustre-Array-Compiler) a ete developpe. Il permetl’utilisation des iterateurs au sein d’un sous-ensemble du langage Lustre.

Il a ete developpe en C, Lex et Yacc pour la partie analyse et generation de code, eten utilisant le langage Stratego [Vis01] pour l’implementation des axiomes d’optimisation.Le tout represente environ 9000 lignes de code.

7.1 Aspects de Lustre utiles pour le prototype : mini-lustre

7.1.1 Types

Nous n’avons pas introduit tous les types habituellement disponibles en Lustre. Nousnous sommes contentes des types suivants :

– entier– booleen– tableau– structuresCes types sont simples a manipuler et ils se sont averes suffisants pour valider nos

techniques sur les exemples et etude de cas que nous avons pu traite.

7.1.2 Expressions, equations

La plupart des operateurs arithmetiques et booleens Lustre sont disponibles dansmini-lustre. Neanmoins, certaines contraintes sont ajoutees :

– l’ordre des equations dans un noeud mini-lustre est important. En effet, on n’effectueaucun tri des equations et leur ordre dans le programme C sera celui dans lequelelles sont donnees dans le programme source. Les equations dans un noeud iteredoivent aussi etre donnees dans l’ordre des variables qu’elles definissent (definitionsdes variables locales, puis des sorties du noeud en respectant leur ordre).

– les expressions utilisees dans une equation conditionnelle ne peuvent pas etre desiterations

Page 100: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

93 7 : Experimentation - Le prototype Lac

– les membres d’une structure doivent etre definies dans la meme equation. Parexemple, si st est de type int,bool,in, alors, on doit ecrire st.%0, st.%2,st.%1 = (..., ..., ...)

7.1.3 Operateurs temporels

Nous n’avons pas eu le temps d’implementer les techniques de compilation pour desiterations de noeud a memoire. L’introduction de l’operateur pre et la completion del’algorithme de generation de code pour ces cas sont en cours. Nous obtiendrons ainsi unprototype qui permettra de valider tous les aspects (fonctionnels comme c’est deja le cas,et temporels) de la compilation des iterateurs de tableau.

7.2 Le processus de compilation dans Lac

Le mecanisme de compilation implemente dans Lac se decoupe en 3 phases distinctes(voir la figure 7.1) :

– expansion des appels de noeuds– optimisation des enchanements– generation de code.

Applicationdes

axiomes

Generationde

Code

in lacoptim.lusfichier.lus

node main ...

Expansiondes appels

de noeuds

out lacoptim.lusmain.c

Fig. 7.1 – Processus de compilation dans Lac

Nous decrivons dans la suite chacune de ces 3 parties.

7.2.1 Expansion des appels de noeuds

L’expansion des appels de noeuds n’est pas une nouveaute (c’est l’etape effectuee parl’outil actuel lus2ec). Cependant, nous n’avons pas pu reutiliser cet outil, puisqu’il nepermettait pas de reconnatre les iterateurs de tableaux. Nous avons donc inclu dans Lacun algorithme d’expansion d’appel readapte a mini-lustre.

L’expansion des appels de noeuds est essentielle afin de rendre efficaces les optimisa-tions du chapitre 5 les plus efficaces possible.

Page 101: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7.2 : Le processus de compilation dans Lac 94

Soit par exemple les noeuds NP et N decrits a la figure 7.2. Le noeud NP contient 2equations. La premiere appelle le noeud N, et la seconde itere un noeud f (quelconque).

node NP(A : int^10) returns (C : int^10);var B : int^10;let

B = N(A);C = map<<f,10>>(B);

tel

node N(Tab_In : int^10) returns (Tab_Out : int^10);let

Tab_Out = map<<g,10>>(Tab_In);let

Fig. 7.2 – les noeuds NP et N

Si on applique l’algorithme donne en 5.3.5, sans expanser l’appel au noeud N, alors onne saura pas detecter l’enchanement de map qui est pourtant evident.

Si on expanse l’appel a N, on obtient le code donne a la figure 7.3. Dans ce cas, on estcapable de reconnatre l’enchanement map(map) attendu.

node NP(A : int^10) returns (C : int^10);var B : int^10;let

B = map<<g,10>>(A);C = map<<f,10>>(B);

tel

Fig. 7.3 – le noeud NP apres expansion des appels de noeuds

Il est indispensable d’implementer l’expansion des noeuds (decrite ci-dessous), pouretre sr d’avoir toutes les iterations du programme dans le noeud principal et ainsi depouvoir optimiser tous les enchanements qui sont optimisables.

AlgorithmeL’algorithme general d’expansion procede de la maniere suivante (voir la fonction

Appliquer appel deNoeud a la figure 7.4). On commence par expanser les appels denoeuds presents dans le noeud courant N. Mais il se peut que cette expansion fasse ap-paratre des appels de noeuds qui etait ecrits dans les noeuds dont les appels viennentd’etre expanses. On recommence donc a parcourir le noeud N, afin d’y expanser tous lesnouveaux appels de noeuds. Et on recommence ainsi de suite jusqu’a ce qu’il n’y ait plusd’appels de noeuds dans N. C’est la semantique de la variable expansable et de la boucletant que expansable faire ....

Une fois qu’on a expanse tous les appels de noeuds dans N, il faut faire la memeoperation dans les noeuds qui sont iteres dans N.

Page 102: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

95 7 : Experimentation - Le prototype Lac

Appliquer appel deNoeud(N : AA Noeud)expansable = true;tant que expansable faire

Expanser appelsDans(N);

Pour chaque noeud NItere itere dans N faireAppliquer appel deNoeud(NItere);

Fig. 7.4 – Fonction principale d’expansion des appels de noeud

L’expansion des appels de noeuds dans un noeud note N se fait de la maniere suivante(voir figure 7.5). On parcourt N.ListEquations. Pour chaque equation Eq, s’il s’agit d’unappel de noeud, on commence par charger le noeud appele, note NA. On va ensuite integrerdans N le code correspondant a NA.

Pour cela, on procede comme suit : on ajoute aux variables locales de N, toutes lesvariables (entrees, sorties et locales) de NA. On prend garde aux redondances de definitions,et on change le nom de toute variable de NA qui a un homonyme dans les variables de N(tout ceci est effectue par la fonction Ajouter Variables).

On ajoute ensuite aux equations de NP :– des equations de correspondance pour les parametres d’entree du noeud appele– les equations du noeud NA– des equations de correspondance pour les parametres de sortie du noeurd appeleIl faut enfin supprimer l’equation d’appel que l’on vient d’expanser.Par exemple, pour le programme de la figure 7.2, on obtiendrait le code de la figure

7.6.Il faudrait encore quelques manipulations (de suppression de variables intermediaires

inutiles, comme ici Tab In et Tab Out) pour rendre evident l’enchanement des iterationsde f et de g dans NP. On devrait pouvoir se ramener au code de la figure 7.3.

Nous n’avons pas eu le temps d’apporter cette derniere fonctionnalite au prototype.Ainsi, Lac ne permet pas encore, dans son etat actuel, de traiter les enchanementsd’iterations places dans des noeuds differents.

Page 103: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7.2 : Le processus de compilation dans Lac 96

Expanser appelsDans(N : AA Noeud)expansable = false;Pour chaque Eq dans N.ListEquation faire

si Eq.expression.type = appelNoeud;alors

expansable = true;

NA : AA Noeud;NA = ChargerNoeud(Eq.expression.Nom);

N.Variables Locales = Ajouter Variables(NA.Parametres Formels);

N.ListEquation = Ajouter EquationCorrespondance(NA.Entrees, Eq.expressions.Parametres);

N.ListEquation = Ajouter ListEquation(NA.ListEquations,Eq.expressions.Parametres);

N.ListEquation = Ajouter EquationCorrespondance(Eq.variables, NA.Sorties);

Supprimer Equations(Eq);sinon

Fig. 7.5 – Expansion des appels de noeuds dans un noeud N

node NP(A : int^10) returns (C : int^10);var

B : int^10;Tab_In : int^10;Tab_Out : int^10;

letTab_In = A;Tab_Out = map<<g,10>>(Tab_In);B = Tab_Out;C = map<<f,10>>(B);

tel

Fig. 7.6 – Resultat de la fonction Appliquer appel deNoeud appliquee a NP

Page 104: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

97 7 : Experimentation - Le prototype Lac

7.2.2 Implementation des axiomes d’optimisation d’enchanements

L’algorithme que nous avons presente au chapitre 5.3.5 n’a pas ete implemente dansLac. Nous avons voulu en effet essayer d’utiliser un outil de transformation de programmesappele Stratego.

Stratego est base sur des techniques de reecriture. Les programmes Lustre peuventetre consideres comme des termes et les axiomes definis en 5.3 comme des regles dereecriture de termes.

Il a donc fallu decrire les programmes Lustre sous forme de termes. Cela se fait tresfacilement avec le langage Stratego.

On a definit des sortes S (des types) et des constructeurs sur ces sortes. L’ensembledefinit les termes de sortes S. Par exemple, on peut definir une classe de termes correspon-dant aux expressions Lustre grce au programme de la figure 7.7. On y declare un modulenomme expression qui utilise notament les sortes et contructeurs definit dans un autremodule (imports list parameters). On y definit une sorte Expr et des constructeurspour manipuler cette sorte. On retrouve tous les operateurs arithmetiques et booleensde Lustre (Add, And, . . ., If, . . .), ainsi que les operateurs map, red, fill, map red etmirror.

module expressionimports list parameterssignature

sorts Exprconstructors

Var : String -> ExprVal : Natural -> Expr

Add : Expr * Expr -> ExprAnd : Expr * Expr -> Expr...If : Expr * Expr * Expr -> ExprSelect : String * Natural -> Expr...Map : String * String * List_Parameters -> ExprMap : String * Natural * List_Parameters -> Expr...Mirror : String -> Expr...list_exp : Expr * Expr -> Expr...Nil : Expr

Fig. 7.7 – Le programme Stratego definissant les termes ’expressions’

Nous avons defini un langage de termes correspondant au mini-lustre que nous avonsdefinit plus haut.

En Stratego, il a ete tres facile d’ecrire des versions simplifiees des axiomes que nousavons defini au chapitre 5. Il suffit de donner des regles de reecriture basees sur le langage

Page 105: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7.2 : Le processus de compilation dans Lac 98

de terme. Par exemple, on ecrit l’axiome map(map) comme la regle de la figure 7.8.

MapMap : lnode(aNode(name1,in1,out1,loc1,

leq(eq(o1,Map(name2,size,i1)),leq(eq(o2,Map(name3,size,o1)),l))

),lnode(aNode(name2,in2,out2,loc2,

listeq2),lnode(aNode(name3,in3,out3,loc3,

listeq3),end_nodes)))

->

lnode(aNode(name1,in1,out1,loc1,

leq(eq(o2,Map(name4,size,i1)),l)

),lnode(aNode(name4,in2,out3,

concatenate(loc2,concatenate(loc3,concatenate(in3,out2))),

concatenate(listeq2,concatenate(leq(eq(ldecl_to_lparam(in3),

ldecl_to_lexpr(out2)),Nil),listeq3))),

end_nodes))where new => name4

Fig. 7.8 – Implementation en Stratego de l’axiome map(map)

Cette regle dit que : si on a une liste de noeuds constituee d’un noeud name1iterant 2 noeuds name2 et name3 par les equations leq(eq(o1,Map(name2,size,i1)) etleq(eq(o2,Map(name3,size,o1)), alors on peut transformer le noeud name1 en rem-plaant ces 2 equations par l’iteration d’un nouveau name4, definit comme la fusion desnoeuds name2 et name3. On donne ainsi une regle pour chaque axiome defini en 5.3 (saufle cas red(fill) qui, comme nous l’avons vu, n’est pas optimisable dans le code source).

Nous avons implemente, dans un outil baptise lacoptim, des parties minimales des

Page 106: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

99 7 : Experimentation - Le prototype Lac

axiomes : nous savons traiter les cas ou les 2 iterations a optimiser sont exactement l’unea la suite de l’autre et dans le bon ordre. Nous pouvons aussi rapprocher des iterationsseparees par une autre equation.

L’axiome de la figure 7.8 ne fonctionne que dans les cas ou :– les 2 iterations sont cte-a-cte dans le noeud name1– les noeuds name1, name2 et name3 sont declares dans cet ordre precis– les noeuds name2 et name3 ne sont utilises nulle part ailleurs dans le programme

considere (les 2 sont supprimes brutallement sans verifier s’ils sont utiles au reste duprogramme)

lacoptim optimise traite le programme qu’on lui fournit jusqu’a ce qu’aucun axiomene soit plus applicable selon les regles que nous lui donnons.

Deux traducteurs ont ete ecrits. lus2lterm permet de transformer des programmesLustre-V6 en des termes correspondant a la syntaxe definie ci-dessus. lterm2lus permetde generer un programme Lustre a partir d’un terme donne.

Le branchement de ces trois outils lacoptim, lus2lterm et lterm2lus permet d’obte-nir (voir figure 7.9), a partir d’un programme Lustre avec iterateur, la version optimiseedans laquelle aucun enchanement d’iterateur n’est plus optimisable.

lterm2lus

out lacoptim.lus

in lacoptim.lus in lacoptim.ltrm

out lacoptim.ltrm

lacoptim

lus2lterm

Fig. 7.9 – Schema d’optimisation

Un outil tel que Stratego est tres general. Pour etre complete, l’implementationnecessite au sein de l’outil lacoptim la redefinition totale de la semantique de Lustre.Mais ce travail est inutile : on a deja, dans un compilateur Lustre, tous les outils et struc-tures necessaires a l’ecriture de l’algorithme que nous avons presente plus haut (chapitre5). A terme, il sera plus facile d’inclure cet algorithme directement dans le compilateur.

Neanmoins, notre but, pour l’instant, n’etait pas de fournir un outil complet, maisd’ecrire un prototype qui permettrait de valider les techniques proposees. Il etait plus

Page 107: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7.3 : Exemples 100

interessant, car plus rapide, d’ecrire un optimiseur incomplet qui soit suffisant pour prouverl’utilite de nos propositions.

7.2.3 Generation de code

Nous avons implemente l’algorithme de generation de code presente au chapitre 5 avecune petite limitation : le traitement des imbrications d’iterations n’est pas complet.

Pour chaque equation du noeud considere, on genere une affectation C, contrairementaux outils pre-existants ou, comme on l’a vu au chapitre 6, on genere des variables in-termediaires pour calculer les sous-expressions.

En dehors de a, nous avons obtenu un prototype satisfaisant qui nous a permis devalider les techniques presentees tout au long de ce rapport, sur des exemples tout a faitconvaincants. Nous avons, entre autres, pu re-ecrire des programmes venant d’une etudede cas fournie par Aerospatiale.

Nous etudions, dans le paragraphe suivant, 2 exemples, dont un est tire de l’etude decas ELMU.

7.3 Exemples

7.3.1 Produit scalaire de 2 vecteurs

Nous proposons de calculer le produit scalaire r de 2 vecteurs V et W de taille n definipar :

r =n∑

i=0

V[i] ∗ W[i]

Le programme Lustre

node Prod_Sum(a : int ; v : int ; w : int) returns (aa : int);let

aa = a + v*w;tel

node scal_prod(V : int^3 ; W : int^3) returns (r : int);let

r = red<<Prod_Sum,3>>(0,V,W);tel

Code C produit par Lac

En compilant, le programme ci-dessus avec Lac, on obtient le code suivant :

Page 108: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

101 7 : Experimentation - Le prototype Lac

typedef int _boolean;typedef int _integer;

void scal_prod(_integer V[3],_integer W[3],_integer *r)

_integer i0;*r = 0;for(i0=0;i0<3;i0++)

*r = *r + V[i0] * W[i0];

7.3.2 Calcul des 2 maxima d’un tableau

Cet exemple est tire de l’etude de cas ELMU sur laquelle nous avons travaille pour lasociete Aerospatiale.

Le but est de calculer, etant donne un tableau A de n entiers, les 2 maxima des elementsde A et leur indice respectif. le noeud principal, note MAX, rend un tableau de booleens resdefinit par :

res[i] = true ⇔ A[i] est une des 2 valeurs maximales de A.

Une premiere etape consiste a determiner les 2 maxima de A (max1 et max2) ainsi queleurs indices (imax1 et imax2). Pour cela, nous utilisons un noeud calculs max definit ala figure 7.10 qui sera itere par l’operateur red sur le tableau A.

strin (resp. strout) regroupe les informations suivantes :– strin.%0 et strin.%1 (resp. strout.%0 et strout.%1) representent les valeurs des

2 maxima courants– strin.%2 et strin.%3 (resp. strout.%2 et strout.%3) representent leurs indices– strin.%4 (resp. strout.%4) represente l’indice de l’element courant de AOn peut ainsi calculer max1, max2, imax1, imax2 grce a l’equation :

max1,max2,imax1,imax2,icourant = red<<calculs_max,10>>(0,0,-1,-1,0,A);

On n’a plus qu’a remplir le tableau res. Pour cela, on utilise un noeud fill booldonne a la figure 7.10.

l’equation elt = (s.%2 = s.%0) or (s.%2 = s.%1) ; assigne a chaque element deres la valeur vrai si et seulement si le rang de cet element correspond a une des valeurss.%0 ou s.%1 (qui correspondent respectivement a imax1 et imax2.

On remplit donc le tableau res avec l’equation suivante :

Page 109: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7.3 : Exemples 102

node calculs max(strin : int,int,int,int,int ; ecourant : int)returns (strout : int,int,int,int,int);letstrout.%0, strout.%1, strout.%2, strout.%3, strout.%4 =

if ecourant<=strin.%1then (strin.%0,strin.%1,strin.%2,strin.%3,strin.%4+1)else if ecourant>strin.%1 and ecourant<=strin.%0

then (strin.%0,ecourant,strin.%2,strin.%4,strin.%4+1)else --ecourant>max1

(ecourant,strin.%0,strin.%4,strin.%2,strin.%4+1);tel

node fill bool(s : int,int,int) returns (st : int,int,int ; elt : bool);let

st.%0,st.%1,st.%2 = (s.%0,s.%1,s.%2+1);elt = (s.%2 = s.%0) or (s.%2 = s.%1);

tel

Fig. 7.10 – Les noeuds calculs max et fill bool

res = fill<<fill_bool,10>>(imax1,imax2,0);

Le programme complet, appele MAX est donne a la figure 7.11. Ce programme estrepresente a la figure 7.12

node MAX (A : int^10) returns (res : bool^10);varmax1 : int;max2 : int;

imax1 : int;imax2 : int;icourant : int;

letmax1,max2,imax1,imax2,icourant = red<<calculs_max,10>>(0,0,-1,-1,0,A);res = fill<<fill_bool,10>>(imax1,imax2,0);

tel

Fig. 7.11 – Le noeud MAX

Le code genere par Lac est donne en annexe A. On y donne aussi une idee du gainen temps d’execution apportee par notre solution, sur un tel programme : par rapport auprogramme original, le code genere a partir du programme ci-dessus est 2 fois plus rapide.

Page 110: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

103 7 : Experimentation - Le prototype Lac

0 0 -1 -1 0

max1 max2 imax1 imax2 icourant(8) (6) (3) (1) (5)

3

fill bool

calculs max

8

2

6

5

res

false

false

true

false

true

A

Fig. 7.12 – Calcul de 2 maxima d’un tableau d’entiers

Page 111: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

7.4 : Utilite de la solution presentee 104

7.3.3 L’additionneur n bits

A titre indicatif, on donne a la figure 7.13 le code produit par Lac pour le programmede l’additionneur n bits, decrit au chapitre 2.3.6.

typedef int Boolean;typedef int Integer;

void ADD(Boolean A[10],Boolean B[10],Boolean * S[10],Boolean * overflow)

Integer i0;Boolean mem overflow;* overflow = 0;for(i0=0;i0<10;i0++)

mem overflow = * overflow;

* S[i0]= A[i0] ^ ( B[i0] ^ mem overflow);* overflow=( A[i0] && B[i0])

^ ( B[i0] && mem overflow)^ ( A[i0] && mem overflow);

Fig. 7.13 – Code produit par Lac pour l’additionneur n bits programme avec des iterateurs

7.4 Utilite de la solution presentee

Il n’a pas ete evident d’etudier l’implementation des iterateurs dans l’etude de cas surlaquelle nous avons travaille. En effet, il a fallu modifier la structure des donnees et desprogrammes qui sont globalement difficiles a lire et a comprendre, de part, justement, leurmanque de structuration.

Les resultats que nous avons obtenu sont pourtant convaincants (voir le code produitpour les exemples ci-dessus). Bien qu’il soit difficile d’estimer le gain global en memoirenecessaire, temps d’execution et taille de code produit (nous n’avions pas assez d’infor-mations pour compiler l’etude de cas complete), nous avons pu confirmer les attentes quenous avons exposees en 2.4 :

– localement (sur les parties de programmes que nous avons pu traiter), le code quel’on peut obtenir en compilant un programme avec iterateurs est plus petit et plusrapide (on diminue d’a peu pres 50% le temps d’execution).

Page 112: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

105 7 : Experimentation - Le prototype Lac

– Les programmes sont plus clairs. Les iterateurs permettent de structurer les donneeset donc d’organiser les programmes. Ceux-ci sont donc plus lisibles, plus facile aecrire, a manipuler et a corriger.

Page 113: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Chapitre 8

Conclusion

8.1 Bilan

Le travail que nous avons presente concerne la generation de code efficace pour desiterateurs de tableaux au sein du langage Lustre.

Nous avons montre que les methodes de compilation utilisees jusqu’ici et initialementdeveloppe pour la programmation de systemes materiels sont particulierement inadapteesa un cadre logiciel. Le code que l’on produit n’est en effet pas aussi efficace que ce qu’onpourrait l’esperer, et ce principalement a cause de la perte de la structuration des donnees.

L’expansion des tableaux en variables independantes empeche de generer du code avectableaux et boucles (c’est a dire un code plus petit et potentiellement plus rapide).

La solution proposee consistait a introduire dans le langage des iterateurs de tableauxpour lesquels on sache produire du code avec boucles et tableaux.

La notion d’iterateur est une notion importante dans le cadre des langages fonctionnels.Les informations que nous avons pu y trouve, concernant aussi bien les iterateurs eux-memes que leur compilation, ou encore les optimisations possibles (notamment en rapportau notion de deforestation et de listlessness) ont ete fondamentales pour notre travail.

Nous en avons extrait une methode de compilation adaptee au cadre plus restreint deLustre, ainsi que des axiomes d’optimisations qui permettent d’optimiser les enchane-ments d’iterations et ainsi d’obtenir un code encore plus rapide et plus econome en termede memoire utilisee.

On a montre que les algorithmes proposes, tout d’abord etudie pour des iterations denoeud sans memoires, peuventetre etendus aux iterations de noeud a memoire. Une seulerestriction (deja couramment acceptee dans les application industriels de Lustre) a etenecessaire : on interdit les rebouclages instantanes non-detectables par analyse statiquesimple (on ne doit pas avoir a analyser le code des noeuds iteres). Les methodes de com-pilation generales utilisees dans les compilateurs Lustre, pourrontetre utilisees avec lesalgorithmes de generation de code pour les iterateurs que nous avons donne.

Finalement, nous avons developpe le prototype de compilateur Lac, au sein duquelnous avons introduit le traitement des iterateurs de tableaux. Nous avons utilise ce pro-

Page 114: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

107 8 : Conclusion

totype pour programmer de nombreux algorithmes manipulant des tableaux, notammentprovenant d’une etude de cas importante fournie par la societe Aerospatiale.

Les resultats ont ete tout a fait satisfaisants, puisqu’on a montre que :– le gain en taille de code est evidement important (on peut generer une boucle ma-

nipulant des tableaux au lieu de generer des actions independantes).– le gain en temps d’execution peutetre fort : comme vu dans l’exemple du calcul des

maxima, on peut esperer diminuer de moitie le temps d’execution d’un programme,rien qu’en generant du code avec boucles et tableaux.

– les algorithmes usuels sont plus faciles a ecrire avec les iterateurs de tableaux qu’avecles operateurs disponibles jusqu’a present.

– les iterateurs de tableaux permettent un structuration forte des programmes.

8.2 Perspectives

Integration au sein de l’usine LustreL’integration des iterateurs de tableaux dans le langage Lustre “officiel” est prevue

pour la nouvelle version Lustre-MM, ainsi que dans l’outil Tau-Scade , developpe parla societe Telelogic.

Les algorithmes de compilation et d’optimisations presente dans ce rapport y serontintegre.

A terme, un outil comme Tau-Scade pourra proposer des bibliotheques de pro-grammes manipulant des tableaux (calculs de maximum, tri, etc), basee sur les iterateurs.Le programmeur pourra manipuler les programmes de cette bibliotheque aussi facilementqu’il manipule les operateurs usuels, notamment grce a la genericite sur la taille des ta-bleaux.

Utilisation de la structuration des donneesNous avons etudie comment on peut tirer partie de la structuration des programmes

pour leur compilation. On peut maintenant envisager utiliser cette structuration pour lesautres etapes de mise en oeuvre des logiciels critiques temps-reel : simulation, generationde tests, debogage, verification formelle.

On pense notamment a etudier comment realiser des preuves inductives sur un pro-gramme structure grce a des tableaux On profiterait du fait que les traitements de tableauxsont exprimes exclusivement en termes d’iterateurs.

En effet, l’utilisation des iterateurs dans les programmes revient a donner explicitementdes invariants de boucles.

Techniquement, on peut alors envisager de marier les techniques de model-checkingdes outils actuels avec l’utilisation d’assistants de preuve, comme Coq ou PVS pour aidera la validation de systemes aux donnees fortement structurees.

Cette idee est a la base du sujet de these qui devrait decouler de ce DEA .

Page 115: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Annexe A

Calcul des 2 max

A.1 Code C produit par Lac

On trouve tout d’abord l’en-tete de la fonction MAX :

typedef int Boolean;typedef int Integer;

void MAX(Integer _A[10],Boolean * res[10])

Integer max1;Integer max2;Integer imax1;Integer imax2;Integer icourant;

Ensuite, on trouve la boucle correspondant a l’equation definissant max1, max2, imax1et imax2 :

//Initialisation des accumulateursInteger i0;Integer mem max1;max1 = 0;max2 = 0;imax1 = - 1;imax2 = - 1;icourant = 0;

for(i0=0;i0<10;i0++)mem max1 = max1;mem max2 = max2;mem imax1 = imax1;mem imax2 = imax2;mem icourant = icourant;//Mise a jour des accumulateurs

if( A[i0] <= mem max2)

Page 116: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

109 A : Calcul des 2 max

max1 = mem max1;max2 = mem max2;imax1 = mem imax1;imax2 = mem imax2;icourant = mem icourant + 1;

elseif( A[i0] > mem max2 && A[i0] <= mem max1)

max1 = mem max1;max2 = A[i0];imax1 = mem imax1;imax2 = mem icourant;icourant = mem icourant + 1;

else

max1 = A[i0];max2 = mem max1;imax1 = mem icourant;imax2 = mem imax1;icourant = mem icourant + 1;

Enfin, voici la boucle correspondant a l’equation :

res = fill<<fill bool,10>>(imax1,imax2,0).

Integer i0;Integer s ;Integer t ;Integer u ;//Initialisation des accumulateursInteger s = imax1 ;Integer t = imax2 ;Integer u = 0;

for(i0=0;i0<10;i0++)s = s;t = t;u = u;

Page 117: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

A.2 : Version originale 110

//Calcul de res et mise a jour des accumulateurs* res[i0]=(u == s ) || (u == t );s=s ;t=t ;u=u + 1;

A.2 Version originale

A titre indicatif, on trouvera ci-dessous le programme original du calcul de maximumqui donne le tableau res (represente par les variables res1 a res2), a partir du tableauA (represente par les variables elt 1 a elt 2).

node Max(elt1,elt2,elt3,elt4,elt5,elt6,elt7 : int)returns (res1,res2,res3,res4,res5,res6,res7 : bool);

varmax : int;

letmax = MAX7 R(elt1,elt2,elt3,elt4,elt5,elt6,elt7);Est max elt1 = elt1=max;Est max elt2 = (elt2=max) and Est max elt1;Est max elt3 = (elt3=max) and Est max elt2;Est max elt4 = (elt4=max) and Est max elt3;Est max elt5 = (elt5=max) and Est max elt4;Est max elt6 = (elt6=max) and Est max elt5;Est max elt7 = (elt7=max) and Est max elt6;inter1 = if(Est max elt1) then 0 else elt1;inter2 = if(Est max elt2) then 0 else elt2;inter3 = if(Est max elt3) then 0 else elt3;inter4 = if(Est max elt4) then 0 else elt4;inter5 = if(Est max elt5) then 0 else elt5;inter6 = if(Est max elt6) then 0 else elt6;inter7 = if(Est max elt7) then 0 else elt7;

max inter = MAX7 R(inter1,inter2,inter3,inter4,inter5,inter6,inter7);Est max inter1 = inter1=max inter;Est max inter2 = (inter2=max inter) and Est max inter1;Est max inter3 = (inter3=max inter) and Est max inter2;

Page 118: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

111 A : Calcul des 2 max

Est max inter4 = (inter4=max inter) and Est max inter3;Est max inter5 = (inter5=max inter) and Est max inter4;Est max inter6 = (inter6=max inter) and Est max inter5;Est max inter7 = (inter7=max inter) and Est max inter6;res1 = Est max inter1) and Est max elt1;res2 = Est max inter2) and Est max elt2;res3 = Est max inter3) and Est max elt3;res4 = Est max inter4) and Est max elt4;res5 = Est max inter5) and Est max elt5;res6 = Est max inter6) and Est max elt6;res7 = Est max inter7) and Est max elt7;

A.3 Comparaison

Nous avons compare les temps d’execution de chacun des 2 programmes (la versionLustre-V6 et la version decrite ci-dessus. Pour cela, nous les avons execute 100000000calculs de maximums avec chaque version.

Le code utilise pour la version originale est celui genere par l’outil SCADE. Pour laversion Lustre-V6, on a utilise le code produit par Lac.

En utilisant la versionLustre-V6, les 100000000 executions prennent 356 secondes.Avec la version original, ce temps d’execution atteint 768 secondes. Le gain apporte parla version V6 represente donc une diminution de moitie du temps d’execution.

Page 119: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

Bibliographie

[AC97] Equipe API-Cosi. Getting started with Alpha. IRISA, september 1997. 4.1[Bac78] J. Backus. Can programming be liberated from the von neuman style ? A

functional style and its algebra of programs. Communications of the ACM,21(8) :613–641, august 1978. :cacm :1978

[BG92] G. Berry and G. Gonthier. The Esterel synchronous programming lan-guage : design, semantics, implementation. Science of Computer Programming,19(2) :87–152, november 1992. 1.2

[Bir88] Richard S Bird. Lectures on constructive functional programming. In M. Broy,editor, Constructive Methods in Computer Science, pages 151–218. Springer-Verlag, 1988. 4.1, 4.1

[FN91] F. Rocheteau and N. Halbwachs. Pollux, A Lustre-based hardware designenvironment. In P. Quinton and Y. Robert, editors, Conference on Algorithmsand Parallel VLSI Architectures II, Chateau de Bonas, 1991. 2.3

[GAPT85] P.L. Guernic, A.Benveniste, P.Bournai, and T.Gauthier. Signal : A data floworiented language for signal processing. Technical Report IRISA report 246,IRISA, 1985. 1.2

[GLP93] Andy Gill, John Launchbury, and Simon L. Peyton Jones. A short cut to de-forestation. Technical report, University of Glasgow, October 1993. :Launch-bury :PeytonJones :glasgow :1993

[Hal93] N. Halbswachs. Synchronous Programming of Reactive Systems. Kluwer Aca-demic Press, Netherlands, 1993. 1.2

[Hal99] N. Halbwachs. Tableaux en Lustre-V6. Verimag, june 1999. 3.1[HCRP91] N. Halbwachs, P. Caspi, P. Raymond, and D. Pilaud. The synchronous data-

flow programming language LUSTRE. Proceedings of the IEEE, 79(9) :1305–1320, septempber 1991. 1.2, 2.1.2

[HR92] N. Halbwachs and F. Rocheteau. Implementing reactive programs on circuits :A hardware implementation of LUSTRE. In J. W. de Bakker, C. Huizing, W. P.de Roever, and G. Rozenberg, editors, Proceedings of Real-Time : Theory inPractice, volume 600 of LNCS, pages 195–208, Berlin, Germany, june 1992.Springer. 2.3

[JV99] P. Johann and E. Visser. Warm fusion in stratego : A case study in thegeneration of program transformation systems, 1999. 4.1, 4.2.2

[Law76] Eugene L Lawler. Combinatorial Optimization : Networks and Matroids, chap-ter 4, 6.3 and 7.11. Holt, Rinehart and Winston, New York, 1976. :Lawler76

Page 120: Compilation e cace d'iter ateurs de tableaux Lustre · 2006. 9. 7. · David, Moussa et Cyril pour avoir support´e mes humeurs lorsque je travaille, merci pour les intenses s´eances

113 BIBLIOGRAPHIE

[LS86] C. E. Leiserson and J. B. Saxe. RETIMING SYNCHRONOUS CIRCUITRY.Technical Memo MIT/LCS/TM-309, Massachusetts Institute of Technology,Laboratory for Computer Science, May 1986. 4.3, 4.3.1, 4.3.1, 4.3.2, 4.3.2

[LS95] John Launchbury and Tim Sheard. Warm fusion : Deriving build-catas from re-cursive definitions. In Conf. Record 7th ACM SIGPLAN/SIGARCH Int. Conf.on Functional Programming Languages and Computer Architecture, FPCA’95,La Jolla, San Diego, CA, USA, 25–28 June 1995, pages 314–323. ACM Press,New York, 1995. 4.2.2

[Muc97] Steven S. Muchnick. Advanced compiler design and implementation. MorganKaufmann Publishers, 2929 Campus Drive, Suite 260, San Mateo, CA 94403,USA, first edition, 1997. :1997 :ACD

[Nik91] R. S. Nikhil. ID Reference Manual. MIT Laboratory for Computer Science,90.1 edition, july 1991. 4.1

[OM92] J-P Sansonnet O. Michel, D. De Vito. 8 1/2 : Data-parallelism and data-flow.Technical report, LRI-CNRS, Universit Paris-Sud, 1992. 4.1

[Ray88] P. Raymond. Compilation spare de programmes Lustre. Master’s thesis,Institut National Polytechnique de Grenoble, 1988. 6.4

[Ray91] P. Raymond. Compilation efficace d’un langage dclaratif synchrone : le gn-rateur de code Lustre-V3. PhD thesis, Institut National Polytechnique deGrenoble, november 1991. 6.2.2, 6.4

[Ver99] Verimag. The declarative code dc. technical report, june 1999. 2.1.3.2

[Vis01] E. Visser. Stratego : A language for program transformation based on theparadigm of rewriting strategies. system description for stratego 0.5. LectureNotes in Computer Science, RTA’01 (Rewriting Techniques and Applications),may 2001. 7

[Wad84] Philip Wadler. Listlessness is better than laziness. In Conference Record ofthe 1984 ACM Symposium on Lisp and Functional Programming, pages 45–52.ACM, ACM, august 1984. :acm :lfp :1984

[Wad85] P. Wadler. Listlessness is better than laziness II : composing listless functions.In H. Ganziger and N. D. Jones, editors, Proc. Workshop on Programs as DataObjects, volume 217 of LNCS. Springer Verlag, 1985. 4.2.2

[Wad88] P. Wadler. Deforestation : Transforming programs to eliminate trees. InH. Ganzinger, editor, Proceedings of the European Symposium on Program-ming, volume 300 of Lecture Notes in Computer Science, pages 344–358. Sprin-ger Verlag, 1988. 4.2, 4.2.2

[Wat91] Richard C. Waters. Automatic transformation of series expressions into loops.ACM Transactions on Programming Languages and Systems, 13(1) :52–98,january 1991. :acm :toplas :1991