Dave Mitchell <[EMAIL PROTECTED]> writes:
>
>There's no reason why you can.t have a hybrid scheme. In fact I think
>it's a big win over a pure register-addressing scheme. Consider...
Which was more or less my own position...
>
>At the start of a new scope, the stack is extended by N to create a new
>stack frame (including a one-off check that the stack can be
>extended). There is then a 'stack pointer' (sp) which is initialised
>to the base of the new frame, or an initial offset thereof. (So sp is
>really just a temporary index within the current frame.)
>
>Then some opcodes can use explicit addressing, while others can be explicit,
>or a mixture.
>
>Explicit opcodes specify one or more 'registers' - ie indexes within the
>current frame, while implicit opcodes use the current value of sp as an
>implicit index, and may alter sp as a side effect. So an ADD opcode
>would use sp[0], sp[-1] to find the 2 operands and would store a pointer
>to the result at sp[-1], then sp--. The compiler plants code in such a way
>that it will never allow sp to go outside the current stack frame.
>
>This allows a big win on the size of the bytecode, and in terms of the
>time required to decode each op.
>
>Consider the following code.
>
>$a = $x*$y+$z
>
>Suppose we have r5 and r6 available for scratch use, and that for some
>reason we wish to keep a pointer to $a in r1 at the end (perhaps we use
>$a again a couple of lines later):
>
>
>This might have the following bytecode with a pure resiger scheme:
>
>GETSV('x',r5) # get pointer to global $x, store in register 5
>GETSV('y',r6)
>MULT(r5,r5,r6) # multiply the things pointed to by r5 and r6; store ptr to
> # result in r5
>GETSV('z',r6)
>ADD(r5,r5,r6)
>GETSV('a',r1)
>SASSIGN(r1,r5)
Globals are a pain. Consider this code:
sub foo
{
my ($x,$y,$z) = @_;
return $x*$y+$z;
}
In the pure register (RISC-oid) scheme the bytecode should be:
FOO:
MULT(arg1,arg2,tmp1)
ADD(tmp1,arg3,result)
RETURN
That is lexicals get allocated registers at compile time, and ops
just go get them.
In the pure stack with alloc scheme (x86-oid) scheme it should be
ENTER +1 # need a temp
MULT SP[1],SP[2],SP[4] # $x*$y
ADD SP[4],SP[3],SP[1] # temp + $z -> result
RETURN -2 # Loose temp and non-results
And in a pure stack (FORTH, PostScript) style it might be
rot 3 # reorder stack to get x y on top
mpy
add
ret
>
>but might be like this in a hybrid scheme:
>
>SETSP(5) # make sp point to r5
>GETSV('x') # get pointer to global $a, store at *sp++
>GETSV('y')
>MULT
>GETSV('z')
>ADD
>GETSV('a')
>SASSIGN
>SAVEREG(r1) # pop pointer at *sp, and store in register 1
The problem that the hybrid scheme glosses over is the re-order the args
issue that is handled by register numbers, stack addressing or
FORTH/PostScript stack re-ordering.
It avoids it by expensive long range global fetches - which is indeed
what humans do when writing PostScript - use globals - but compilers
can keep track of such mess for us.
>
>
>Both use the same regsters, have the same net result, but the explicit
>scheme requires an extra 11 numbers in the bytecode, not to mention all
>the extra cycles required to extract out those nunmbers from the bytecode
>in the first place.
--
Nick Ing-Simmons
who is looking for a new job see http://www.ni-s.u-net.com/