desug.ml 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. open Printf
  2. open Types
  3. open Util
  4. (* Create new constant variables for all ArrayConst values so that they are only
  5. * evaluated once *)
  6. let rec consts_to_vars node =
  7. let rec create_vars new_vars values = function
  8. | [] -> (new_vars, values)
  9. | hd :: tl ->
  10. let (new_vars, value) = match hd with
  11. | ArrayConst (values, ann) ->
  12. let (new_vars, values) = create_vars new_vars [] values in
  13. (new_vars, ArrayConst (values, ann))
  14. | value ->
  15. let index = fresh_const "const" in
  16. (new_vars @ [(index, value)], Var (index, None, annof value))
  17. in
  18. create_vars new_vars (values @ [value]) tl
  19. in
  20. match node with
  21. | VarDec (ctype, name, Some (ArrayConst (values, vann)), ann) ->
  22. let (new_vars, values) = create_vars [] [] values in
  23. let value = ArrayConst (values, vann) in
  24. let create_vardec (name, value) =
  25. VarDec (basetypeof node, name, Some value, annof value)
  26. in
  27. let new_vardecs = List.map create_vardec new_vars in
  28. Block (new_vardecs @ [VarDec (ctype, name, Some value, ann)])
  29. | node -> transform_children consts_to_vars node
  30. (* Generate new variables for array dimensions, to avoid re-evalutation when
  31. * array dimensions are used (e.g., after array dimension reduction). *)
  32. let rec array_dims node =
  33. let make_dims basename values make_dec =
  34. let make_name i _ = basename ^ "$dim$$" ^ string_of_int (i + 1) in
  35. let names = mapi make_name values in
  36. let decs = List.map2 make_dec values names in
  37. let make_dim value name = Dim (name, annof value) in
  38. let dims = List.map2 make_dim values names in
  39. (decs, dims)
  40. in
  41. match node with
  42. | VarDec (ArrayDims (ctype, values), name, init, ann) ->
  43. let make_dec value name = VarDec (Int, name, Some value, []) in
  44. let (decs, dims) = make_dims name values make_dec in
  45. Block (decs @ [VarDec (ArrayDims (ctype, dims), name, init, ann)])
  46. | GlobalDef (export, ArrayDims (ctype, values), name, None, ann) ->
  47. let make_dec value name = GlobalDef (export, Int, name, Some value, []) in
  48. let (decs, dims) = make_dims name values make_dec in
  49. Block (decs @ [GlobalDef (export, ArrayDims (ctype, dims), name, None, ann)])
  50. | GlobalDec (ArrayDims (ctype, dims), name, ann) ->
  51. let rec make_decs = function
  52. | [] -> []
  53. | Dim (name, ann) :: tl -> GlobalDec (Int, name, ann) :: (make_decs tl)
  54. | _ -> raise InvalidNode
  55. in
  56. let decs = make_decs dims in
  57. Block (decs @ [GlobalDec (ArrayDims (ctype, dims), name, ann)])
  58. | node -> transform_children array_dims node
  59. (* Split variable declaration and initialisation *)
  60. let rec split_inits = function
  61. (* Translate scalar array initialisation to ArrayScalar node,
  62. * for easy replacement later on *)
  63. | VarDec (ArrayDims (_, dims) as ctype, name, Some (Const _ as v), ann) ->
  64. let init = Some (ArrayInit (ArrayScalar v, dims)) in
  65. split_inits (VarDec (ctype, name, init, ann))
  66. (* Wrap ArrayConst in ArrayInit to pass dimensions *)
  67. | VarDec (ArrayDims (_, dims) as ctype, name, Some (ArrayConst _ as v), ann) ->
  68. let init = Some (ArrayInit (v, dims)) in
  69. split_inits (VarDec (ctype, name, init, ann))
  70. (* Variable initialisations are split into dec;assign *)
  71. | VarDec (ctype, name, Some init, ann) ->
  72. Block [
  73. VarDec (ctype, name, None, ann);
  74. Assign (name, None, init, ann);
  75. ]
  76. | GlobalDef (export, ctype, name, Some init, ann) ->
  77. Block [
  78. GlobalDef (export, ctype, name, None, ann);
  79. Assign (name, None, init, ann);
  80. ]
  81. | node -> transform_children split_inits node
  82. (* Add <allocate> statements after array declarations *)
  83. let rec add_allocs node =
  84. let create_dimvar = function
  85. | Dim (name, _) -> Var (name, None, [])
  86. | _ -> raise InvalidNode
  87. in
  88. match node with
  89. | VarDec (ArrayDims (_, dims), _, _, ann) ->
  90. Block [node; Allocate (node, List.map create_dimvar dims, ann)]
  91. | GlobalDef (_, ArrayDims (_, dims), _, _, ann) ->
  92. Block [node; Allocate (node, List.map create_dimvar dims, ann)]
  93. | node -> transform_children add_allocs node
  94. let extract_inits lst =
  95. let rec trav inits = function
  96. | [] ->
  97. (List.rev inits, [])
  98. | (Assign _ as hd) :: tl
  99. | (Allocate _ as hd) :: tl ->
  100. trav (hd :: inits) tl
  101. | hd :: tl ->
  102. let (inits, tl) = trav inits tl in
  103. (inits, (hd :: tl))
  104. in trav [] lst
  105. let rec move_inits = function
  106. (* Move global initialisations to __init function *)
  107. | Program (decls, ann) ->
  108. let decls = List.map move_inits decls in
  109. (match extract_inits decls with
  110. | ([], _) -> Program (decls, ann)
  111. | (inits, decls) ->
  112. let init_func = FunDef (true, Void, "__init", [], Block inits, []) in
  113. Program (init_func :: decls, ann)
  114. )
  115. (* Split local variable initialisations in declaration and assignment *)
  116. | FunDef (export, ret_type, name, params, Block body, ann) ->
  117. let rec place_inits inits = function
  118. | VarDecs lst :: tl ->
  119. let (inits, decs) = extract_inits lst in
  120. VarDecs decs :: (place_inits inits tl)
  121. | LocalFuns _ as hd :: tl ->
  122. hd :: inits @ tl
  123. | _ -> raise InvalidNode
  124. in
  125. let body = Block (place_inits [] body) in
  126. FunDef (export, ret_type, name, params, body, ann)
  127. | node -> transform_children move_inits node
  128. let for_to_while node =
  129. let rec replace_var var replacement node =
  130. let trav = (replace_var var replacement) in
  131. match node with
  132. | Var (name, None, ann) when name = var ->
  133. Var (replacement, None, ann)
  134. | For (counter, start, stop, step, body, ann) when counter = var ->
  135. For (replacement, trav start, trav stop, trav step, trav body, ann)
  136. | node ->
  137. transform_children trav node
  138. in
  139. let rec traverse new_vars = function
  140. | FunDef (export, ret_type, name, params, body, ann) ->
  141. let new_vars = ref [] in
  142. let body = traverse new_vars body in
  143. let create_vardec name = VarDec (Int, name, None, []) in
  144. let new_vardecs = List.map create_vardec !new_vars in
  145. let _body = new_vardecs @ (flatten_blocks (block_body body)) in
  146. FunDef (export, ret_type, name, params, Block _body, ann)
  147. (* Transform for-loops to while-loops *)
  148. | For (counter, start, stop, step, body, ann) ->
  149. let _i = fresh_var counter in
  150. let _stop = fresh_const "stop" in
  151. let _step = fresh_const "step" in
  152. new_vars := !new_vars @ [_i; _stop; _step];
  153. let vi = Var (_i, None, []) in
  154. let vstop = Var (_stop, None, annof stop) in
  155. let vstep = Var (_step, None, annof step) in
  156. let cond = Cond (
  157. Binop (Gt, vstep, Const (IntVal 0, []), []),
  158. Binop (Lt, vi, vstop, []),
  159. Binop (Gt, vi, vstop, []),
  160. []
  161. ) in
  162. Block [
  163. Assign (_i, None, start, annof start);
  164. Assign (_stop, None, stop, annof stop);
  165. Assign (_step, None, step, annof step);
  166. traverse new_vars (While (cond, (Block (
  167. block_body (replace_var counter _i body) @
  168. [Assign (_i, None, Binop (Add, vi, vstep, []), [])]
  169. )), ann));
  170. ]
  171. (* DISABLED, while-loops are explicitly supported by the assembly phase
  172. (* Transform while-loops to do-while loops in if-statements *)
  173. | While (cond, body, ann) ->
  174. let cond = traverse new_vars cond in
  175. let body = traverse new_vars body in
  176. Block [If (cond, Block [DoWhile (cond, body, ann)], ann)]
  177. *)
  178. | node -> transform_children (traverse new_vars) node
  179. in
  180. traverse (ref []) node
  181. let rec array_init = function
  182. (* Transform scalar assignment into nested for-loops *)
  183. | Assign (name, None, ArrayInit (ArrayScalar value, dims), ann) ->
  184. let rec add_loop indices = function
  185. | [] ->
  186. Assign (name, Some indices, value, ann)
  187. | dim :: rest ->
  188. let counter = fresh_var "i" in
  189. let body = Block [add_loop (indices @ [Var (counter, None, [])]) rest] in
  190. For (counter, Const (IntVal 0, []), dim, Const (IntVal 1, []), body, [])
  191. in
  192. add_loop [] dims
  193. (* Transform array constant inisialisation into separate assign statements
  194. * for all entries in the constant array *)
  195. (* TODO: only allow when array dimensions are constant? *)
  196. | Assign (name, None, ArrayInit (ArrayConst _ as value, dims), ann) ->
  197. let ndims = List.length dims in
  198. let rec make_assigns depth i indices = function
  199. | [] -> []
  200. | hd :: tl ->
  201. let assigns = traverse depth (i :: indices) hd in
  202. make_assigns depth (i + 1) indices tl @ assigns
  203. and traverse depth indices = function
  204. | ArrayConst (values, _) ->
  205. make_assigns (depth + 1) 0 indices values
  206. | value when depth = ndims ->
  207. let indices = List.map (fun i -> Const (IntVal i, [])) indices in
  208. [Assign (name, Some (List.rev indices), value, ann)]
  209. | node ->
  210. let msg = sprintf
  211. "dimension mismatch: expected %d nesting levels, got %d"
  212. ndims depth
  213. in
  214. raise (NodeError (node, msg))
  215. in
  216. Block (List.rev (traverse 0 [] value))
  217. | node -> transform_children array_init node
  218. let phase = function
  219. | Ast node ->
  220. (* Generate variable declarations for expressions that must be evaluated
  221. * once and used multiple times *)
  222. let node = consts_to_vars (array_dims node) in
  223. (* Split variable initialisations into declarations and assignments, and
  224. * move the assignments to the function body *)
  225. let node = move_inits (add_allocs (split_inits node)) in
  226. (* Transform ArrayConst assignment to assignments in for-loops, and
  227. * transform all for-loops to while-loops afterwards *)
  228. Ast (for_to_while (array_init (node)))
  229. | _ -> raise (InvalidInput "desugar")