desug.ml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. open Printf
  2. open Types
  3. open Util
  4. (* Create new constant variables for all assigned array values so that they are
  5. * only 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. (* Add vardecs for values in arrayconst *)
  22. | VarDec (ArrayDims _ as ctype, name, Some (ArrayConst (values, vann)), ann) ->
  23. let (new_vars, values) = create_vars [] [] values in
  24. let value = ArrayConst (values, vann) in
  25. let create_vardec (name, value) =
  26. VarDec (basetypeof node, name, Some value, annof value)
  27. in
  28. let new_vardecs = List.map create_vardec new_vars in
  29. Block (new_vardecs @ [VarDec (ctype, name, Some value, ann)])
  30. (* Add vardec for scalar value *)
  31. | VarDec (ArrayDims _ as ctype, name, Some value, ann) as node ->
  32. let scalar_name = fresh_const "scalar" in
  33. Block [
  34. VarDec (basetypeof node, scalar_name, Some value, ann);
  35. VarDec (ctype, name, Some (Var (scalar_name, None, annof value)), ann);
  36. ]
  37. | node -> transform_children consts_to_vars node
  38. let make_dims make_dimname values make_dec =
  39. let names = mapi make_dimname values in
  40. let decs = List.map2 make_dec values names in
  41. let make_dim value name = Dim (name, annof value) in
  42. let dims = List.map2 make_dim values names in
  43. (decs, dims)
  44. (* Generate new variables for array dimensions, to avoid re-evalutation when
  45. * array dimensions are used (e.g., after array dimension reduction). *)
  46. let rec array_dims node =
  47. match node with
  48. | VarDec (ArrayDims (ctype, values), name, init, ann) ->
  49. (* Names for VarDec dimensions must be unique to avoid weid errors when
  50. * during context analysis, when an array variable is redeclared within the
  51. * same scope *)
  52. let make_dimname i _ = fresh_const (name ^ "$" ^ string_of_int (i + 1)) in
  53. let make_dec value name = VarDec (Int, name, Some value, []) in
  54. let (decs, dims) = make_dims make_dimname values make_dec in
  55. Block (decs @ [VarDec (ArrayDims (ctype, dims), name, init, ann)])
  56. | GlobalDef (export, ArrayDims (ctype, values), name, init, ann) ->
  57. (* For global decs, the name must also be unique, but not constant (no $$in
  58. * the name) since the variable must exist for exporting *)
  59. let make_dimname i _ = fresh_var (name ^ "$" ^ string_of_int (i + 1)) in
  60. let make_dec value name = GlobalDef (export, Int, name, Some value, []) in
  61. let (decs, dims) = make_dims make_dimname values make_dec in
  62. Block (decs @ [GlobalDef (export, ArrayDims (ctype, dims), name, init, ann)])
  63. (* DISABLED, this is also done in extern.ml
  64. | GlobalDec (ArrayDims (ctype, values), name, ann) ->
  65. (*
  66. let rec make_decs = function
  67. | [] -> []
  68. | Dim (name, ann) :: tl -> GlobalDec (Int, name, ann) :: (make_decs tl)
  69. | _ -> raise InvalidNode
  70. in
  71. let decs = make_decs values in
  72. Block (decs @ [GlobalDec (ArrayDims (ctype, dims), name, ann)])
  73. *)
  74. let make_dec value name = GlobalDec (Int, name, []) in
  75. let (decs, dims) = make_dims name values make_dec in
  76. Block (decs @ [GlobalDec (ArrayDims (ctype, dims), name, ann)])
  77. *)
  78. | node -> transform_children array_dims node
  79. (* Split variable initialisation into declaration and assignment *)
  80. let rec split_inits = function
  81. (* Wrap array initialisation in ArrayInit to pass dimensions *)
  82. | VarDec (ArrayDims (_, dims) as ctype, name, Some value, ann) ->
  83. Block [
  84. VarDec (ctype, name, None, ann);
  85. Assign (name, None, ArrayInit (value, dims), ann);
  86. ]
  87. | GlobalDef (export, (ArrayDims (_, dims) as ctype), name, Some value, ann) ->
  88. Block [
  89. GlobalDef (export, ctype, name, None, ann);
  90. Assign (name, None, ArrayInit (value, dims), ann);
  91. ]
  92. | VarDec (ctype, name, Some init, ann) ->
  93. Block [
  94. VarDec (ctype, name, None, ann);
  95. Assign (name, None, init, ann);
  96. ]
  97. | GlobalDef (export, ctype, name, Some init, ann) ->
  98. Block [
  99. GlobalDef (export, ctype, name, None, ann);
  100. Assign (name, None, init, ann);
  101. ]
  102. | node -> transform_children split_inits node
  103. (* Add <allocate> statements after array declarations *)
  104. let rec add_allocs node =
  105. let create_dimvar = function
  106. | Dim (name, _) -> Var (name, None, [])
  107. | _ -> raise InvalidNode
  108. in
  109. match node with
  110. | VarDec (ArrayDims (_, dims), _, _, ann) ->
  111. Block [node; Allocate (node, List.map create_dimvar dims, ann)]
  112. | GlobalDef (_, ArrayDims (_, dims), _, _, ann) ->
  113. Block [node; Allocate (node, List.map create_dimvar dims, ann)]
  114. | node -> transform_children add_allocs node
  115. let extract_inits lst =
  116. let rec trav inits = function
  117. | [] ->
  118. (List.rev inits, [])
  119. | (Assign _ as hd) :: tl
  120. | (Allocate _ as hd) :: tl ->
  121. trav (hd :: inits) tl
  122. | hd :: tl ->
  123. let (inits, tl) = trav inits tl in
  124. (inits, (hd :: tl))
  125. in trav [] lst
  126. let rec move_inits = function
  127. (* Move global initialisations to __init function *)
  128. | Program (decls, ann) ->
  129. let decls = List.map move_inits decls in
  130. begin match extract_inits decls with
  131. | ([], _) -> Program (decls, ann)
  132. | (inits, decls) ->
  133. let body = Block (VarDecs [] :: LocalFuns [] :: inits) in
  134. let init_func = FunDef (true, Void, "__init", [], body, []) in
  135. Program (init_func :: decls, ann)
  136. end
  137. (* DISABLED, interleaved declarations and assignments are allowed in the
  138. * intermediate representation
  139. | FunDef (export, ret_type, name, params, Block body, ann) ->
  140. let rec place_inits inits = function
  141. | VarDecs lst :: tl ->
  142. let (inits, decs) = extract_inits lst in
  143. VarDecs decs :: (place_inits inits tl)
  144. | LocalFuns _ as hd :: tl ->
  145. hd :: inits @ tl
  146. | _ -> raise InvalidNode
  147. in
  148. let body = Block (place_inits [] body) in
  149. FunDef (export, ret_type, name, params, body, ann)
  150. *)
  151. | node -> transform_children move_inits node
  152. let for_to_while node =
  153. let rec replace_var var replacement node =
  154. let trav = (replace_var var replacement) in
  155. match node with
  156. | Var (name, None, ann) when name = var ->
  157. Var (replacement, None, ann)
  158. | For (counter, start, stop, step, body, ann) when counter = var ->
  159. For (replacement, trav start, trav stop, trav step, trav body, ann)
  160. | node ->
  161. transform_children trav node
  162. in
  163. let rec traverse new_vars = function
  164. | FunDef (export, ret_type, name, params, body, ann) ->
  165. let rec place_decs decs = function
  166. | Block (VarDecs lst :: tl) -> Block (VarDecs (decs @ lst) :: tl)
  167. | _ -> raise InvalidNode
  168. in
  169. let new_vars = ref [] in
  170. let body = traverse new_vars body in
  171. let create_vardec name = VarDec (Int, name, None, []) in
  172. let new_vardecs = List.map create_vardec !new_vars in
  173. let body = place_decs new_vardecs body in
  174. FunDef (export, ret_type, name, params, body, ann)
  175. (* Transform for-loops to while-loops *)
  176. | For (counter, start, stop, step, body, ann) ->
  177. let _i = fresh_var counter in
  178. let _stop = fresh_const "stop" in
  179. let _step = fresh_const "step" in
  180. new_vars := !new_vars @ [_i; _stop; _step];
  181. let vi = Var (_i, None, []) in
  182. let vstop = Var (_stop, None, annof stop) in
  183. let vstep = Var (_step, None, annof step) in
  184. let cond = Cond (
  185. Binop (Gt, vstep, Const (IntVal 0, []), []),
  186. Binop (Lt, vi, vstop, []),
  187. Binop (Gt, vi, vstop, []),
  188. []
  189. ) in
  190. Block [
  191. Assign (_i, None, start, annof start);
  192. Assign (_stop, None, stop, annof stop);
  193. Assign (_step, None, step, annof step);
  194. traverse new_vars (While (cond, (Block (
  195. block_body (replace_var counter _i body) @
  196. [Assign (_i, None, Binop (Add, vi, vstep, []), [])]
  197. )), ann));
  198. ]
  199. (* Transform while-loops to do-while loops in if-statements *)
  200. (* DISABLED, while-loops are explicitly supported by the assembly phase
  201. | While (cond, body, ann) ->
  202. let cond = traverse new_vars cond in
  203. let body = traverse new_vars body in
  204. Block [If (cond, Block [DoWhile (cond, body, ann)], ann)]
  205. *)
  206. | node -> transform_children (traverse new_vars) node
  207. in
  208. traverse (ref []) node
  209. let rec sublist n = function
  210. | [] when n > 0 -> raise (Invalid_argument "n")
  211. | [] -> []
  212. | lst when n = 0 -> lst
  213. | _ :: tl -> sublist (n - 1) tl
  214. let rec array_init = function
  215. (* Transform array constant initialisation into separate assign statements
  216. * for all entries in the constant array *)
  217. | Assign (name, None, ArrayInit (ArrayConst _ as value, dims), ann) ->
  218. let ndims = List.length dims in
  219. let rec make_assigns depth i indices = function
  220. | [] -> []
  221. | hd :: tl ->
  222. let assigns = traverse depth (i :: indices) hd in
  223. make_assigns depth (i + 1) indices tl @ assigns
  224. and traverse depth indices = function
  225. | ArrayConst (values, _) ->
  226. make_assigns (depth + 1) 0 indices values
  227. | value when depth = ndims ->
  228. let indices = List.map (fun i -> Const (IntVal i, [])) indices in
  229. [Assign (name, Some (List.rev indices), value, ann)]
  230. | value when depth < ndims ->
  231. (* Use the for-loops constructed for scalar assignment *)
  232. let value = ArrayInit (value, dims) in
  233. let indices = List.map (fun i -> Const (IntVal i, [])) indices in
  234. [array_init (Assign (name, Some (List.rev indices), value, ann))]
  235. | node ->
  236. let msg = sprintf
  237. "dimension mismatch: expected %d nesting levels, got %d"
  238. ndims depth
  239. in
  240. raise (NodeError (node, msg))
  241. in
  242. Block (List.rev (traverse 0 [] value))
  243. (* Replace no indices with empty indices to have a list below *)
  244. | Assign (name, None, (ArrayInit _ as value), ann) ->
  245. array_init (Assign (name, Some [], value, ann))
  246. | Assign (name, Some indices, ArrayInit (value, dims), ann) ->
  247. let rec add_loop indices = function
  248. | [] ->
  249. array_init (Assign (name, Some indices, value, ann))
  250. | dim :: rest ->
  251. let counter = fresh_var "i" in
  252. let start = Const (IntVal 0, []) in
  253. let step = Const (IntVal 1, []) in
  254. let body = Block [add_loop (indices @ [Var (counter, None, [])]) rest] in
  255. let stop = match dim with
  256. | Dim (name, ann) -> Var (name, None, ann)
  257. | _ -> dim
  258. in
  259. For (counter, start, stop, step, body, [])
  260. in
  261. let dims_left = sublist (List.length indices) dims in
  262. add_loop indices dims_left
  263. | node -> transform_children array_init node
  264. let phase = function
  265. | Ast node ->
  266. (* Generate variable declarations for expressions that must be evaluated
  267. * once and used multiple times *)
  268. let node = consts_to_vars (array_dims node) in
  269. (* Split variable initialisations into declarations and assignments, and
  270. * move the assignments to the function body *)
  271. let node = move_inits (add_allocs (split_inits node)) in
  272. (* Transform ArrayConst assignment to assignments in for-loops, and
  273. * transform all for-loops to while-loops afterwards *)
  274. Ast (for_to_while (array_init (node)))
  275. | _ -> raise (InvalidInput "desugar")