2014-10-22 0:45 GMT+02:00 Eliot Miranda <eliot.miranda@gmail.com>:
On Tue, Oct 21, 2014 at 1:02 PM, Nicolai Hess <nicolaihess@web.de> wrote:
The more I tried to change/fix the compiler and checking the failing testcases, the more I learn about it. Finally I think the compiler and testcases are mostly right and my understanding was wrong.
My (wrong) assumptions were: - the "numTemps" in the method header is always the number of declared temps, regardless whether they end up in an indirection vector
Ah, no. It is the sum of the arguments and the local temporaries. So it is the position to set the stack pointer to on activating a method.
- the inlined ifTrue: and the inlined whileTrue: blocks are handled the same way,
both assumptions are wrong: A method that starts with foo | a b c|
and all temps end up in an indirect vector has only 1 tempvar, the "indirection vector" and even "numTemps" in the method header is 1.
ifTrue and whileTrue are handled differently for example in this case
|a| a:=1. (...) ifTrue:[ ... assign to "a" ... create a block which uses "a" ]
the block only needs a copy of "a", as it is not changed after the creation of the block
Right.
|a| a:=1. [...] whileTrue:[ ... assign to "a" ... create a block which uses "a" ]
here we need a indirection vector, because the while-block *can* loop repeatedly and change the value of "a" after an block was created.
Right. In general the compiler cannot tell whether the whileTrue: will be executed 0, 1 or many times. In cases where it can tell it would take lots of machinery to do so and only be able to tell in relatively few cases. So the compiler always assumes the whileTrue: is evaluated more than once, and hence that it is possible for a block to be created and a modified in a subsequent iteration of the loop. Hence it must put a in an indirection vector.
If this is all correct, there is only one problem in this special case (my example above): If there is no assignment within the loop at all, there is no need to create a indirection vector and all used vars (a b c) can just be copied.
Or am I still confused ?!
No you're not. You get it now :-). One question is whether you can explain it all better than I did on my blog, because people seem to find this area of teh system hard and take a while to "get it".
@eliot Your blog contains all the information needed. But if someone don't have already a deep knowledge of the compiler and VM-internals, it can be a bit overwhelming. And I must admit I have overread or skipped some parts, because I thought they are not important or because I didn't understand :) And now I found the place in the (old) compiler, where the blocks in optimized loops are handled. You search for assignments in a loop and if one is found, restart the "analyseClosure" as if the write had happened after the close over. Now I need to find a way to do the same with opal compiler. It is (and looks a lot) different than the old compiler. It tags the variables with a usage marker #write, #read and an "escaping" flag. And it does only one pass over the tree. But this way, it can not distinguish between a write that happens before entering the loop from a write happening within the loop. @marcus I propese an extra usage tag #writeInLoop, that is only set on assignments within a loop. And then, mark an "escaping" var in an optimized loop only as "escapingWrite", if it is marked as "writeInLoop".
nicolai
-- best, Eliot