I have an idea roughly what's happening, but i need to work through
it with the lurkers to pinpoint the problem. So ..

First, Felix eliminates unused variables, and that's essential,
rather than an optimisation. For example:

var windows_version = winver();
var linux_version = linver();
var osx_version = osxver();
...
println$ osx_version;

In this program I am running OSX, so this will work.
If you're running Linux the program will stuff up, because
the function "osxver()" won't work on Linux. This is what we
want.

So clearly, windows_version and linux_version must be eliminated
to get rid of their initialisers, otherwise if that stuff is in the library
then NO program will work!

Here's another example:

        var thread_pool = create_thread_pool();
        // not used

I'm not using the thread_pool so we want to eliminate the variable
to get rid of the creator.


Second. Felix does the elimination with a very poor algorithm.
It collects all the used symbols, and copies them to a new
symbol table. So if you have

        var a = 1;
        var b = a;
        var c = b;

and c is not used, c is eliminated. But b is used so it is kept.
So Felix does the symbol garbage collection AGAIN.
This time b is eliminated but a is kept. So Felix does the
garbage collection AGAIN. This time a is eliminated.
Felix then does the collection AGAIN. This time nothing
is eliminated so it's finished. This is extremely inefficient,
because it's done globally over the whole program, and it's
done after a large number of optimisations (i.e. not just
once!). The algorithm could be made more efficient: one pass
would be enough, if one recognized the "result" expressions:
the return values of a function, for example, or any value
output, and used them as "roots". 

In any case, complete elimination of unused variables is essential.
Note carefully assigning the result of a generator with side effects
to an unused variable WILL eliminate the variable and the generator
invocation! It's not a bug! It's MEANT to do that!

Third. Now the nitty gritty, problem number ONE.

What's "use" mean????

In theory this is simple. It means the variable is read.

If the variable is a structure, then we can make do with any
part being read (it would be better to eliminate unread parts
but that's tricky!)

This means in a simple assignment:

        a = b

then b is used but a is not. Writing isn't use.
What about read/modify;wr9te:

        ++i;

Nope. That's not a use because the value is only read for the purpose
of writing a different value. however here:

        x = i++

variable i is used. So now consider this:

        a . i . mem = 1

here, i is used because it is read. Only a is written (mem is a field name
so it isn't  a variable). Usually, everything on the LHS of an assignment is
"used" except the "top level lvalue". Of course this is a little tricky because
its actually nested:

        get (get (a, i), mem)

so we would have to carefully analyse the LHS of an assignment to find
all the non-lvalues.

But remember "in principle" Felix doesn't have any assignments.
It uses pointers instead,. So if we do

        (&x) <- a

we have to decide x is not used. But this is bad because

        var px = &x;
        px <- a;

Here px is used, it's read to calculate where to store a. So we have to decide
x i used as well, even though it is only addressed, not read. Once we have
a pointer to a variable, we don't know how the pointer is going to be used,
so if the pointer is used at all, the variable has to be considered used.
[In general, aliasing etc means the alternative is data flow analysis]

So in general, if the address is taken in the LHS of a <- operator,
that's NOT a use, provided its the "innermost" pointer. For example:

        (&x) . (*&y) <- 1

here y is used! But x is not. 

I suspect Felix is getting this wrong, but I'm not sure.
At present the code says: the LHS is not checked for 
usage if it's a simple variable or a projection BEXPR_get_n.
[That handles tuple indices, and maybe some arrays,
and I suspect record and struct components too]
In the array case, with a integer variable index I think it's
forgetting to consider the index as being used.
The result is an exception being thrown and a hack in the
compiler just eliminated the whole assignment: the hack
is to allow just "deleting" unused variables. The hack shouldn't
be needed now that horrible inefficient symbol garbage collector
is being used. So that's possible error 1, though I'm not confident
because I know the index variables i,j using in nbody are counted
as used anyhow (they're used on the RHS too)

Now for the NEXT problem. Lazy evaluation.

Felix can replace a variable with its value.
It does this even for projections. For example

        var x = 1,2;
        var y = x.0;
        var z = x.1;

may well produce:

        var y = (1,2).0;
        var z = (1,2).1;

In this case, that would lead to 
        
        y = 1;
        z = 2;

which is nice. However, here:

        var a = 1,1,1,1,1 .... 1; // 1000 times
        for i in 0 upto 900 do
                print a.i, a.(i+1) .... a. (i+99); // 100 times
        done

it would be a disaster because you'd get 100 copies of
the 1000 values.

But that's just slowness. The real disaster would be if
Felix did this kind of substitution on the LHS of an assignment:

        a . i = 1;

WOOPS! If we replace a with a value here we'd be "addressing
an rvalue" on the assignment and the modification would just
get lost.

However, again this only applied to the "lvalue" variable.
It's possible this is the bug too.

OK, so why not eliminate assignments altogether?
After all I've been trying to do that for some time.

Well, there's a reason. Consider:

        var x = expr;

If we do:

        var x : typeof(expr);
        set (&x, expr);

and "set" is an arbitrary procedure, we cannot use the value
of x in place of x (because we don't know that it is "expr").
If we use an intrinsic

        &x <- expr

we can special case it. Note that vals are often represented
by variables too, however the initial assignment is given by
BEXPR_init, not BEXPR_assign. Of course we could use
assignment for vals (just because the user can't take the address
doesn't mean the compiler can't :)

SO there we have it. Two possible sources of the bug:

(a) failing to count something as used that should be
(b) replacing an lvalue by its initial value in an assignment

I really can't think of anything else. I do know, it is NOT assigning
the value.

--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Free Next-Gen Firewall Hardware Offer
Buy your Sophos next-gen firewall before the end March 2013 
and get the hardware for free! Learn more.
http://p.sf.net/sfu/sophos-d2d-feb
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to