freenode/#clasp - IRC Chatlog
Search
1:00:37
karlosz
so we probably need a new hir instruction that denotes a return to an out of scope tag
1:01:03
karlosz
just so that inlining can wire itself to some sort of error when it meets an illegal return
4:00:09
beach
karlosz: Wouldn't the escape analysis prevent inlining in those cases so that the infinite loop is avoided?
4:06:51
karlosz
beach: how so? the inliner inlines something like (block nil (funcall () (return nil)) fine
4:11:32
beach
In those cases, the environment of the LAMBDA can not be allocated in the parent, which is one of the criteria for inlining.
4:12:26
Bike
yeah, i thought the thing ruled that out now that the continuation is explicitly in a variable
4:13:33
beach
If the environment of the callee can not be allocated in the caller, then the callee can not be inlined.
4:14:43
beach
Conservatively, then, when the environment of the callee is captured and escapes in some way that we can not determine to be safe, then we must conclude that the environment of the callee can not be allocated in the caller.
4:15:04
Bike
karlosz: i mean that's fine, but the inliner is too conservative to notice, or ought to be
4:16:29
Bike
karlosz: functions that return like that are closures (this is another reason i added catch-instruction)
4:17:34
beach
karlosz: Sure, in this case it could be inlined. But we need to come up with criteria that work for every possible case. And if we need to be a bit conservative so that this particular case is ruled out, then that's just too bad.
4:17:52
Bike
i'm saying that i expected the inlining criteria that currently exist to rule out inlining that example even though it is obviously possible
4:18:55
karlosz
the trapper criterion that is already there doesnt care about the the function being inlined escaping, but only about subfunctions capturing its environment escaping
4:19:13
karlosz
so it amkes sense that with nly one level of nesting the trapper criterion doesnt even come into play
4:20:04
beach
Also, in this case, at some point we should include the knowledge that FUNCALL does not capture its argument in some arbitrary way.
4:20:45
Bike
it does inline closures, just as long as the closure doesn't let the environment escape
4:21:10
karlosz
yeah, otherwise it wouldnt even make sense to have a method on inline, which there clearly is
4:26:54
karlosz
it wasn't very hard to add on to the inline method on unwind and make (funcall (block nil (lambda () (if n (return nil)))) inline correctly with a branch to an illegal unwind instruction
4:28:08
karlosz
and if it doesn't introduce an illegal unwind instruction instead of the nop instruction used for the valid case
4:32:22
beach
The criterion about the environment for inlining goes like this: The environment of the callee can be allocated in the caller only if 1) The environment of the callee does not survive the invocation of the caller, and 2) There is only ever a single active invocation of the callee for each invocation of the caller.
4:34:46
beach
But we need to avoid too many special cases, in particular if they handle code that is rarely seen.
4:35:17
Bike
other than the complicated code that's supposed to keep unwinds only if needed, i guess
4:36:34
Bike
if my code works, once the function in (block nil ((lambda () (return)))) is inlined, the unwind instruction will be removed and it will be just a regular control arc
4:37:47
Bike
but for example in (block nil (foo (lambda () ((lambda () (return))))) the inner function can be inlined but there's still an unwind.
4:41:39
karlosz
yes, i think the only thing that warrants changing is the UB example. it would be nice to not infinite loop and do the right thing
4:45:28
Bike
(loop with x do (block nil (if (null x) (setf x (lambda () (return))) (funcall x)))) which is extremely artificial
4:46:27
Bike
it won't cause any memory faults or weird shit like that which is why i'm not super concerned, but it's still unfortunate
4:49:25
karlosz
Bike: i just tried it with cleavir+clisp and it gave me an out of extent return error fine
4:49:51
karlosz
but this is with the closure conversion fix so maybe that has something to do with it
4:51:02
Bike
the idea is that it hits the catch instruction, sets x, then exits the block scope to the top of the loop, then hits the catch instruction which again sets the continuation to something valid
5:04:05
karlosz
well here's one issue: i think its written somewhere that the output of enclose is never assigned to by anthing else
5:13:43
karlosz
there should be a sentence like the output of an enclose instruction is never assigned to by construction
5:15:51
karlosz
::notify Bike i see the problem in your example. yes, if you always insert cells at the top of the procedure, you are going to run into the issue. if you insert the cell inside the loop using the closure fix i wrote with dominators it works correctly
5:31:43
karlosz
::notify Bike: putting create cells at the top of the procedure essentially means that the lambdas all share the same block tag cell which keeps getting updated as the loop goes on, exactly the same problem as the (loop i ->5 collect (let ((x i)) (lambda () x)))) example