[mercury-users] mmc --optimize-constructor-last-call

Michael Day mikeday at yeslogic.com
Sun Jan 4 22:19:33 AEDT 2009


Okay, things start to get interesting if I combine the --structure-reuse 
and --optimize-constructor-last-call options. I start with this code, 
which is almost tail-recursive but not quite:

filter_neg([], []).
filter_neg([X|Xs], Ys) :-
     ( if X < 0 then
         Y = 0
     else
         Y = X
     ),
     filter_neg(Xs, Ys0),
     Ys = [Y|Ys0].

run Mercury with the following options:

  --grade=hlc.gc -O5 --structure-reuse --optimize-constructor-last-call

and get four procedures for the predicate:

  ctgc__pred__LCMCpr_filter_neg_1__0__0_2_p_0
  ctgc__pred__filter_neg__0__0_2_p_0
  LCMCpr_filter_neg_1_2_p_0
  filter_neg_2_p_0

It's duplicating ctgc and non-ctgc procedures again, even though based 
on their being only one mode for the predicate I can't see when you 
would want to call the non-ctgc one, which is the only one actually 
getting called by the test program.

Looking at the generated code, the ctgc combined with constructor last 
call optimisation seems to be getting closer to ideal:

void filter_neg(Word Xs, Word * Ys)
{
     if (Xs == 0)
     {
         *Ys = 0;
     }
     else
     {
         Integer X = (Integer) field(tag(1), Xs, 0);
         Word Xs0 = (Word) field(tag(1), Xs, 1);
         Integer Y;
         Word * AddrYs0;

         if (X < 0)
           Y = 0;
         else
           Y = X;

         *Ys = (Word) Xs;
         field(tag(1), *Ys, 0) = Y;
         field(tag(1), *Ys, 1) = AddrYs0;

         filter_neg_LCMC(Xs0, AddrYs0);
     }
}

void filter_neg_LCMC(Word Xs, Word * AddrOfPrevYs0)
{
     while (TRUE)
     {
         if (Xs == 0)
         {
             *AddrOfHeadVar__2_10 = 0;
             break;
         }
         else
         {
             Integer X = (Integer) field(tag(1), Xs, 0);
             Word Xs0 = (Word) field(tag(1), Xs, 1);
             Integer Y;
             Word * AddrYs0;

             if (X < 0)
               Y = 0;
             else
               Y = X;

             field(tag(1), Xs, 0) = Y;
             field(tag(1), Xs, 1) = AddrYs0;

             *AddrOfPrevYs0 = Xs;
             AddrOfPrevYs0 = AddrYs0;
             Xs = Xs0;
         }
     }
}

No allocations, and it's a tail-recursive loop. There are still some 
unnecessary copies, but it's looking pretty good.

However, I don't understand how the last call optimisation is works, in 
particular these three lines of filter_neg:

         Word * AddrYs0;

         field(tag(1), *Ys, 1) = AddrYs0;

         filter_neg_LCMC(Xs0, AddrYs0);

That would seem to be assigning an unset variable to the tail of the Ys 
cons cell, then passing in that random value to the loop procedure.

Shouldn't it be doing the assignment the other way around, passing in 
the address of the second field of Ys0, something like this:

         AddrYs0 = &(field(tag(1), *Ys, 1);

I really can't see how the current code could work, but since it's not 
being called in practice perhaps it doesn't matter (?) Oh hang on, this 
dodgy code is only generated for the ctgc versions of the procedure, the 
non-ctgc versions have the assignment the right way around.

So that's a bug report, these two optimisations do not appear to play 
nicely with each other in rotd-2008-01-30. I'll copy to mercury-bugs.

Cheers,

Michael

-- 
Print XML with Prince!
http://www.princexml.com
--------------------------------------------------------------------------
mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the users mailing list