EPITA

Introdution à Prolog, cours n° 4

Jean-François Perrot

Génération de code pour expressions arithmétiques

  1. Préambule
    1. L'idée
    2. L'assembleur LMU
    3. Exemples
    4. Auxiliaires d'usage général
      1. Syntaxe de LMU
      2. Confection d'une liste d'instructions LMU, avec une liste différentielle
      3. Impression d'une liste d'instructions au format LMU.

  2. Le générateur de code simpliste "tout dans la pile"

  3. Le générateur raisonnable avec pile dans les registres et gestion du débordement

  4. Le générateur optimal avec calcul préliminaire du nombre de registres nécessaires
    1. Calcul du nombre minimum de registres
    2. Le prédicat maître
    3. Premier prédicat auxiliaire
    4. Second prédicat auxiliaire

Préambule

Le générateur de code simpliste "tout dans la pile"

genexp0(Exp) --> {number(Exp), !}, clmu(['LDI', 'R0', Exp]).
genexp0(Exp) --> {atomic(Exp), !}, clmu(['LDR', 'R0', Exp]).
genexp0(Exp) --> {functor(Exp, Op, 2),
                arg(1, Exp, Ag), arg(2, Exp, Ad)},
                genexp0(Ag), clmu(['PSH', 'R0']),
                genexp0(Ad), clmu(['POP', 'R1']),
                {mnem(Op, Codop)},
                clmu([Codop, 'R0', 'R1', 'R0']).
Appel par :
try0(E) :- genexp0(E, X-X, Y), vlmu(Y).

Le générateur raisonnable avec pile dans les registres et gestion du débordement

On s'autorise 4 registres. Au-delà, on "déborde" dans la pile.
On introduit donc un prédicat auxiliaire genaux1 pour avoir une définition en deux clauses,
dont la seconde traitera le débordement dans la pile

maxreg(3).         % seule manière de déclarer une constante en Prolog !

genexp1(Exp, PRL) --> {number(Exp), !, registre(PRL, RPRL)}, % PRL = Premier Registre Libre
                            clmu(['LDI', RPRL, Exp]).
genexp1(Exp, PRL) --> {atomic(Exp), !, registre(PRL, RPRL)},
                            clmu(['LDR', RPRL, Exp]).
genexp1(Exp, PRL) --> {functor(Exp, Op, 2), arg(1, Exp, Ag), arg(2, Exp, Ad),
                       mnem(Op, Codop), registre(PRL, RPRL)},
                     genaux1(Codop, Ag, Ad, PRL, RPRL).

genaux1(Codop, Ag, Ad, PRL, RPRL) --> {maxreg(MR), PRL < MR, !, % on ne déborde pas
                       PRL1 is PRL+1, registre(PRL1, RPRL1)},
                    genexp1(Ag, PRL), genexp1(Ad, PRL1),
                    clmu([Codop, RPRL, RPRL, RPRL1]).

genaux1(Codop, Ag, Ad, PRL, RPRL) --> {PRL1 is PRL-1, registre(PRL1, RPRL1)},
                clmu(['PSH', RPRL1]), % on déborde
                genexp1(Ag, PRL1), genexp1(Ad, PRL),
                clmu([Codop, RPRL, RPRL1, RPRL]),
                clmu(['POP', RPRL1]).
Appel par :
try1(E) :- genexp1(E, 0, X-X, Y), vlmu(Y).

Le générateur optimal avec calcul préliminaire du nombre de registres nécessaires

  1. Calcul du nombre minimum de registres

    Les listes de Prolog vont nous permettre de construire "au vol" une structure arborescente parallèle à l'arbre d'expression
    et portant en chacun de ses sommets le nombre minimum de registres nécessaires à la séquence de code
    qui correspond au sommet homologue de l'arbre d'expression.
    Le prédicat nmrn(Exp, Liste) contrôlant cette construction est défini ci-après.
    Sa définition récursive traduit directement la spécification :
           nmrn(E) = 1 si E est une constante ou une variable
           nmrn(Eg op Ed) =
                   soit ng = nmrn (Eg), nd = nmrn(Ed)
                      max (ng, nd) si ng =/= nd
                      nd+1 si ng = nd.

    On l'utilisera ainsi :
    genopt(Exp, PRL) :- {nmrn(Exp, A)}, genexp2(Exp, A, PRL).

    nmrn(Exp, [1]) :- number(Exp), !.
    nmrn(Exp, [1]) :- atomic(Exp), !.
    nmrn(Exp, [R | [G | D]]) :- functor(Exp, Op, 2),
                    arg(1, Exp, Ag), arg(2, Exp, Ad),
                    nmrn(Ag, G), nmrn(Ad, D), resrn(G, D, R).

    resrn([NG |_], [ND |_], R) :- NG=ND, !, R is NG+1.
    resrn([NG |_], [ND |_], NG ) :- NG>ND, !.
    resrn([NG |_], [ND |_], ND) .

    Exemple :
    ?- nmrn(x*3-(y+3-(x*(y-1))), A).
    A = [3, [2, [1], 1], 3, [2, [1], 1], 2, [1], 2, [1], 1].

  2. Le prédicat maître

    à l'arité près, identique à genexp1.
    Comme ci-devant, un auxiliaire genaux2 va gérer le débordement dans la pile.

    genexp2(Exp, ARN, PRL) --> {number(Exp), !, registre(PRL, RPRL)},
                        clmu(['LDI', RPRL, Exp]).
    genexp2(Exp, ARN, PRL) --> {atomic(Exp), !, registre(PRL, RPRL)},
                        clmu(['LDR', RPRL, Exp]).
    genexp2(Exp, [_ | [ARG | ARD]], PRL) -->   
            {functor(Exp, Op, 2), arg(1, Exp, Ag), arg(2, Exp, Ad),
            mnem(Op, Codop), registre(PRL, RPRL)},
            genaux2(Codop, Ag, Ad, ARG, ARD, PRL, RPRL).


  3. Premier prédicat auxiliaire

    L'appel récursif à genexp2 va demander un intermédiaire de plus genaux21,
    pour déterminer l'ordre d'évaluation des sous-arbres
    celui qui est le plus gournamd en registres devant être traité en premier.

    genaux2(Codop, Ag, Ad, ARG, ARD, PRL, RPRL) -->
                    {maxreg(MR), PRL < MR, !,
    % on ne déborde pas
                    PRL1 is PRL+1, registre(PRL1, RPRL1),
                    ARG = [NRG | _], ARD = [NRD | _]},
                    genaux21(Codop, Ag, Ad, ARG, ARD, NRG, NRD,
                                       PRL, RPRL, PRL1, RPRL1).


    genaux2(Codop, Ag, Ad, ARG, ARD, PRL, RPRL) -->
                    {PRL1 is PRL-1, registre(PRL1, RPRL1)},
                    clmu(['PSH', RPRL1]),
    % on déborde
                    genexp2(Ag, ARG, PRL1), genexp2(Ad, ARD, PRL),
                    clmu([Codop, RPRL, RPRL1, RPRL]),
                    clmu(['POP', RPRL1]).


  4. Second prédicat auxiliaire

    genaux21(Codop, Ag, Ad, ARG, ARD, NRG, NRD,
                                PRL, RPRL, PRL1, RPRL1) -->
                    {NRG > NRD, !},  % le sous-arbre gauche d'abord
                    genexp2(Ag, ARG, PRL), genexp2(Ad, ARD, PRL1),
                    clmu([Codop, RPRL, RPRL, RPRL1]).

    genaux21(Codop, Ag, Ad, ARG, ARD, NRG, NRD,
                                PRL, RPRL, PRL1, RPRL1) -->  % le sous-arbre droit d'abord
                    genexp2(Ad, ARD, PRL), genexp2(Ag, ARG, PRL1),
                    clmu([Codop, RPRL, RPRL1, RPRL]).