1
2open HolKernel Parse boolLib bossLib;
3open arithmeticTheory listTheory pairTheory finite_mapTheory stringTheory;
4open source_valuesTheory source_syntaxTheory x64asm_syntaxTheory;
5
6val _ = new_theory "codegen";
7
8(* we return lists with explicit appends to avoid "bad append" performance *)
9
10Datatype:
11  app_list = List ('a list) | Append app_list app_list
12End
13
14Definition flatten_def:
15  flatten (List xs) acc = xs ++ acc ���
16  flatten (Append l1 l2) acc = flatten l1 (flatten l2 acc)
17End
18
19(* initialization code *)
20
21Definition init_def:
22  init k = (*  0 *) [Const RAX 0w;
23           (*  1 *)  Const R12 16w;
24           (*  2 *)  Const R13 (n2w (2 ** 63 - 1));
25           (* jump to main function *)
26           (*  3 *)  Call k;
27           (* return to exit 0 *)
28           (*  4 *)  Const RDI 0w;
29           (*  5 *)  Exit;
30           (* alloc routine starts here: *)
31           (*  6 *)  Comment "cons";
32           (*  7 *)  Jump (Equal R14 R15) 14;
33           (*  8 *)  Store RDI R14 0w;
34           (*  9 *)  Store RAX R14 8w;
35           (* 10 *)  Mov RAX R14;
36           (* 11 *)  Add R14 R12;
37           (* 12 *)  Ret;
38           (* give up: *)
39           (* 13 *)  Comment "exit 1";
40           (* 14 *)  Push R15;
41           (* 15 *)  Const RDI 1w;
42           (* 16 *)  Exit]
43End
44
45Overload AllocLoc[inferior] = ���7:num���;
46
47(* Naming conventions:
48    - prefix "c_" is used to mean "compile"
49    - argument names:
50       t - boolean indicating tail position (true if in tail position)
51       l - location where the next instruction will be placed in memory
52           (relative to first instruction of the entire program)
53       vs - a model of the stack: the ith element is SOME v if the value
54            of source variable v is at stack index i; positions containing
55            NONE do not correspond to a source-level variable; this information
56            is used by when compiling Var (in the c_var function)
57       fs - an a-list with locations for all the function locations,
58            compilation of Call (in c_exp) uses this information
59*)
60
61Definition even_len_def:
62  even_len [] = T ���
63  even_len (x::xs) = odd_len xs ���
64  odd_len [] = F ���
65  odd_len (x::xs) = even_len xs
66End
67
68Definition give_up_def[simp]:
69  give_up b = if b then 14:num else 15
70End
71
72Definition c_const_def:
73  c_const l n vs = if 2**63-1 < n
74                   then (List [Jump Always (give_up (odd_len vs))], l+1)
75                   else (List [Push RAX; Const RAX (n2w n)], l+2)
76End
77
78Definition find_def:
79  find n [] k = k ���
80  find n (NONE::vs) k = find n vs (k+1) ���
81  find n (SOME v::vs) k = if v = (n:num) then k else find n vs (k+1)
82End
83
84Definition c_var_def:
85  c_var l n vs =
86    let k = find n vs 0 in
87      if k = 0 then (List [Push RAX], l+1) else
88        (List [Push RAX; Load_RSP RAX k], l+2)
89End
90
91Definition c_add_def:
92  c_add vs = [Pop RDI; Add RAX RDI; Jump (Less R13 RAX) (give_up (even_len vs))]
93End
94
95Definition c_sub_def:
96  c_sub l = [Pop RDI;
97             Jump (Less RAX RDI) (l+3); (* i.e. skip the next instruction *)
98             Mov RAX RDI;
99             Sub RDI RAX;
100             Mov RAX RDI]
101End
102
103Definition c_div_def:
104  c_div = [Mov RDI RAX;
105           Pop RAX;
106           Const RDX 0w;
107           Div RDI]
108End
109
110Definition c_cons_def:
111  c_cons vs = if even_len vs (* stack must be aligned at call *)
112              then [Load_RSP RDI 0; Call AllocLoc; Pop RDI]
113              else [Pop RDI; Call AllocLoc]
114End
115
116Definition c_head_def:
117  c_head = [Load RAX RAX 0w]
118End
119
120Definition c_tail_def:
121  c_tail = [Load RAX RAX 8w]
122End
123
124Definition align_def:
125  align b cs = if b then [Push RAX]++cs++[Pop RDI] else cs
126End
127
128Definition c_read_def:
129  c_read vs = align (even_len vs) [Push RAX; GetChar]
130End
131
132Definition c_write_def:
133  c_write vs = align (even_len vs) [Mov RDI RAX; PutChar; Const RAX 0w]
134End
135
136Definition c_op_def:
137  c_op Add vs l = c_add vs ���
138  c_op Sub vs l = c_sub l ���
139  c_op Div vs l = c_div ���
140  c_op Cons vs l = c_cons vs ���
141  c_op Head vs l = c_head ���
142  c_op Tail vs l = c_tail ���
143  c_op Read vs l = c_read vs ���
144  c_op Write vs l = c_write vs
145End
146
147Definition c_test_def:
148  c_test (c:source_syntax$test) target =
149    let cond = (case c of Equal => Equal RDI RBX | Less => Less RDI RBX) in
150      [Mov RBX RAX; Pop RDI; Pop RAX; Jump cond target]
151End
152
153Definition c_if_def:
154  c_if t test (c1,l1) (c2,l2) (c3,l3) =
155    (Append c1 (Append (List (c_test test (l2 + if t then 0 else 1)))
156               (Append c2 (Append (List (if t then [] else [Jump Always l3])) c3))),l3)
157End
158
159Definition c_pops_def:
160  c_pops xs vs =
161    let k = LENGTH xs in
162      if k = 0 then [Push RAX] else
163      if k = 1 then [] else
164      if k = 2 then [Pop RDI] else
165      if k = 3 then [Pop RDI; Pop RDX] else
166      if k = 4 then [Pop RDI; Pop RDX; Pop RBX] else
167      if k = 5 then [Pop RDI; Pop RDX; Pop RBX; Pop RBP] else
168      otherwise [Jump Always (give_up (odd_len xs ��� odd_len vs))]
169End
170
171Definition call_env_def:
172  call_env [] acc = acc ���
173  call_env (x::xs) acc = call_env xs (SOME x :: acc)
174End
175
176Definition c_pushes_def:
177  c_pushes vs l =
178    let k = LENGTH vs in
179    let e = call_env vs [] in
180      if k = 0 then (List [], [NONE], l) else
181      if k = 1 then (List [],e,l) else
182      if k = 2 then (List [Push RDI],e,l + 1) else
183      if k = 3 then (List [Push RDX; Push RDI],e,l + 2) else
184      if k = 4 then (List [Push RBX; Push RDX; Push RDI],e,l + 3) else
185          otherwise (List [Push RBP; Push RBX; Push RDX; Push RDI],e,l + 4)
186End
187
188Definition c_call_def:
189  c_call t vs target xs (c,l) =
190    let ys = c_pops xs vs in
191      if t then
192        (Append c (Append (List ys)
193          (List [Add_RSP (LENGTH vs); Jump Always target])), l + LENGTH ys + 2)
194      else
195        let cs = align (even_len vs) [Call target] in
196          (Append c (Append (List ys) (List cs)), l + LENGTH ys + LENGTH cs)
197End
198
199Definition lookup_def:
200  lookup n [] = 0 ���
201  lookup n ((x,y)::xs) = if x = (n:num) then y else lookup n xs
202End
203
204Definition make_ret_def:
205  make_ret vs (c,l) =
206    (Append c (List [Add_RSP (LENGTH vs); Ret]), l + 2)
207End
208
209Definition c_exp_def:
210  c_exp t l vs fs z =
211    (if t then
212       case z of
213       | Let n x y =>
214           (let r1 = c_exp F l vs fs x in
215            let r2 = c_exp T (SND r1) (SOME n::vs) fs y in
216              (Append (FST r1) (Append (FST r2) (List [])), SND r2))
217       | If cmp xs y z =>
218           (let r1 = c_exps l vs fs xs in
219            let r2 = c_exp T (SND r1 + 4) vs fs z in
220            let r3 = c_exp T (SND r2) vs fs y in
221              c_if T cmp r1 r2 r3)
222       | Call n xs =>
223           (c_call T vs (lookup n fs) xs (c_exps l vs fs xs))
224       | _ => make_ret vs (c_exp F l vs fs z)
225     else
226       case z of
227       | Let n x y =>
228           (let r1 = c_exp F l vs fs x in
229            let r2 = c_exp F (SND r1) (SOME n::vs) fs y in
230              (Append (FST r1) (Append (FST r2) (List [Add_RSP 1])),SND r2+1))
231       | If cmp xs y z =>
232           (let r1 = c_exps l vs fs xs in
233            let r2 = c_exp F (SND r1 + 4) vs fs z in
234            let r3 = c_exp F (SND r2 + 1) vs fs y in
235              c_if F cmp r1 r2 r3)
236       | Call n xs =>
237           (c_call F vs (lookup n fs) xs (c_exps l vs fs xs))
238       | Const n => c_const l n vs
239       | Var n => c_var l n vs
240       | Op op xs =>
241           (let r1 = c_exps l vs fs xs in
242            let insts = c_op op vs (SND r1) in
243              (Append (FST r1) (List insts), SND r1 + LENGTH insts))) ���
244  c_exps l vs fs zs =
245    case zs of
246    | [] => (List [],l)
247    | (x::xs) => (let res1 = c_exp F l vs fs x in
248                  let res2 = c_exps (SND res1) (NONE::vs) fs xs in
249                    (Append (FST res1) (FST res2), SND res2))
250Termination
251  WF_REL_TAC ���inv_image (measure I LEX measure I)
252    (��x. case x of INL (t,l,vs,fs,x) => (exp_size x,if t then 1 else 0)
253                 | INR (l,vs,fs,xs) => (exp1_size xs,0))���
254End
255
256Definition c_exp'_def: (* rephrasing that is better for proofs *)
257  c_exp' t l vs fs (Let n x y) =
258    (let (c1,l') = c_exp' F l vs fs x in
259     let (c2,l'') = c_exp' t l' (SOME n::vs) fs y in
260       (Append c1 (Append c2 (List (if t then [] else [Add_RSP 1]))),
261        if t then l'' else l'' + 1)) ���
262  c_exp' t l vs fs (If test xs y z) =
263    (let (c1,l1) = c_exps' l vs fs xs in
264     let (c2,l2) = c_exp' t (l1 + 4) vs fs z in
265     let (c3,l3) = c_exp' t (l2 + if t then 0 else 1) vs fs y in
266       c_if t test (c1,l1) (c2,l2) (c3,l3)) ���
267  c_exp' t l vs fs (Call n xs) =
268    c_call t vs (lookup n fs) xs (c_exps' l vs fs xs) ���
269  c_exp' F l vs fs (Const n) = c_const l n vs ���
270  c_exp' F l vs fs (Var n) = c_var l n vs ���
271  c_exp' F l vs fs (Op op xs) =
272    (let (c,l0) = c_exps' l vs fs xs in
273     let insts = c_op op vs l0 in
274       (Append c (List insts),l0 + LENGTH insts)) ���
275  c_exp' T l vs fs (Const v10) = make_ret vs (c_exp' F l vs fs (Const v10)) ���
276  c_exp' T l vs fs (Var v11) = make_ret vs (c_exp' F l vs fs (Var v11)) ���
277  c_exp' T l vs fs (Op op xs) = make_ret vs (c_exp' F l vs fs (Op op xs)) ���
278  c_exps' l vs fs [] = (List [],l) ���
279  c_exps' l vs fs (x::xs) =
280    (let (c1,l') = c_exp' F l vs fs x in
281     let (c2,l'') = c_exps' l' (NONE::vs) fs xs in
282      (Append c1 c2,l''))
283Termination
284  WF_REL_TAC ���inv_image (measure I LEX measure I)
285    (��x. case x of INL (t,l,vs,fs,x) => (exp_size x,if t then 1 else 0)
286                 | INR (l,vs,fs,xs) => (exp1_size xs,0))���
287End
288
289Theorem c_exp'[simp]:
290  c_exp' = c_exp ��� c_exps' = c_exps
291Proof
292  once_rewrite_tac [EQ_SYM_EQ]
293  \\ fs [FUN_EQ_THM] \\ ho_match_mp_tac c_exp'_ind \\ rw []
294  \\ fs [c_exp'_def] \\ rw [Once c_exp_def] \\ rpt (pairarg_tac \\ fs [])
295QED
296
297Theorem c_exp_alt = c_exp'_def |> SIMP_RULE (srw_ss()) []
298Theorem c_exp_ind_alt = c_exp'_ind |> SIMP_RULE (srw_ss()) []
299
300Definition c_defun_def:
301  c_defun l (fs:(num # num) list) (Defun n vs body) =
302    let (c0,vs0,l0) = c_pushes vs l in
303    let (c1,l1) = c_exp T l0 vs0 fs body in
304      (Append c0 c1,l1)
305End
306
307Definition name_of_def:
308  name_of (Defun n _ _) = n
309End
310
311Definition name2str_def:
312  name2str n acc =
313    if n = 0 then acc else name2str (n DIV 256) (CHR (n MOD 256) :: acc)
314End
315
316Definition c_decs_def:
317  c_decs l fs [] = (List [],[],l) ���
318  c_decs l fs (d::ds) =
319    let fname = name_of d in
320    let comment = List [Comment (name2str fname [])] in
321    let r1 = c_defun (l+1) fs d in
322    let r2 = c_decs (SND r1) fs ds in
323      (Append comment (Append (FST r1) (FST r2)),
324       (fname,l+1)::(FST (SND r2)),
325       SND (SND r2))
326End
327
328Definition codegen_def:
329  codegen (Program funs main) =
330    let init_l = LENGTH (init 0) in
331    let (_,fs,k) = c_decs init_l [] funs in
332    let (c,fs,_) = c_decs init_l fs (funs ++ [Defun (name "main") [] main]) in
333      flatten (Append (List (init (k+1))) c) []
334End
335
336val _ = export_theory();
337