I hope you do not feel like I'm spamming the list but I would like to talk about my endeavor as much as possible so that you can follow it and perhaps see any stupidity in the ideas early on. So what I'm
doing now is to investigate different compiling strategies to output some kind of effective rtl code.
So everything is a small mod on the compile-glil code and the output is instrumented and evaluated to see how sound the method may be. So let's compile a function and dissect the output (I''m not true to current
rtl layout, just to see if the generation of code is sound.
The adress layout in the scm rtl space for a frame is 0 = procedure 1 = arg 0 2 = arg 1 ... narg = arg narg - 1 narg + 1 = local 0 narg + 2 = local 1
... narg + nlocal -1 = local nlocal - 1 narg + nlocal = rsp start ----------------------------------------------------
Now this is maped to a physical layout that is (arg0 return adress old-frame program arg1 ... arg(narg - 1) local0 ... )
ok here is the code (lambda (x) (f (h (k x) y) (+ z 2) 12)
And here is the compilation output, ((begin-program () program5351) (std-prelude 0 0) (label :LCASE5349) ((begin-program () program5350)
(std-prelude 1 1) (rtl-bind ((x 0))) (label :LCASE5348) (clear 2 3) (toplevel 0 f ref) (move 4 1) (toplevel 5 k ref) (call (mem : 4) (sp : 4) 1) (toplevel 5 h ref) (toplevel 6 y ref)
(call (mem : 1) (sp : 4) 2) (toplevel 4 z ref) (load-const 5 2) (add 2 (4 5)) (load-const 3 12) (tail-call 3)) (return))
(rtl-bind) - don't now yet about this
(clear 2 3)
We see here that we need to allocate from the stack from [2,3] and reset those values in order to fill in three arguments because only [0,1] are filled in and we need [0,1,2,3] in order to do the tail call
(toplevel 0 f ref)
Here we fill in the new function. To do this correctly we must make sure that if we reference f later on if we for example need a closure variable, if we have those references we must copy the old f to a stack position and use that later on for function reference
but for simple algorithms we will just overwrite the old f, not sure if this is good yet, we could change this to the old setup where we calculate f on the stack and then in the call statement transfer it to it's position we'll see.
Now we would like to calculate (f (h (k x) y)) and put it in position 1 note that x is located at 1 and if this location would have changed we must transfer the x to the stack and use it. Somehow we must look forward in time to see what to do here leading to a n**2 algorithm
which is bad, I will later in stead try to to compilation in phases by delaying stack calculations perhaps we can conclude a good n algorithm still in the end. anyhow
(move 4 1) ;; x -> sp 4 stack-space = (x ...)
(toplevel 5 k ref) ;; k -> sp 5 stack-space = (x k ...) (call (mem : 4) (sp : 4) 1) a one argument call, by seeing that the position to put the result is 4 and the sp at the beginning of the call is 4 we see that we can leave the result
of the call on the stack and just adjust the stack pointer note that we first fill in the first argument and then the function name, this is how I have layouted logically the function call, I just kept one slot in the beginning where the return value may be put and by making sure the first argument is also located there
we have symmetry in case we would like to call a function on the output from the call. so at sp : 4 we will have the result of (k x). Next
(toplevel 5 h ref) stack-space ((k x) h) (toplevel 6 y ref) stack-space ((k x) h y)
(call (mem : 1) (sp : 4) 2) call the function (h (k x) y)
note here that mem < sp in which case we must output a second rmove instruction, the signature of the rmove is (rmove (a1 ... an)) and it will transport the values returnd to the registers a1 ... an. in this case we fill the first argument
with of the tail call with the result.
(toplevel 4 z ref) ;; stack-space (z ... (load-const 5 2) ;; stack.-space (z 2) (add 2 (4 5)) ;; Add 4 and 5 and put it into 2 the second argument of the tail call.
Note here that if we have an argument that is a variable ref we will use that directly in stead of going through the stack hence save copying. A lot of arguments to operations are variables so this can save considerable amount of copying.
(load-const 3 12) ;; Put constant 12 in slot 3, the third argument of the tail call and finally
(tail-call 3) ;; Do a three argument tail call. To note here is that we have not allocated the stack-space fot the function frame, but it's possible to instrument a probe for the maximum sp that
shows up and use that.
So this is how it looks right now, things may change and we'll see where we end but I feel that the current setup has some beauty in it that bode well for an effective byte code.