nolimix86 is an attempt to make a basic virtual machine with unlimited registers.

Does it work?


Why would anyone want that ?

During the Tiger Compiler project, the Instruction Selection step is targeting multiple targets (MIPS, x86 and ARM).

The philosophy of the Tiger Compiler project is to make every step easily testable. But it seems like the instruction selection step generates code with virtual registers (temporaries), that are unlimited.

Let’s take a look at the code generated at this step for the x86 target:

  movl $1, %t1
  movl %t1, %t2
  push $42
  pop %eax
  push $101

Notice the %t1 registers, that represent those temporary registers, waiting for the Register Allocation step to be done.

Since we would like to evaluate the output of the students’ work on the x86 target, I decided to make a virtual machine (emulator?) allowing the usage of those kind of registers.


Since correctly parsing x86 assembly is a PITA, and since LLVM provides a correct x86 assembly parser, I decided to look there and allow those unlimited registers in LLVM’s parser.

This following modifications were applied:

  • X86AsmParser.cpp: Handle %t# registers in the lexer.
  • X86Operand.h: Handle %t# registers as general purpose registers, allowing compatibility between general purpose registers and temporaries.

From there, a subclass of llvm::MCELFStreamer is creating an AST using various hacks in order to detect the correct x86 instruction to create. Most of the instructions opcodes are declared in src/x86/instructions.hh, allowing a range of MC opcodes to bind to a specific instructions, without minding the operands types.


The virtual machine is actually an AST visitor. So the instruction pointer is actually an iterator on an instruction, and the virtual machine communicates with the CPU class that holds all the CPU state (registers, flags, …).


Memory accesses go through the cpu::mmu template class, which translates host < – > vm addresses, depending on the CPU.

The stack and the heap are wrappers around a big memory chunk that is accessed through the mmu.


In order to test the virtual machine, the final state of the CPU can be dumped in YAML format. This allows testing to be easily compared in the test suite.