-
Notifications
You must be signed in to change notification settings - Fork 5
/
disasm.ml
130 lines (119 loc) · 5.52 KB
/
disasm.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
open Instr
let no_line_number buf pc = ()
let line_number buf pc = Printf.bprintf buf "% 6d |" pc
let pr = Printf.bprintf
let rec dump_comma_separated how buf what =
match what with
| [] -> ()
| [e] -> how buf e
| e::t -> pr buf "%a, %a" how e (dump_comma_separated how) t
let disassemble_instrs buf ?(ott_compatible = false) ?(format_pc = no_line_number) (prog : instructions) =
let dump_instr buf pc instr =
let simple buf = function
| Var v -> pr buf "%s" v
| Constant c -> pr buf "%s" (IO.string_of_literal c)
in
let dump_expr buf exp =
match exp with
| Simple e -> simple buf e
| Unop (Neg, a) -> pr buf "(-%a)" simple a
| Unop (Not, a) -> pr buf "(!%a)" simple a
| Binop (Plus, a, b) -> pr buf "(%a + %a)" simple a simple b
| Binop (Sub, a, b) -> pr buf "(%a - %a)" simple a simple b
| Binop (Mult, a, b) -> pr buf "(%a * %a)" simple a simple b
| Binop (Div, a, b) -> pr buf "(%a / %a)" simple a simple b
| Binop (Mod, a, b) -> pr buf "(%a %% %a)" simple a simple b
| Binop (Eq, a, b) -> pr buf "(%a == %a)" simple a simple b
| Binop (Neq, a, b) -> pr buf "(%a != %a)" simple a simple b
| Binop (Lt, a, b) -> pr buf "(%a < %a)" simple a simple b
| Binop (Lte, a, b) -> pr buf "(%a <= %a)" simple a simple b
| Binop (Gt, a, b) -> pr buf "(%a > %a)" simple a simple b
| Binop (Gte, a, b) -> pr buf "(%a >= %a)" simple a simple b
| Binop (And, a, b) -> pr buf "(%a && %a)" simple a simple b
| Binop (Or, a, b) -> pr buf "(%a || %a)" simple a simple b
| Array_index (a, i) -> pr buf "%s[%a]" a simple i
| Array_length e -> pr buf "length(%a)" simple e
in
let dump_arg buf arg = dump_expr buf arg in
format_pc buf pc;
begin match instr with
| Call (l, var, f, args) ->
pr buf " call %s = "var;
dump_expr buf f;
pr buf " (%a) %s" (dump_comma_separated dump_arg) args l;
| Stop exp -> pr buf " stop %a" dump_expr exp
| Return exp -> pr buf " return %a" dump_expr exp
| Decl_var (var, exp) -> pr buf " var %s = %a" var dump_expr exp
| Decl_array (var, Length exp) -> pr buf " array %s[%a]" var dump_expr exp
| Decl_array (var, List li) -> pr buf " array %s = [%a]" var
(dump_comma_separated dump_expr) li
| Drop var -> pr buf " drop %s" var
| Assign (var, exp) -> pr buf " %s <- %a" var dump_expr exp
| Array_assign (var, index, exp) -> pr buf " %s[%a] <- %a" var dump_expr index dump_expr exp
| Branch (exp, l1, l2) -> pr buf " branch %a $%s $%s" dump_expr exp l1 l2
| Label (MergeLabel label) -> pr buf "%s:" label
| Label (BranchLabel label) -> pr buf "$%s:" label
| Label (BailoutLabel label) -> pr buf ">%s:" label
| Goto label -> pr buf " goto %s" label
| Print exp -> pr buf " print %a" dump_expr exp
| Assert exp -> pr buf " assert %a" dump_expr exp
| Guard_hint es -> pr buf " guard_hint %a" (dump_comma_separated dump_expr) es
| Read var -> pr buf " read %s" var
| Assume {label; guards; target={func; version; pos}; varmap; extra_frames} ->
let dump_var buf = function
| x, e -> pr buf "var %s = %a" x dump_expr e
in
let dump_frame buf {cont_pos={func; version; pos}; cont_res; varmap} =
pr buf "(%s, %s, %s) [var %s = $%s%a]"
func version pos
cont_res
(if varmap = [] then "" else ", ")
(dump_comma_separated dump_var) varmap
in
pr buf ">%s: assume [%a] else (%s, %s, %s) [%a]%s%a"
label
(dump_comma_separated dump_expr) guards
func version pos
(dump_comma_separated dump_var) varmap
(if extra_frames = [] then "" else ", ")
(dump_comma_separated dump_frame) extra_frames
| Comment str -> pr buf " #%s" str
end;
pr buf "\n"
in
Array.iteri (dump_instr buf) prog
let disassemble buf (prog : Instr.program) =
(* TODO: disassemble annotations *)
List.iter (fun {name; formals; body} ->
let print_formal buf (Param x) = pr buf "var %s" x in
let print_formals buf = (dump_comma_separated print_formal) buf formals in
Printf.bprintf buf "function %s (%t)\n" name print_formals;
List.iter (fun version ->
pr buf "version %s\n" version.label;
disassemble_instrs buf version.instrs) body
) (prog.main :: prog.functions)
let disassemble_s (prog : Instr.program) =
let b = Buffer.create 1024 in
disassemble b prog;
Buffer.to_bytes b
let disassemble_o outchan (prog : Instr.program) =
let b = Buffer.create 1024 in
disassemble b prog;
Buffer.output_buffer outchan b;
flush outchan
let disassemble_instrs_s (prog : instructions) =
let b = Buffer.create 1024 in
disassemble_instrs b prog;
Buffer.to_bytes b
let disassemble_instrs_o outchan (prog : instructions) =
let b = Buffer.create 1024 in
disassemble_instrs b prog;
Buffer.output_buffer outchan b;
flush outchan
let pretty_print_version outchan (name, version) =
let b = Buffer.create 1024 in
Printf.bprintf b "version %s\n" name;
disassemble_instrs b ~format_pc:line_number version;
Buffer.output_buffer outchan b
let pretty_print outchan prog =
List.iter (pretty_print_version outchan) prog