Crates.io | ilvm |
lib.rs | ilvm |
version | 0.2.1 |
source | src |
created_at | 2018-11-16 13:13:52.312968 |
updated_at | 2018-11-23 15:22:41.409903 |
description | An interpreter for an assembly-like language |
homepage | |
repository | https://github.com/plasma-umass/ilvm |
max_upload_size | |
id | 97018 |
size | 29,427 |
The intermediate-level virtual machine (ILVM) is an interpreter for a language that has a few features that make it higher-level than typical assembly languages:
ILVM has malloc and free instructions that work similar to the C functions. However, the free list is not in program memory, so a program cannot accidentally clobber it.
ILVM has an if ... then .. else instruction, so it supports structured control flow.
ILVM has primitive instructions to print to screen.
Note: ILVM implements a Harvard architecture and does not have a stack.
A program in ILVM is a collection of blocks, where each contains a sequence of instructions. Each block has a unique number and execution always starts at block zero. For example, the following program has a single block and prints 30:
block 0 {
exit(30);
}
The following program uses the goto instruction to jump to block 1 and then print 20:
block 1 {
exit(20);
}
block 0 {
goto(1);
}
Note that the order in which blocks appear is not relevant.
ILVM has registers numbered r0 through rn, where n can be set by the user. ILVM supports basic binary operations (+, -, *) that take either registers or constants as arguments, and store their results in registers. It also supports operations to load data into registers from the heap, and to store values from registers in the heap. Some examples of these operations are given below:
block 0 {
r0 = 10; // set r0 to 10
r1 = r0 * 2; // set r1 to 20
*r1 = 50; // store 50 at heap address 20
r2 = *r1; // load the value at heap address in r1 into r2 (i.e., set
// r2 to 50
exit(0);
}
The goto(n); instruction jumps to block n. The argument may either be a literal constant, or it may be value stored in a register. For example, the following program calculates the address of the block to jump to:
block 0 {
r0 = 10;
r1 = r0 - 9;
goto(r1); // jumps to block 1
}
block 1 {
exit(0);
}
The ifz r trueBlock else falseBlock instruction is a conditional with two sub-blocks. If the value in the register is zero, it executes trueBlock, else it executes falseBlock. For example, the following program calculates factorial(5):
block 0 {
r2 = 1;
r1 = 5;
goto(1);
}
block 1 {
ifz r1 {
exit(r2);
}
else {
r2 = r2 * r1;
r1 = r1 - 1;
goto(1);
}
}
Note that the sub-blocks may have nested ifz instructions. Also note that sub-blocks are not numbered. Therefore, a program cannot use goto to jump to a sub-block.
The exit(n) instruction terminates the program normally, and produces the value n. The abort; instruction is an abnormal exit and should be avoided if possible. Note that the sequence of instructions in every block must end with either exit, goto, or abort. In other words, a program cannot "fall-through" from one block to the next, and must explicitly jump to another block or terminate.
The word size of ILVM is 32-bits.
A program can read and write to any memory address. The initial value stored at all memory addresses and registers is zero. Each memory location and register is one word long (i.e., 32 bits).
ILVM has a malloc(n) instruction that returns the address of a free block of memory that is n words long, and a free(a) instruction that frees the block that was allocated at the address a. It may be convenient to use these functions instead of writing an allocation manually. Note that these operators maintain their metadata in an independent part of memory, so it is not possible for an ill-behaved program to corrupt the state that malloc and free require.
Programs do not have to use malloc and free. However, it may be convenient to do so.
Registers r ::= "r0" | ... | "r64"
Values val ::= r
| i Signed 32-bit integers
Operators op ::= "+"
| "-"
| "*"
| "/"
| "%"
| "=="
| "<"
Instructions instr ::= "goto" "(" val ")" ";"
| "exit" "(" val ")" ";"
| "abort" ";"
| r "=" val op val ";" instr
| r "=" val ";" instr
| r "=" "*" val ";" instr
| "*" r "=" val ";" instr
| "ifz" val "{" instr "}" "else" "{" instr "}""
| r "=" "malloc" "(" val ")" ";" instr
| "free" "("r ")" ";" instr
Blocks block ::= "block" n "{" instr "}"
Programs p ::= block
| block p
Run ilvm --help
for documentation.