rpjohnst / dejavu

Game Maker reimplementation
https://dejavu.abubalay.com
Apache License 2.0
70 stars 7 forks source link

VM instructions don't allow addressing >256 registers or >256 constants #38

Open elipsitz opened 4 years ago

elipsitz commented 4 years ago

Each instruction is 32-bits, and has an 8-bit opcode, and 3 8-bit fields (a, b, c). Instructions use just one of these fields to index into the registers on the stack, and the local constants table, which limits the maximum addressable registers and constants.

One approach to extend this to 65536 registers/constants would be to add special Move opcodes that can move to/from registers >256, by combining two of the fields to make one 16-bit address. This is the approach that Dalvik does.

You'd need a "Move from high (16-bit) to low" and a "Move from low (16-bit) to high" instruction unfortunately. I guess you could also meet in the middle and add one that splits up the 3 fields into 2 12-bit register indices (a destination and source), which would allow moving between registers two registers (0-4095) in a single instruction, as an optimization.

Similarly, the Imm instruction uses only (a, b) -- you could make (b, c) represent a single 16-bit offset into the constants table.

I guess if you really needed to index many (>65536) registers, you could fall back to indirect addressing -- like, "Move from the register indexed at this register"

rpjohnst commented 2 years ago

I've made some improvements in this area to unblock some sample code I've been looking at. 8e6d2ac7b21d72cc85c63c3a98c17be30ae6bf7d relieves some of the pressure by splitting symbols (like API and field names) out from the constants table and moving script references out of the Call instruction into the constant table, 0f72e8a65f4de4aa13b2f1aa121eaf6ebd247e08 fixes a bug that led to high register usage in some cases, and 64cbd695f99811e105ff0d4a6e6f4d2cbc281fef increases the field width for the Const instruction (recently renamed from Imm).

It seems unlikely so far that we will need >256 registers (and it looks like Lua has a similar maximum), but if that happens then wide Move opcode(s) plus some spill/fill logic in the register allocator is probably the next step there. There may also be ways to reduce register pressure with better codegen.

Another possibility for symbols, if we start hitting that limit again, might be to add support for naming them indirectly via a register, which could then be loaded with a wide Const instruction. Instructions using symbols would either need to be duplicated, or have an extra bit stolen from somewhere to indicate whether their operand(s) are symbols vs registers.