assemble.ml 9.5 KB

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