Module Fang_asm

Manipulate and pretty-print assembly instructions.

Assembly instructions are defined by how they are pretty-printed but can be altered after construction to "swap out" different registers. This is useful, for example, for assigning real processor registers to the temporary storage locations in assembly emitted by earlier stages of the compiler ("coloring").

Instructions are annotated in a limited way so that they can analyzed by different stages of the compiler. For example, registers are marked as being read ("use") and/or written to ("def") by the instruction.

An example might be helpful.

type asm

A single assembly instruction.

All instructions are distinct, even if they are pretty-printed identically to other instructions.

module Asm : sig ... end

Assembly instructions.

Example

Suppose we wish to represent the instruction

add x, y

(which adds the value in the register x to the value in the register y and stores the result back in x) for some registers x and y defined as follows:

let x = box ()
and y = box ()

The instruction can be defined as

let t =
  Asm.v ~use:[x; y] ~def:[x] (fun ~use ~def pp_box ppf () ->
      Fmt.pf ppf "@[<h>add@ %a,@ %a@]" pp_box (use 0) pp_box (use 1) )

x and y have been marked as "use" because the instruction reads their values. Only x has been marked as "def" ("defined") because only x is written to (y is unchanged by the instruction).

The instruction is defined by specifying a pretty-printer for it. Instead of referring to the registers x and y directly we use the pp_box formatter that is provided and refer to the registers by their index in the use and def lists.

The reason for this complexity is to make it easier to "swap out" different registers without having to reconstruct the instruction.

For example, here's a pretty-printer for our registers x and y

let pp_reg ppf b =
  if Box.equal b x then Fmt.text ppf "x"
  else if Box.equal b y then Fmt.text ppf "y"
  else Box.pp ppf b

with which we can pretty-print the instruction:

Fmt.strf "%a" (Asm.pp pp_reg) t 

The result is "add x, y".

Now, let's replace y with x:

let t2 = Asm.replace ~target:y x t 

The result of

Fmt.strf "%a" (Asm.pp pp_reg) t2 

is "add x, x".