• Aucun résultat trouvé

Expression template au delà de l arithmétique

N/A
N/A
Protected

Academic year: 2022

Partager "Expression template au delà de l arithmétique"

Copied!
27
0
0

Texte intégral

(1)

Expression template au delà de l’arithmétique

19 / 06 / 2002

Francis MAES

maes_f@epita.fr

(2)

Expression template au dela de l’arithmétique

I Introduction II Préliminaires III Implémentation IV Exemple

V Conclusion

(3)

I.1 Introduction: le Tiger

let

type list = { head: int, tail: list } function read_list (size : int) : list =

if size > 0 then list {head = read_int (), tail = read_list (size - 1)} else nil var the_list := read_list (5)

var infinite := 2147483647 /* 2 ^ 31 - 1 */

function min (l : list) : int =

let function min_ (a : int, b : int) : int = if a < b then a else b

in

if l = nil then infinite else min_ ( l.head, min (l.tail) ) end

in

print_int (min (the_list) ) end

Langage introduit par Andrew Appel, dans [1]

(4)

I.2 Introduction: compilation

code Tiger

arbre de syntaxe abstraite en C++ statique

Représentation(s) intermédiaire(s)

Assembleur executable

•lexeur

•parseur compilation Tiger compilation Tiger

génération de code

(simple) méta-compilation C++:

instançiations de templates, inline de fonctions

arbre de syntaxe abstraite

Représentation(s) intermédiaire(s) C++

compilation C++

génération de code

(très complexe)

code C++

complexe

(5)

I.3 Introduction: arbre de syntaxe abstraite

(a + b * 3) / c

/ +

*

c a

b 3

(6)

I.4 Introduction: expression template

FloatArray100 a, b, c;

d = (a + b * 3) / c;

Binop< Binop< Var, Binop< Var, Const, Times>, Plus>, Var, Div >

méta-compilation for (unsigned i = 0; i < Size; ++i) d[i] = (a[i] + b[i] * 3) / d[i]

template<class T_left, T_right, T_op>

struct Binop {

inline float eval(unsigned i);

};

struct Const

{ inline float eval(unsigned i);

};

Technique introduite par

Todd Veldhuizen dans [3]

(7)

I.5 Introduction: au dela des expressions templates

• if a < 6 then square(b) else 1

If< Binop< Var, Const<6> , Less>, Square <Var>, Const<1> >

• Pas de typage

• Pas de déclaration

• Pas de fonctions

• Pas de structures de contrôle...

(8)

II.1 Préléminaires: élements du langage Tiger

• Déclarations:

– variables – types – fonctions

• Expressions:

– arithmétique

– accès aux variables – structure de controle

– instançiations de tableaux et enregistrements

– appel de fonctions

(9)

II.2 Préléminaires: quelques exemples...

/* déclaration et usage de variables */

let

var i := 50 var j := 1

in i + j

end

/* déclaration et usage de types */

let

type int32 = int

type entry = {num: int32, desc: string}

var e := entry {num = 505, desc = "smousse"}

in

() end

LetInEnd<T_decs, T_exps >

Decs< ? >

VarDec < ? > VarDec < ? >

Binop<T_left, T_right, T_op>

Var< ? > Var < ? > Plus

(10)

II.3 Préléminaires: quelques exemples...

/* déclaration et usage de fonctions */

let

function double(x : int) : int = 2 * x function inc(x : int) : int = x + 1 in

double(30) - inc(8) end

on doit pouvoir:

• déclarer des types, variables et fonctions

• accéder à ces éléments...

• …via un mécanisme d’identification

(11)

II.4 Préléminaires: déclarations en Tiger

• structure de déclaration : let…in…end

• équivalence :

let

function f2 = ...

function f1 = … type t1 = … type t2 = … type t3 = ...

var v1 = ...

var v2 = ...

in

...

end

let

function f1 = … function f2 = ...

in let

type t1 = … type t2 = … type t3 = ...

in let

var v1 = ...

var v2 = ...

in

...

(12)

II.5 Préléminaires: déclarations et environnement

• Block de déclaration (chunk): ensemble de déclarations successives de même nature.

• Environnement: ensemble de chunks actifs

à un point donné du programme.

(13)

II.6 Préléminaires: opérations sur l’environnement

• Initialisations: builtins

• Let…in…end

– empilage d’un chunk

• Appel de fonction

– dépilage des chunks situés entre la déclaration et l’appel – empilage du chunk décrivant les paramètres formels

• Identification et Extraction : paire d’entiers

(14)

III.1 Implémentation: liste statique

struct EmptyList {

enum {size = 0};

};

template<class T_head, class T_tail = EmptyList>

struct List {

enum {size = 1 + tail::size};

typedef T_head head;

typedef T_tail tail;

};

typedef List<int, List<float, List<char> > > foo_t;

(15)

III.2 Implémentation: opération sur les listes statiques

• Sous-liste: template<class T_list, unsigned N>

struct ListSub {

typedef typename ListSub< typename T_list::tail, N - 1>::T res;

};

template<class T_list>

struct ListSub<T_tlist, 0>

{

typedef T_list res;

};

//example : typedef typename ListSub<foo_t, 2>::res bar_t ;

• Extraction: template<class T_list, unsigned N>

struct ListGet {

typedef typename ListSub<T_list, N>::head res;

};

//example : typedef typename ListGet<foo_t, 2>::res bar_t;

(16)

III.3 Implémentation: classes de types

• En Tiger toutes les variables font 4 octets.

• Un type doit pouvoir créer, détruire, assigner et comparer ses instances.

• Un type peut avoir besoin de l’environnement.

typedef void* var_t;

struct Type {

template<class T_env>

struct eval {

void create(var_t& v);

void destroy(var_t v);

void assign(var_t& left, var_t right);

int compare(var_t left, var_t right);

};

(17)

III.4 Implémentation:

déclarations

• déclaration de variables:

– Variable <class T_init_exp, unsigned TyChunk, unsigned TyNum>

• déclaration de fonctions:

– Function <class T_formal_list, class T_exp, unsigned ChunkLevel>

• déclaration de types:

– TypeLnk <unsigned TyChunk, unsigned TyNum>

– ArrayType <unsigned TyChunk, unsigned TyNum>

– RecordType <class T_fields_type_list>

– IntType

– StringType

(18)

III.5 Implémentation: classes d’expressions

• Une expression doit pouvoir évaluer son type.

• Une expression doit pouvoir évaluer sa valeur.

• Une expression peut

– avoir besoin de l’environnement.

– modifier l’environnement.

struct Exp {

template< class T_env>

struct eval {

typedef ... T;

var_t doit ();

};

};

(19)

III.6 Implémentation: exemples d’expressions

• ConstInt: template<signed Value>

struct ConstInt {

template<class T_env>

struct eval {

typedef IntType T;

var_t doit () {return Value;}

};

};

• LetInEnd:

(simplifié)

template<class T_dec_chunk, class T_seq_exp>

struct LetInEnd {

template<class T_env>

struct eval {

typedef List< T_dec_chunk, T_env> T_new_env;

typedef typename T_seq_exp::eval<T_new_env>::T T;

var_t doit ()

{ return T_seq_exp::eval<T_new_env>::doit();

}

};

(20)

III.7 Implémentation:

expressions

• arithmétique et constantes:

– BinOp<class T_exp_left, class T_exp_right, class T_op>

– ConstInt<signed Value>

– ConstString<unsigned Index>

• accès aux variables:

– SimpleVar<unsigned Chunk, unsigned Num>

– FieldVar<class T_lvalue, unsigned FieldNum>

– SubscriptVar<class T_lvalue, class T_exp>

– Assign<class T_lvalue, class T_exp>

• déclarations et appels de fonctions:

– LetInEnd<class T_dec_chunk, class T_seqexp>

– FuncCall<unsigned Chunk, unsigned Num, class T_param_list>

(21)

III.7 Implémentation:

expressions

• instanciations:

– Record<unsigned TyChunk, unsigned TyNum, class T_exp_list>

– Array<unsigned TyChunk, unsigned TyNum, class T_size, class T_init>

• structures de contrôle:

– If<class T_cond, class T_exp_then, class T_exp_else = Void>

– While<class T_cond, class T_exp>

– For<unsigned BlockID, unsigned VarID, class T_init, class T_end, class T_exp>

– Break

– ExpList<class T_first, class T_next = Void>

(22)

III.8 Implémentation: Stockage et accès aux variables

• On aimerait stocker les variables sur la pile du programme.

• Tiger possède la structure de blocs.

let

var a := 51 var b := 86

function f(c : int) : int = let

function g(d : int) : int = a + b + c + d

in g(1) end in

f(2) end

Chunk 0: int a int b

Chunk 2: int c

Chunk 4: int d

Chunk 1: (function f)

Chunk 3: (function g) Chunk -1: Tiger builtins

&a NULL

&c NULL

&d

Environnement Stack

(23)

IV.1 Exemple: code Tiger

/* A program to solve the 8-queens problem */

let

var N := 8

type intArray = array of int var row := intArray [ N ] of 0 var col := intArray [ N ] of 0

var diag1 := intArray [N+N-1] of 0 var diag2 := intArray [N+N-1] of 0 function printboard() =

(for i := 0 to N-1 do (for j := 0 to N-1

do print(if col[i]=j then " O" else " .");

print("\n"));

print("\n"))

function try(c: int) = if c=N

then printboard() else for r := 0 to N-1

do if row[r]=0 & diag1[r+c]=0 & diag2[r+7-c]=0 then (row[r]:=1; diag1[r+c]:=1; diag2[r+7-c]:=1;

col[c]:=r;

try(c+1);

row[r]:=0; diag1[r+c]:=0; diag2[r+7-c]:=0) in

try(0)

end

(24)

IV.2 Exemple: code C++ généré.

/* generated tiger->c++ code */

#include "all.h"

using namespace metasmousse;

typedef LetInEnd< TList< Variable< ConstInt< 8 >, builtin_types, 1 > >, LetInEnd< TList< ArrayType< builtin_types, 1 > >,

LetInEnd< TList< Variable< Array< 1, 0, SimpleVar< 0, 0 >, ConstInt< 0 > >, 1, 0 >, TList< Variable< Array< 1, 0, SimpleVar< 0, 0 >, ConstInt< 0 > >, 1, 0 >, TList<

Variable< Array< 1, 0, BinOp< BinOp< SimpleVar< 0, 0 >, SimpleVar< 0, 0 >, Plus >, ConstInt< 1 >, Minus >, ConstInt< 0 > >, 1, 0 >, TList< Variable< Array< 1, 0, BinOp< BinOp< SimpleVar< 0, 0 >, SimpleVar< 0, 0 >, Plus >, ConstInt< 1 >, Minus >, ConstInt< 0 > >, 1, 0 > > > > >,

LetInEnd< TList< Function< TList< >, ExpList< For< 5, 0, ConstInt< 0 >, BinOp< SimpleVar< 0, 0 >, ConstInt< 1 >, Minus >, ExpList< For< 6, 0, ConstInt< 0 >, BinOp< SimpleVar< 0, 0 >, ConstInt< 1 >, Minus >, FuncCall< builtin_funcs, 0, TList< If< BinOp< SubscriptVar< SimpleVar< 2, 1 >, SimpleVar< 5, 0 > >, SimpleVar< 6, 0 >, Equal >, ConstString< 0 >, ConstString< 1 > > > > >, ExpList< FuncCall< builtin_funcs, 0, TList< ConstString< 2 > > > > > >, ExpList<

FuncCall<builtin_funcs, 0, TList< ConstString< 3 > > > > >, 3 >, TList<

Function< TList< TypeLnk< builtin_types, 1 > >, If< BinOp< SimpleVar< 4, 0 >, SimpleVar< 0, 0 >, Equal >, FuncCall< 3, 0, TList< > >, For< 5, 0, ConstInt< 0 >, BinOp<SimpleVar< 0, 0 >, ConstInt< 1 >, Minus >, If< If< If< BinOp< SubscriptVar< SimpleVar< 2, 0 >, SimpleVar< 5, 0 > >, ConstInt< 0 >, Equal >, BinOp<

SubscriptVar<SimpleVar< 2, 2 >, BinOp< SimpleVar< 5, 0 >, SimpleVar< 4, 0 >, Plus > >, ConstInt< 0 >, Equal >, ConstInt< 0 > >, BinOp< SubscriptVar<

SimpleVar< 2, 3 >, BinOp< BinOp< SimpleVar< 5, 0 >, ConstInt< 7 >, Plus >, SimpleVar< 4, 0 >, Minus > >, ConstInt< 0 >, Equal >, ConstInt< 0 > >, ExpList<

Assign< SubscriptVar< SimpleVar< 2, 0 >, SimpleVar< 5, 0 > >, ConstInt< 1 > >, ExpList< Assign< SubscriptVar< SimpleVar< 2, 2 >, BinOp< SimpleVar< 5, 0 >, SimpleVar< 4, 0 >, Plus > >, ConstInt< 1 > >, ExpList< Assign< SubscriptVar< SimpleVar< 2, 3 >, BinOp< BinOp< SimpleVar< 5, 0 >, ConstInt< 7 >, Plus >, SimpleVar< 4, 0 >, Minus > >, ConstInt< 1 > >, ExpList< Assign< SubscriptVar< SimpleVar< 2, 1 >, SimpleVar< 4, 0 > >, SimpleVar< 5, 0 > >, ExpList< FuncCall<

3, 1, TList< BinOp<SimpleVar< 4, 0 >, ConstInt< 1 >, Plus > > >, ExpList< Assign< SubscriptVar< SimpleVar< 2, 0 >, SimpleVar< 5, 0 > >, ConstInt< 0 > >, ExpList< Assign< SubscriptVar<SimpleVar< 2, 2 >, BinOp< SimpleVar< 5, 0 >, SimpleVar< 4, 0 >, Plus > >, ConstInt< 0 > >, ExpList< Assign< SubscriptVar<

SimpleVar< 2, 3 >, BinOp< BinOp< SimpleVar< 5, 0 >, ConstInt< 7 >, Plus >, SimpleVar< 4, 0 >, Minus > >, ConstInt< 0 > > > > > > > > > > > > >, 3 >> >, ExpList< FuncCall< 3, 1, TList< ConstInt< 0 > > > > > > > >

program_t;

const char* metasmousse::const_string[] = {" O", " .", "\012", "\012",NULL};

int main() {

return (int)program_t::eval< TList<> >::doit();

(25)

IV.3 Exemple: exécution du programme.

• Temps sur un Athlon 1 gHz:

– parsing + vérification de types + génération du code: moins de 1 s.

– méta-compilation et compilation C++: 10 s – exécution: immédiat

• Exécution:

>> ./queens O . . . . . . . . O . . . . . . O . . . O . . . . O . . . . . . . . O . . O . . . . . . . O . . . .

[...]

[...]

. . . O . . . O . . . . O . . . . . . O . . . . . . . . O . . . O . . . . . . . O . . . . . O . . .

>>

(26)

V Conclusion

• 100% du Tiger converti en C++

• Code de génération simple (et sans intérêt)

• Programme obtenue efficace

• Nouveaux traitements facilement implémentables:

– auto-affichage du programme

– affichage d’info. de debuggage

– statistiques d’exécutions

(27)

Références

• [1] Andrew W. Appel, "Modern Compiler Implementation in C/Java/ML", Cambridge University Press, 1997

• [3] T. Veldhuizen, “Techniques for Scientific C++”, http://osl.iu.edi/~tveldhui/papers/techniques/

• [2] T. Veldhuizen, "Expression Templates", C++ Report,

Vol. 7 No. 5 June 1995, pp. 26-31

Références

Documents relatifs

Records a debug message on the stack, and prints it to STDOUT (or actually $DEBUG_FH, see the GLOBAL VARIABLES section below), if the VERBOSE option is true.. The VERBOSE

The policy map cust-policy specifies average rate shaping of 384 kbps and assigns the service policy cust1-classes to the class cust1. The policy map cust-policy specifies peak

B 15 Apr-76 (Level 1: Requirements) Descri.bes the primary AC power character ~stics normally provided at utilization points of major distribution networks and

Order lio. Intended for use by supervisol's and operators.. ELMFWAV-OP-OOAQ Revision A Date: a1-Aug-aO Abstract: DeS&lt;:lribes operating procedures for tne Solder

[ J Active - Mechanical or Electrical change of state is required to occur for the component to perform its safety function.. I X ] Passive - Change of state is not required for

Capstan Tacho Pulse A is erroneously seL at or i t remains at '0' for one cycle duriag high speed rotation.. After replacement, connect the

Records a message on the stack, and prints it to STDOUT (or actually $MSG_FH, see the GLOBAL VARIABLES section below), if the VERBOSE option is true.. The VERBOSE option defaults

Returns a boolean indicating whether the package is a known third-party module (i.e. it's not provided by the standard Perl distribution and is not available on the CPAN, but on