assemble.ml 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. open Printf
  2. open Types
  3. open Util
  4. open Stringify
  5. open Globals
  6. let comline comment = InlineComment (EmptyLine, comment)
  7. let assemble program =
  8. let labcounter = ref 0 in
  9. let genlabel suffix =
  10. labcounter := !labcounter + 1;
  11. string_of_int !labcounter ^ "_" ^ suffix
  12. in
  13. let consts = Hashtbl.create 20 in
  14. let rec trav node =
  15. let rec trav_all = function
  16. | [] -> []
  17. | hd :: tl -> trav hd @ (trav_all tl)
  18. in
  19. let rec traverse_localfuns = function
  20. | LocalFuns body -> List.concat (List.map trav body)
  21. | Block body -> List.concat (List.map traverse_localfuns body)
  22. | _ -> []
  23. in
  24. match node with
  25. (* Global *)
  26. | Program (decls, _) ->
  27. trav_all decls
  28. | GlobalDef (_, ctype, name, _, _) ->
  29. [Comment (sprintf "global var \"%s\" at index %d" name (indexof node));
  30. Global ctype]
  31. | FunDec (ret_type, name, params, _) ->
  32. [Comment (sprintf "extern fun \"%s\" at index %d" name (indexof node));
  33. Import (name, ret_type, List.map typeof params)]
  34. | FunDef (export, ret_type, name, params, body, _) ->
  35. let label = labelof node in
  36. (if export then
  37. let param_types = List.map typeof params in
  38. [Export (name, ret_type, param_types, label)]
  39. else []) @
  40. [
  41. Comment (sprintf "fun \"%s\" with %d local vars" label (indexof node));
  42. Label label;
  43. RtnEnter (indexof node);
  44. ] @
  45. (trav body) @
  46. (match ret_type with Void -> [Ret Void] | _ -> []) @
  47. [EmptyLine] @
  48. (traverse_localfuns body)
  49. | VarDec (_, name, _, _) ->
  50. [comline (sprintf "local var \"%s\" at index %d" name (indexof node))]
  51. | LocalFuns _ -> []
  52. | Block body | VarDecs body -> trav_all body
  53. (* Statements *)
  54. | VarLet (dec, None, value, _) ->
  55. let store = match (depthof dec, depthof node) with
  56. | (0, _) -> Store (typeof dec, Glob, indexof dec)
  57. | (a, b) when a = b -> Store (typeof dec, Current, indexof dec)
  58. | (a, b) -> Store (typeof dec, Rel (b - a), indexof dec)
  59. in
  60. trav value @ [InlineComment (store, node2str node)]
  61. | Return (value, _) ->
  62. trav value @ [InlineComment (Ret (typeof value), node2str node)]
  63. | If (cond, body, _) ->
  64. let endlabel = genlabel "end" in
  65. (trav cond) @
  66. [Branch (false, endlabel);
  67. comline ("if (" ^ (node2str cond) ^ ") {")] @
  68. (trav body) @
  69. [comline "}";
  70. Label endlabel]
  71. | IfElse (cond, true_body, false_body, _) ->
  72. let elselabel = genlabel "else" in
  73. let endlabel = genlabel "end" in
  74. (trav cond) @
  75. [Branch (false, elselabel);
  76. comline ("if (" ^ (node2str cond) ^ ") {")] @
  77. (trav true_body) @
  78. [Jump endlabel;
  79. comline "} else {";
  80. Label elselabel] @
  81. (trav false_body) @
  82. [comline "}";
  83. Label endlabel]
  84. | While (cond, body, _) ->
  85. let startlabel = genlabel "while" in
  86. let endlabel = genlabel "end" in
  87. let com = ("while (" ^ (node2str cond) ^ ") {") in
  88. [Label startlabel] @
  89. (trav cond) @
  90. [InlineComment (Branch (false, endlabel), com)] @
  91. (trav body) @
  92. [Jump startlabel;
  93. Label endlabel;
  94. comline "}"]
  95. | DoWhile (cond, body, _) ->
  96. let startlabel = genlabel "dowhile" in
  97. let com = ("} while (" ^ (node2str cond) ^ ");") in
  98. [comline "do {";
  99. Label startlabel] @
  100. (trav body) @
  101. (trav cond) @
  102. [InlineComment (Branch (true, startlabel), com)]
  103. (* Expression statement pops the disregarded expression value from the
  104. * stack, if any *)
  105. | Expr value ->
  106. let pop = match typeof value with
  107. | Void -> [comline (node2str node)]
  108. | ctype -> [InlineComment (Pop ctype, node2str node)]
  109. in
  110. (trav value) @ pop
  111. (* Expressions *)
  112. (* Immediate values are handled here, and not in the peephole optimizer,
  113. * for convenience: the indices in the constant table would be altered,
  114. * so entries cannot be removed. By this early detection (also during
  115. * index analysis), they are not added in the first place *)
  116. | Const (value, _) when is_immediate_const value ->
  117. [InlineComment (LoadImm value, node2str node)]
  118. | Const (value, _) ->
  119. Hashtbl.replace consts value (indexof node);
  120. let load = LoadConst (typeof node, indexof node) in
  121. [InlineComment (load, node2str node)]
  122. | VarUse (dec, None, _) ->
  123. let load = match (depthof dec, depthof node) with
  124. | (0, _) -> Load (typeof dec, Glob, indexof dec)
  125. | (a, b) when a = b -> Load (typeof dec, Current, indexof dec)
  126. | (a, b) -> Load (typeof dec, Rel (b - a), indexof dec)
  127. in
  128. [InlineComment (load, node2str node)]
  129. | Monop (op, value, _) ->
  130. (trav value) @
  131. [InlineComment (Op (op, typeof value), op2str op)]
  132. | Binop (op, left, right, _) ->
  133. (trav left) @
  134. (trav right) @
  135. [InlineComment (Op (op, typeof left), op2str op)]
  136. | TypeCast (ctype, value, _) ->
  137. let vtype = typeof value in
  138. (match (ctype, vtype) with
  139. | (Float, Int) | (Int, Float) -> ()
  140. | _ ->
  141. let msg = sprintf
  142. "invalid typecast: %s -> %s"
  143. (type2str vtype) (type2str ctype)
  144. in raise (NodeError (node, msg))
  145. );
  146. trav value @ [Convert (vtype, ctype)]
  147. (* Function calls *)
  148. | FunUse (dec, args, _) ->
  149. let init = match (depthof dec, depthof node) with
  150. | (0, _) -> RtnInit Glob
  151. | (a, b) when a = b - 1 -> RtnInit Current
  152. | (a, b) when a = b -> RtnInit Local
  153. | (a, b) -> RtnInit (Rel (b - a - 1))
  154. in
  155. let jmp = match dec with
  156. | FunDec _ -> RtnJmp (ExternFun (indexof dec))
  157. | FunDef _ -> RtnJmp (LocalFun (List.length args, labelof dec))
  158. | _ -> raise InvalidNode
  159. in
  160. init :: (trav_all args) @ [jmp]
  161. | Arg value -> trav value
  162. (* Conditional expression (short-circuit evaluation) *)
  163. (* <cond>
  164. * branch_f else
  165. * <true_expr>
  166. * jump end
  167. * else:
  168. * <false_expr>
  169. * end:
  170. *)
  171. | Cond (cond, texp, fexp, _) ->
  172. let elselabel = genlabel "false_expr" in
  173. let endlabel = genlabel "end" in
  174. (trav cond) @
  175. [Branch (false, elselabel)] @
  176. (trav texp) @
  177. [Jump (endlabel);
  178. Label (elselabel)] @
  179. (trav fexp) @
  180. [InlineComment (Label (endlabel), node2str node)]
  181. (* Arrays *)
  182. | Allocate (dec, dims, _) ->
  183. let store = match (depthof dec, depthof node) with
  184. | (0, _) -> Store (typeof dec, Glob, indexof dec)
  185. | (a, b) when a = b -> Store (typeof dec, Current, indexof dec)
  186. | _ -> raise InvalidNode
  187. in
  188. trav_all dims @
  189. [NewArray (basetypeof dec, List.length dims);
  190. InlineComment (store, node2str node)]
  191. | VarUse (dec, Some dims, _) ->
  192. let load = match (depthof dec, depthof node) with
  193. | (0, _) -> Load (typeof dec, Glob, indexof dec)
  194. | (a, b) when a = b -> Load (typeof dec, Current, indexof dec)
  195. | (a, b) -> Load (typeof dec, Rel (b - a), indexof dec)
  196. in
  197. (trav_all (List.rev dims)) @ (* push dimensions *)
  198. [InlineComment (load, nameof dec)] @ (* push array reference *)
  199. [InlineComment (LoadArray (basetypeof dec), node2str node)]
  200. | VarLet (dec, Some dims, value, _) ->
  201. let load = match (depthof dec, depthof node) with
  202. | (0, _) -> Load (typeof dec, Glob, indexof dec)
  203. | (a, b) when a = b -> Load (typeof dec, Current, indexof dec)
  204. | (a, b) -> Load (typeof dec, Rel (b - a), indexof dec)
  205. in
  206. (trav value) @ (* push value *)
  207. (trav_all dims) @ (* push dimensions *)
  208. [InlineComment (load, nameof dec)] @ (* push array reference *)
  209. [InlineComment (StoreArray (basetypeof dec), node2str node)]
  210. | _ -> [Comment ("FIXME: " ^ Stringify.node2str node)]
  211. (*| _ -> raise InvalidNode*)
  212. in
  213. let instrs = trav program in
  214. (* Sort aggregated constants and add definitions
  215. * If possible, this should be rewritten in the future because it's a little
  216. * cumbersome right now... *)
  217. let pairs = ref [] in
  218. let add_pair value index =
  219. let com = sprintf "index %d" index in
  220. pairs := (InlineComment (ConstDef value, com), index) :: !pairs;
  221. in
  222. Hashtbl.iter add_pair consts;
  223. let cmp (_, i) (_, j) = compare i j in
  224. let sorted_pairs = List.sort cmp !pairs in
  225. let const_defs = List.map (fun (d, _) -> d) sorted_pairs in
  226. instrs @ const_defs
  227. let phase = function
  228. | Ast node -> Assembly (assemble node)
  229. | _ -> raise (InvalidInput "assembly")