diff --git a/test/should_work/appli_para_pre.lus b/test/should_work/appli_para_pre.lus new file mode 100644 index 0000000000000000000000000000000000000000..91e04523f14e43c7f453c6521e91374926324462 --- /dev/null +++ b/test/should_work/appli_para_pre.lus @@ -0,0 +1,223 @@ + +(* +partage du boulot entre : +- CGEN: le compilo 'classique' Lustre, indépendant d'un choix + d'implem parallele particilier ; l'idée générale + est d'avoir un code à 'trous' que le générateur de glue 'para' doit remplir. + TODO ce code peut être à base de : + - fonctions (le 'collage' se fait dynamiquement) + - macros (le collage PEUT se faire à compile-time) + => on regarde les 2 solutions, tant qu'on a pas fait de choix on + parle de 'hook' sans prciser si c'est un fonction ou une macro +- PGEN: le générateur de glue 'parallele' qui récupère les infos + du compilo est remplit les trous suivant le mode de parallelisme + choisi + +IMPORTANT: Les nodes utilisés dans un 'para' DOIVENT être compilés +en mode '-2ch', i.e. : +- passage de paramètre via le contexte +- step avec un seul argument (le pointeur sur l'instance) +Pour simplifier ici, on compile tout en '-2ch' +IMPORTANT: Ici on compile en --no-prefix pour avoir du code + lisible +*) + +node D(x: int) returns (o: int); +let + o = 0 -> (x - pre x) / 2; +tel + +node A(x: int) returns (o: int); +let + o = x + (0 -> pre o); +tel + +node C(x, y: int) returns (o: int); +let + o = 0 -> pre (x + y); +tel + + +(* +D, A, C n'ont pas de para, on génère le code classique : +- struct: 'D_ctx_type' (avec champs x i(in) et o (out)) +- step: void D_step(D_ctx_type* ctx) + +Si A ou D sont utilisé par ailleurs dans un 'para' on a besoin d'une interface +'para' générique abstraite, que le PGEN devra défénir : +- un type abstrait 'D_TASK' (une valeur de base, e.g. un entier, un pointeur + qui identifie de manière unique l'instance de la task) +- un hook + D_TASK_INIT() +qui renvoie une valeur de type 'task_D' qui sera utilisée dans tout les autres hook +- un hook par input, ici + D_TASK_SETIN_x(tD, v) +- 2 hooks + D_TASK_START(tD) + D_TASK_JOIN(tD) +- un hook par output, ici + D_TASK_GETOUT_o(tD, v) +- un hook + D_TASK_RESET_D(tD) +*) + + +node B(x: int) returns (o: int); +var l, d : int; +let + l = A(5 * x - 12); + d = %MT:task1% D(x); --para + o = 3 * d - l; +tel + +(* +B contient une instance para de D : +- dans B_ctx_type, au lieu de réserver un + un contexte séquentiel classique de type 'D_ctx_type', + on réserve un 'D_task' + +typedef struct { + /*INPUTS*/ + _integer x; + /*OUTPUTS*/ + _integer o; + /*INSTANCES*/ + D_TASK D_TASK_tab[1]; + A_ctx_type A_ctx_tab[1]; +} B_ctx_type; + + +- WARNING en séquentiel, on a une seule fonction 'reset' + qui sert de 'init', en para il faut les DEUX ! + - init qui doit être appelée un seule fois au début + - reset qui peut être appelé n'imoprte quand pour remattre le temps à 0 + +void B_ctx_reset(B_ctx_type* ctx){ + int _i; + D_TASK_RESET_D(tx->D_TASK_tab[0]) + A_ctx_reset(&ctx->A_ctx_tab[0]); +} + +void B_ctx_init(B_ctx_type* ctx){ + int _i; + ctx->D_TASK_tab[0] = D_TASK_INIT(); + B_ctx_reset(ctx); +} + +La génération du step (le tri topo) est modifiée pour placer +correctement les appels des hooks : + + +void B_step(B_ctx_type* ctx){ + _integer _X_5; + _integer _X_4; + _integer _X_3; + _integer l; + _integer d; + + // tri topo -> on lance D_task au plus tôt + //n.b. avant: ctx->D_ctx_tab[0].x = ctx->x; + D_TASK_SETIN_x(&ctx->D_TASK_tab[0], ctx->x;) + D_TASK_START(ctx->D_TASK_tab[0]); + + + _X_3 = 5 * ctx->x; + _X_4 = _X_3 - 12; + ctx->A_ctx_tab[0].x = _X_4; + A_step(&ctx->A_ctx_tab[0]); + l = ctx->A_ctx_tab[0].o; + + //n.b. avant: + //D_step(&ctx->D_ctx_tab[0]); + //d = ctx->D_ctx_tab[0].o; + D_TASK_JOIN(ctx->D_task_tab[0]); + D_TASK_GETOUT_o(d); + //WARNING: c'est une version 'macro' + // il y a un choix à faire, e.g. + // peut-etre D_TASK_GETOUT_o(&d), + // voire d = D_TASK_GETOUT_o() + + _X_5 = 3 * d; + ctx->o = _X_5 - l; + +} // End of B_step + +N.B. Pour la compil modulaire, les nodes qui utilisent +B DOIVENT SAVOIR QUE B 'utilise une D_task +*) + +node appli_para_pre( + z, y : int +) returns ( + o : int +); +var a, b1, b2: int; +let + a = A(z); + b1 = B(y); + b2 = B(b1); + o = C(a,b1); +tel + +(* +top utilise un 'para', donc on créé une A_task (comme pour B avec sa task D) +de plus il 'hérite' des tasks des 2 instances de B + +typedef struct { + /*INPUTS*/ + _integer x; + _integer y; + /*OUTPUTS*/ + _integer o; + /*INSTANCES*/ + B_ctx_type B_ctx_tab[2]; + A_TASK A_TASK_tab[1]; +} top_ctx_type; + +void top_ctx_reset(top_ctx_type* ctx){ + int _i; + + B_ctx_reset(&ctx->B_ctx_tab[0]); + B_ctx_reset(&ctx->B_ctx_tab[1]); + A_TASK_reset(&ctx->A_TASK_tab[0]); +} + +void top_ctx_init(top_ctx_type* ctx){ + int _i; + + B_ctx_init(&ctx->B_ctx_tab[0]); + B_ctx_init(&ctx->B_ctx_tab[1]); + &ctx->A_TASK_tab[0] = A_TASK_init(); + top_ctx_reset(ctx); +} + +void top_step(top_ctx_type* ctx){ + _integer a; + _integer b1; + _integer b2; + + //avant: + //ctx->A_ctx_tab[0].x = ctx->x; + //A_step(&ctx->A_ctx_tab[0]); + A_TASK_SETIN_x(&ctx->A_TASK_tab[0], ctx->x;) + A_TASK_START(ctx->A_TASK_tab[0]); + + ctx->B_ctx_tab[0].x = ctx->y; + B_step(&ctx->B_ctx_tab[0]); + b1 = ctx->B_ctx_tab[0].o; + + ctx->B_ctx_tab[1].x = b1; + B_step(&ctx->B_ctx_tab[1]); + b2 = ctx->B_ctx_tab[1].o; + + //avant: + //a = ctx->A_ctx_tab[0].o; + A_TASK_JOIN(ctx->A_TASK_tab[0]); + A_TASK_GETOUT_o(a); + + C_ctx.x = a; + C_ctx.y = b1; + C_step(); + ctx->o = C_ctx.o; + +} +*)