add bytecode-like data type
This commit is contained in:
parent
41c64d8c51
commit
b17531b799
14
bin/main.ml
14
bin/main.ml
|
@ -3,7 +3,15 @@ let () =
|
||||||
Logs.set_level (Some Logs.Debug);
|
Logs.set_level (Some Logs.Debug);
|
||||||
|
|
||||||
try
|
try
|
||||||
let syn = Spice.parse "val x = 3 val y = x + 1" in
|
let int n = Spice.Code.Cst_int (Int64.of_int n) in
|
||||||
let lir = Spice.compile syn in
|
let reg n = Spice.Code.Reg n in
|
||||||
Fmt.pr "%a\n" Spice.Lir.pp_entrypoint lir
|
|
||||||
|
let l0 = Spice.Code.make_basic_block [ MUL (0, reg 1); RET ] in
|
||||||
|
let ep =
|
||||||
|
Spice.Code.make_basic_block
|
||||||
|
[ MOV (0, int 4); MOV (1, int 5); ADD (1, int 6); JMP l0 ]
|
||||||
|
in
|
||||||
|
|
||||||
|
let prog = Spice.Code.make_program ep in
|
||||||
|
Fmt.pr "%a" Spice.Code.pp_program prog
|
||||||
with Spice.Error msg -> Logs.err (fun m -> m "%s" msg)
|
with Spice.Error msg -> Logs.err (fun m -> m "%s" msg)
|
||||||
|
|
2
lib/dune
2
lib/dune
|
@ -1,3 +1,3 @@
|
||||||
(library
|
(library
|
||||||
(name spice)
|
(name spice)
|
||||||
(libraries fmt spice_syntax spice_lower))
|
(libraries fmt spice_syntax spice_lower spice_runtime))
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
type regidx = int
|
||||||
|
|
||||||
|
type operand =
|
||||||
|
| Cst_nil
|
||||||
|
| Cst_true
|
||||||
|
| Cst_false
|
||||||
|
| Cst_int of int64
|
||||||
|
| Reg of regidx
|
||||||
|
|
||||||
|
type basic_block = {
|
||||||
|
mutable ins_builder : ins list;
|
||||||
|
mutable ins_list : ins list;
|
||||||
|
(* bc_pc : int *)
|
||||||
|
(* bc_len : int *)
|
||||||
|
}
|
||||||
|
|
||||||
|
and ins =
|
||||||
|
| MOV of regidx * operand
|
||||||
|
| ADD of regidx * operand
|
||||||
|
| SUB of regidx * operand
|
||||||
|
| MUL of regidx * operand
|
||||||
|
| JMP of basic_block
|
||||||
|
| BRT of operand * basic_block * basic_block
|
||||||
|
| RET
|
||||||
|
|
||||||
|
let make_basic_block ins_list = { ins_builder = List.rev ins_list; ins_list }
|
||||||
|
|
||||||
|
let instructions bb =
|
||||||
|
(* memoize computing "rev ins_builder" by storing result in ins_list *)
|
||||||
|
if bb.ins_list = [] then bb.ins_list <- List.rev bb.ins_builder;
|
||||||
|
bb.ins_list
|
||||||
|
|
||||||
|
let add_ins bb is =
|
||||||
|
(* "append" instruction by prepending to ins_builder list *)
|
||||||
|
bb.ins_builder <- is :: bb.ins_builder;
|
||||||
|
(* invalidate the cache *)
|
||||||
|
bb.ins_list <- []
|
||||||
|
|
||||||
|
type program = { entrypoint : basic_block }
|
||||||
|
|
||||||
|
let make_program entrypoint = { entrypoint }
|
||||||
|
|
||||||
|
(* pretty printing *)
|
||||||
|
|
||||||
|
let pp_reg ppf r = Fmt.pf ppf "$%d" r
|
||||||
|
|
||||||
|
let pp_operand ppf = function
|
||||||
|
| Cst_nil -> Fmt.pf ppf "nil"
|
||||||
|
| Cst_true -> Fmt.pf ppf "true"
|
||||||
|
| Cst_false -> Fmt.pf ppf "false"
|
||||||
|
| Cst_int n -> Fmt.pf ppf "#%s" (Int64.to_string n)
|
||||||
|
| Reg r -> pp_reg ppf r
|
||||||
|
|
||||||
|
let pp_ins ~get_bb_name ppf = function
|
||||||
|
| MOV (l, r) -> Fmt.pf ppf "mov %a, %a" pp_reg l pp_operand r
|
||||||
|
| ADD (l, r) -> Fmt.pf ppf "add %a, %a" pp_reg l pp_operand r
|
||||||
|
| SUB (l, r) -> Fmt.pf ppf "sub %a, %a" pp_reg l pp_operand r
|
||||||
|
| MUL (l, r) -> Fmt.pf ppf "mul %a, %a" pp_reg l pp_operand r
|
||||||
|
| RET -> Fmt.pf ppf "ret"
|
||||||
|
| JMP l -> Fmt.pf ppf "jmp %s" (get_bb_name l)
|
||||||
|
| _ -> failwith "..."
|
||||||
|
|
||||||
|
let pp_program ppf pr =
|
||||||
|
let ep = pr.entrypoint in
|
||||||
|
let basic_blocks = ref [ ep, "START" ] in
|
||||||
|
let work_list = ref [ ep ] in
|
||||||
|
let get_bb_name bb =
|
||||||
|
match List.find (fun (bb', _) -> bb == bb') !basic_blocks with
|
||||||
|
| _, name -> name
|
||||||
|
| exception Not_found ->
|
||||||
|
let name = Fmt.str "L%d" (List.length !basic_blocks - 1) in
|
||||||
|
basic_blocks := (bb, name) :: !basic_blocks;
|
||||||
|
work_list := bb :: !work_list;
|
||||||
|
name
|
||||||
|
in
|
||||||
|
let rec loop i =
|
||||||
|
match !work_list with
|
||||||
|
| [] -> ()
|
||||||
|
| bb :: rest ->
|
||||||
|
work_list := rest;
|
||||||
|
if i > 0 then Fmt.pf ppf ",";
|
||||||
|
Fmt.pf ppf "%S:[" (get_bb_name bb);
|
||||||
|
List.iteri
|
||||||
|
(fun i is ->
|
||||||
|
if i > 0 then Fmt.pf ppf ",";
|
||||||
|
let str = Fmt.str "%a" (pp_ins ~get_bb_name) is in
|
||||||
|
Fmt.pf ppf "%S" str)
|
||||||
|
(instructions bb);
|
||||||
|
Fmt.pf ppf "]";
|
||||||
|
loop (i + 1)
|
||||||
|
in
|
||||||
|
Fmt.pf ppf "{";
|
||||||
|
loop 0;
|
||||||
|
Fmt.pf ppf "}"
|
|
@ -0,0 +1,3 @@
|
||||||
|
(library
|
||||||
|
(name spice_runtime)
|
||||||
|
(libraries fmt))
|
|
@ -1,5 +1,6 @@
|
||||||
module Syn = Spice_syntax.Ast
|
module Syn = Spice_syntax.Ast
|
||||||
module Lir = Spice_lower.Lir
|
module Lir = Spice_lower.Lir
|
||||||
|
module Code = Spice_runtime.Code
|
||||||
|
|
||||||
exception Error of string
|
exception Error of string
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue