Front page | perl.perl6.internals |
Postings from May 2001
Re: Stacks & registers
From: Dan Sugalski
May 23, 2001 11:20
Re: Stacks & registers
Message ID: email@example.com
[I'm taking these all at once, so bear with me]
>Register based. Untyped registers; I'm hoping that the vtable stuff can be
>sufficiently optimized that there'll be no major win in storing multiple
>copies of a PMC's data in different types knocking around.
Maybe, but I'm thinking that adding two cached integers together (the
integer piece of the register being essentially a cache) will be faster
than two calls to get_integer.
Also, by having integer bits of registers, it means we can avoid making a
full PMC for integer constants, or for integers (or floats, or strings) the
interpreter wants to deal with internally. (scratch
>For those yet to be convinced by the benefits of registers over stacks, try
>grokking in fullness what op scratchpads are about. Ooh look, registers.
Or just dig through the code for pp_split. (While it might not convince you
of the joys of registers, it will make your head hurt sufficiently to
convince you that Things Must Be Done. Preferably things involving lots of
Dave Mitchell wrote:
>For low-level assembly, registers are important because using them
>avoids memory accesses. For high-level perl 6 bytecode, I suppose the
>analogy would be having a pool of scratch PMCs that dont have
>to be continually alloced+GCed. Whether we can avoid the allocs depends
>on the fine detail of how how PMCs are allocated in general. If the allocs
>can't be avoided, then I think we might as well stick with a stack
We'll have a stack, certainly, or something like it. If the register file
is limited in size (and it'll have to be, reality being what it is)
there'll have to be a scratch spot to stick things we aren't using.
We could call 'em temporaries, or named temporaries, or whatever, but
that's just a roundabout way of saying register. :) (Or vice versa, I
suppose, depending on which direction you're coming from)
>I'm unclear what purpose having virtual resisters for ints and nums serves:
>can't we just put those in real registers? Or perhaps I'm missing the pt?
The point of having int/num/string registers is for cache and convenience
reasons. If Parrot's dealing with an integer and it *knows* that it's an
integer (because, for example, we're dealing with some sort of internal
counter, or Python code) there seems little reason to promote it to a full PMC.
>I think "stack based =~ register based". If we don't have Java-like "jsr"
We might, though. Probably will, as it will make translation to JVM and
native machine code easier. (I think. Could be wrong)
> every bytecode inside one method always operates on the same
>depth, therefore we can just treat the "locals + stack" as a flat register
>file. A single pass can translate stack based code into register based code.
Fair enough, but then registers are just oddly named stack entities, which
makes their being on the stack a matter of implementation. (Whether that
means anything useful is another matter)
>first question: is this for the intermediate language or the back end
>VM? they don't have to be the same.
Bytecode. I want the bytecode to be what the Parrot VM eats--it will be
Parrot's assembly language.
>since our goal is to support the polymorphic front/back end design, the
>intermediate language (IL) should be easy to generate and easy to
>compile to various targets. also it needs to have other features like
>being modifiable for optimization, storable on disk, debuggable (for dev
This is the one spot it falls down. Though arguably translating bytecodes
dealing with PMCs will be more work than bytecodes that deal with ints or
If someone thinks the whole "multiple views per register" thing is a bad
idea, this would be a good line of attack to start with. :)
>the PL/I compiler suite i hacked on used that style of IL. but is
>allocated as many named temps as it needed by using N-tuples for each op
>code. each OP would leave its result in a named temp which could be
>referred to by later OPs. i think they were generic (as PL/I could mung
>many more types of data than perl) but the compiler knew what held what
>so that wasn't an issue.
That's still reasonably stack-based, and assumes a single return value per
sub, which we don't have. (Unless we consider a list as a single value,
which is reasonable)
>the problem with a fixed number of registers is register overflow. this
>is true in all register based machines and VM's and is a pain. if we go
>with a pure named temp architecture, you don't need to worry about
>that. but it is slower to access and manage named temps than a fixed set
>of registers (or even just a stack which is like a single reg machine).
From all the literature I've dug through, a largish register set (like 32
or 64) gets around 90+% of the overflow issues, and we can still have
register push/pop opcodes.
>i have some experience with N-tuples and it does work well for
>compiling as you don't care about the managing of registers at run time
>then. you just keep a fat namespace table at compile time and throw it
>out later. we have a compile and run phase so managing a large number of
>N-tuples may be slow running but easy to generate and manipulate. that
>is a typical tradeoff.
I am worried about making the base compilation inherently expensive, which
would be bad. (/OPTIMIZE=BREATHTAKING switches notwithstanding, as you'll
get what you ask for there) OTOH, this sounds rather like what all the
compiler books I have use in some form, so I might be fretting over nothing.
>we should have a small set of special registers to handle events,
>booleans, the PC, signals, etc.
Hadn't thought about that. Looks like a really good idea.
> DS> I'm definitely feeling unsure about this, so feel free (please!)
> DS> to wade in with comments, criticisms, or personal attacks... :)
>you are a doofus.
<fweeep!>Umpire calls foul! Statements of fact do not meet the above criteria!
>but a smart one. :)
This does, however. :)
>A little backwards my answer will be. I'm fairly sure we won't need linked
>registers. The PMC's vtable implemention should already take care of the
>int/float/string cross-referencing - by having the linked registers, you'd
>really only be creating a parallel structure to wade through. Worse case,
>you're doing both - using the vtable to create the values for the other
>registers. (After checking the register first to see if it were valid?)
>That doesn't sound like a win at all. You could bypass the PMC's vtable and
>populate the registers directly, but then why have the PMC. I don't see any
>reason for the linking.
>Now, assuming I'm not way out in the left-field stands above, I don't see
>the necessity for typed registers (at least as described).
Linked registers may well not be useful enough to justify the extra
complexity. They're in there as much for interpreter temps and internal
values as anything else, though I think there might be speed wins as well.
(Well, and for better support for non-perl languages, but that's a horribly
Buddha wrote: (And I like the way that came out... :)
>In the section I snipped, you described "linked" registers in relation to
>multiple sets of typed registers, with linking meaning that IntR1 would
>have the same value as FloatR1, etc. What do you mean by "linked" here,
>with each register being (as I read it) dynamically typed?
Basically a register would be really fat, looking like:
|V| PMC pointer |
|V| string |
|V| integer |
|V| float |
With the "V" bit being a "this part is valid" marker. There'd be opcodes like:
makeint 1; Fills in the integer part of register 1
makestr 1; Fills in the string part of register 1
makepmc 1; Creates a valid PMC for register 1
makenum 1; Fills in the float part of register 1
makeall 1; Make all the invalid pieces of register 1 real
With each one scanning the register and creating the piece specified from
another piece in the register that's already valid.
>Is N fixed, or can we have different number of visible registers at a
>time? When we push registers onto the stack, do we push them
>individually, or as a set?
Fixed, I think, and I expect that pushing multiple registers in one go will
be a given. (Shades of 68K assembly! :)
>That comment reminds me of how the register file is implemented in
>a sun sparc. They have a large register file, but only some are accessable
>at any given time, say 16. When you do a sub call you place your
>arguments in the high registers, say 4, and shift the window pointer
>by 12 (in this case). What was r12-r15 now becomes r0-r3. On return
>the result is placed into r0-r3 which are then available to the
>caller as r12-r15.
>This allows very efficient argument passing without having to save
>registers to a stack and restor them later.
Hmmm. Yeah, there is that, and if we go to register-based parameter passing
(which I know Larry intends in some cases, and I agree as it'll make C
binding cleaner) it'll be a useful thing. Perhaps two sets of registers,
the parameter passing ones and the work ones, would be in order.
I think that's it--is there anything I missed?
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
firstname.lastname@example.org have teddy bears and even
teddy bears get drunk