On Sun, 2007-03-11 at 17:36 +1100, skaller wrote:
> Almost done now ..

The infinite cloning problem is back somehow: reminder
of what happens:

fun B { fun C { call B } call C }
fun A { call B }

Here, B,C are mutually recursive. Felix only inlines
a recursive call if the callee is a child of the caller,
if the child calls the parent directly this should lead
to a recursive self-call: inlining C into B leaves:

fun B { call B }

But this is not what actually happens. When we inline B
into A we first get:

fun A { fun C' {call B} call C' }

and inlining the call to C' we get

fun A { call B }

which is right back where we started. The problem is that
C' is a clone of C, reparent to belong to A. It calls B,
which is not its parent .. A is its parent. So the call
can be inlined and we get an infinite loop.

When the call to B is a tail call, I think this
is handled: B is optimised to 

fun B { call B }

first, and if that's a tail call replaced by a goto. That
happens before B is inlined into A. A realistic example:

fun B { fun C { c1; call B; c2; } b1; call C; b2; }

will result in

fun B { b1; c1; call B; c2; b2; }

So now, when A inlined B, it still doesn't work:

fun A { b1; c1; call B; c2; b2; }

and it repeats. Now this case is actually blocked from an 
infinite recursion because it results in a self-call,
but if the recursion is via a sibling this will not
happen YET. Instead, Felix doesn't inline yet, because
recursive calls to a sibling aren't inlined.

The problem is back at the original example now,
where we have failed for some reason to reduce to a self-call,
then the cloning process leaves the recursive call pointing
at the original uncloned target B, and the recursion manifiests
by infinite unfolding: yet none of the unfolding calls are
recursive because when inlining the recursion is unfolded.

Just to be clear: when you inline a function, you are
'reparenting' its code and children (variables and nested
functions) to the caller. Reparenting specialises the
children both over type variables and value arguments,
and the reparented function generally refers to reparented
variables.

The exceptions are: calls to a common ancestor or ancestors
children, for example library functions -- this always includes
all globals. IN particular note B above is a global, so the
interior call to it within C is NOT remapped -- it actually
CANNOT be remapped because it would have to call C' parent
which is A, clearly the wrong thing. EXCEPT if it is a tail
call in which case it can call B' by jumping to the start
of the B' code inlined into A.

I have no serious idea how to stop this clone spawning fest
at the moment .. if anyone can suggest an algorithm
it would be interesting.


-- 
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to