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