"Leopold Toetsch" <[EMAIL PROTECTED]> wrote:
Depending on the arch (32 vs 64 bits) one of these opcodes is
suboptimal. With a new "L" (Long) register type the functionality could
be handled transparently:
$L0 = pio.'tell'()
Yes, but as you add more register types you get a combinatorial blow-up
on various opcodes.
This depends on the implementation of 'opcodes'. With the current scheme
any such extension isn't really implementable because of the combinatorial
opcode explosion. I've written a (still internal) proposal that would
prevent the combinatorial issue. It (or some similar thing) would be
indeed necessary to even think about more register types like int8, int16,
int32/int64 or float32.
Iff we want those register types. .NET is interesting in that it recognises
int8, int16 etc as fundemental types, but on the stack only recognizes
int32, int64 and native int (out of the integer types anyway). If you want
to have an int8 then you just do the ops in an int32 and then use a conv.i1
instruction. I think the wisdom here is, where do we actually really need
to support int8. And it's in arrays that it matters most for example, for
size reasons.
My understanding was that "I" registers were native integers so you
could get good performance, and you used a PMC if you wanted some
guarantees about what size you were talking about.
In the long run, we certainly don't want to use PMCs for e.g.
immplementing bytes (int8) or some such for performance reasons. 'long
long' aka int64 is usually supported by compilers and has for sure by far
better performanche than a BigInt PMC.
Actually using 'int8' or 'float32' is usually only important, if you have
huge arrays of these. That means that there's a very limited need for
opcodes using these types, just some basic math mainly and array
fetch/store. Or in other words: what is supported by the hardware CPU.
If it's just arrays, then we can provide a (Fixed|Resizable)ByteArray PMC,
etc. I don't think we need any instructions to specially handle doing 8-bit
arithmetic. Maybe we want something to truncate a 32-bit to an 8-bit etc,
maybe throwing an exception on overflow.
The register allocator would map 'L0' either to a pair (I0, I1) on 32
bit arch or just to 'I0' on 64 bit arch.
Yes, but surely it becomes somewhat more than just a mapping problem?
For example, what do we do about:
add L0, L1, L2
mul L0, L1, L2
I don't see any problem with above code.
The register mapping rules would be something like:
- Lx occupies registers I(2x, 2x+1) - this is compile time,
that is 'L1' prevents 'I2' and 'I3' from being assigned by the register
allocator
- the runtime mapping isn't portable due to endianess and sizeof types
'L1' might be 'I1' on 64-bit arch or (I2,I3) or (I3,I2) on 32-bit arch
Yup, and I really, really don't like the idea of making our bytecode format
non-portable. Part of the point of having a VM is portability, right?
- if you write PASM, overlapping Ix/Ly may cause warnings or errors, but
could be used in a non-portable way, if you know what you are doing on a
specific platform.
You still didn't address my question with these points, though.
mul L0, L1, L2
Isn't just a case of churning out something like:-
mul I0, I2, I4
mul I1, I3, I5
So it's not just so simple as a "map 1 L to 2 Is" problem.
Jonathan