|
From: Kevin K. <kev...@gm...> - 2017-12-30 21:48:39
|
I have an extremely rough first cut at an implementation of procedure
inlining, on the 'inline' branch. While the eventual objective is to make
procedures that do [uplevel] behave as macros, in order to make it possible
to try to compile them, it's not nearly there yet.
A couple of the limitations seem to be fairly silly, and I suspect that
they'll be straightforward to fix.
First, and most important by far, is that I can't inline a procedure that
might return failure. I've simply not found a way to do it with the
existing quadcode instruction repertoire. I can see the 'returnException'
instruction in the procedure to be inlined, but I don't see a good way to
construct the object that the procedure would have returned. (Ideally,
including the stack trace that would have appeared, for which I have all
necessary information, I think.) This is blocking all but about a dozen of
the potential opportunities for inlining.
A second limitation is that I don't seem to have any way in the @debug
quadcodes to indicate that I've brought in code from a different source
file. That will mess up stack traces, compile-time messages and so on, if a
procedure in one file inlines a procedure defined in a different file.
Beyond these issues, the work on these issues also exposed a couple of bugs:
https://core.tcl.tk/tclquadcode/tktview?name=58e3e71962
https://core.tcl.tk/tclquadcode/tktview?name=4f8bd5f5b2
Once these are settled, the next big step will be to allow invocation of
procs that use the callframe - and this is a necessary prerequisite before
we can actually address [uplevel]. What's going to be interesting there is
that we will now have multiple callframe objects; one for the inline
procedure and one for the procedure that embeds it. I can identify readily
the points at which the embedded callframe must be stacked and unstacked,
and it will be easy to bind moveToCallFrame and moveFromCallFrame (and
friends) to the appropriate frame. But I really don't understand callframe
management well enough to implement this without a lot of study.
I'm hoping that Donal will be able to help me out.
For what it's worth, I'm really pleased with the result of embedding
'impure' into 'impure-caller'. It begins to look really, really
minimalistic; I'd expect that it could easily be as fast as C.
Procedure: ::impure-caller:
0: entry {} {literal {}}
1: @debug-line {} {literal 1259}
2: @debug-script {} {literal {impure 10 10000 10}}
3: @debug-line {} {literal 1229}
4: @debug-script {} {literal {set x 0}}
5: @debug-line {} {literal 1230}
6: @debug-script {} {literal {set i $a}}
7: @debug-script {} {literal {for {set i $a} {$i < $b} {incr i $c} {
set x [expr {$x + $i}]
}}}
8: {widenTo 60 INT} {var x 8} {literal 0}
9: copy {temp phi 9} {literal 10}
10: phi {var x 10} {var x 8} {pc 9} {var x 25} {pc 33}
11: phi {var i 11} {temp phi 9} {pc 9} {var i 30} {pc 33}
12: lt {temp 12 12} {var i 11} {literal 10000}
13: jumpTrue {pc 19} {temp 12 12}
14: free {} {temp 12 12}
15: free {} {var i 11}
16: @debug-line {} {literal 1233}
17: @debug-script {} {literal {return $x}}
18: return {} Nothing {var x 10}
19: free {} {temp 12 12}
20: @debug-line {} {literal 1231}
21: @debug-script {} {literal {expr {$x + $i}}}
22: add {temp 12 22} {var x 10} {var i 11}
23: free {} {var x 10}
24: @debug-script {} {literal {set x [expr {$x + $i}]}}
25: copy {var x 25} {temp 12 22}
26: free {} {temp 12 22}
27: @debug-line {} {literal 1230}
28: @debug-script {} {literal {for {set i $a} {$i < $b} {incr i $c} {
set x [expr {$x + $i}]
}}}
29: @debug-script {} {literal {incr i $c}}
30: add {var i 30} {var i 11} {literal 10}
31: free {} {var i 11}
32: @debug-script {} {literal {for {set i $a} {$i < $b} {incr i $c} {
set x [expr {$x + $i}]
}}}
33: jump {pc 10}
Unfortunately, this didn't yield a substantial performance gain, at least
on my machine. I suspect that in this specific case, LLVM is smart enough
to inline the 'impure' procedure itself and generates approximately the
same code. That said, the real purpose of this exercise is to comvert
proc's into macros in order to enable at least the simple uses of
[uplevel]. which is surely going to go beyond LLVM's powers of analysis.
Kevin
|