Optimisations Across Hardware and Software using RISC-V [pf341-diss]
How can an open-source specification for a modular, flexible, reduced instruction set architecture (RISC-V) allow for greater control and manipulation over the hardware-software interface.
OCaml uses a tagged-bit runtime representation to distinguish between pointers and immediate values (like an integer or constant constructors for variants). The least significant bit (LSB) is a 1 for immediate values and 0 for pointers. This means 1 + 2 is really 3 + 5 but instead of getting 7 (2 * 3 + 1) you get 8! You have to perform an additional subtraction to get the correct value. Two instructions for a single addition (or subtraction). So I proposed ocadd to do it all in one.
Another feature of OCaml is its support for pattern-matching:
type animal = Dog | Cat | Camel
let print_animal = function
| Dog -> print_endline "dog"
| Cat -> print_endline "cat"
| Camel -> print_endline "camel"
These constructors are represented at runtime as immediate values (an enumeration using odd numbers 1, 3, 5...). Long enough pattern-matches are converted into jump tables using this enumeration to index the correct address (see p.24). These addresses (of the jumps) are separated by four bytes, we use the enumeration to do the jump by first converting to 0, 1, 2... and then shifting left twice (multipying by 4) and finally adding it to a base address. This is quite common. A new instruction, oclea fuses these into one shift-and-add instruction (named after load-effective address).
Another common task is applying functions. This can require saving or loading the return address and moving the stack pointer. This collection of assembly instructions are often called function prologues and epilogues. These were combined into one instruction.
As mentioned, OCaml has a tagged-bit representation. It is quite common to turn a number into an OCaml value by shifting left and adding one - ocvali does this in one go. oceqi r1 r2 imm checks if r2 is equal to imm and assigns 1 to r1 if it is, otherwise 0. This is useful in OCaml because the true value is a 1 which is really a 3! So simple truth checking looks like:
L101: li a1, 1 beq a0, a1, L100 li a0, 1 ret L100: li a0, 3 ret