You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
8.4 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. module M = import "data/map.ml"
  2. module S = import "data/set.ml"
  3. module Str = import "data/set.ml"
  4. open import "prelude.ml"
  5. open import "./lang.ml"
  6. open import "./lib/monads.ml"
  7. type addr =
  8. | Combinator of string
  9. | Local of int
  10. | Arg of int
  11. | Int of int
  12. type gm_code =
  13. | Push of addr
  14. | Update of int
  15. | Pop of int
  16. | Slide of int
  17. | Alloc of int
  18. | Unwind
  19. | Mkap
  20. | Add | Sub | Mul | Div | Eval
  21. | Iszero of list gm_code * list gm_code
  22. | Pack of int * int
  23. | Casejump of list (int * list gm_code)
  24. instance show gm_code begin
  25. let show = function
  26. | Mkap -> "Mkap"
  27. | Unwind -> "Unwind"
  28. | Push (Combinator k) -> "Push " ^ k
  29. | Push (Arg i) -> "Pusharg " ^ show i
  30. | Push (Local i) -> "Pushlocal " ^ show i
  31. | Push (Int i) -> "Pushint " ^ show i
  32. | Update n -> "Update " ^ show n
  33. | Pop n -> "Pop " ^ show n
  34. | Slide n -> "Slide " ^ show n
  35. | Alloc n -> "Alloc " ^ show n
  36. | Add -> "Add"
  37. | Mul -> "Mul"
  38. | Sub -> "Sub"
  39. | Div -> "Div"
  40. | Eval -> "Eval"
  41. | Pack (arity, tag) -> "Pack{" ^ show arity ^ "," ^ show tag ^ "}"
  42. | Casejump xs -> "Casejump " ^ show xs
  43. | Iszero xs -> "Iszero " ^ show xs
  44. end
  45. type program_item =
  46. | Sc of string * int * list gm_code
  47. | Fd of fdecl
  48. instance show program_item begin
  49. let show = function
  50. | Sc p -> show p
  51. | Fd _ -> "<foreign item>"
  52. end
  53. let rec lambda_lift strict = function
  54. | Ref v -> pure (Ref v)
  55. | Lit v -> pure (Lit v)
  56. | App (f, x) -> (| app (lambda_lift false f) (lambda_lift false x) |)
  57. | Lam (v, x) ->
  58. let! body = lambda_lift true x
  59. let! (i, defs, known_sc) = get
  60. let vars =
  61. x |> free_vars
  62. |> S.delete v
  63. |> flip S.difference known_sc
  64. |> S.members
  65. let def = ("Lam" ^ show i, vars ++ [v], body)
  66. let app = foldl (fun f -> app f # Ref) (Ref ("Lam" ^ show i)) vars
  67. put (i + 1, Decl def :: defs, known_sc)
  68. |> map (const app)
  69. | Case (sc, alts) ->
  70. let! sc = lambda_lift true sc
  71. let! alts = traverse (fun (c, args, e) -> (c,args,) <$> lambda_lift true e) alts
  72. let case = Case (sc, alts)
  73. if strict then
  74. pure case
  75. else
  76. let! (i, defs, known_sc) = get
  77. let vars =
  78. case
  79. |> free_vars
  80. |> flip S.difference known_sc
  81. |> S.members
  82. let def = ("Case" ^ show i, vars, case)
  83. let app = foldl (fun f -> app f # Ref) (Ref ("Case" ^ show i)) vars
  84. put (i + 1, Decl def :: defs, known_sc)
  85. |> map (const app)
  86. | Let (vs, e) ->
  87. let! vs = flip traverse vs @@ fun (v, e) ->
  88. (v,) <$> lambda_lift false e
  89. let! e = lambda_lift true e
  90. pure (Let (vs, e))
  91. | If _ -> error "if expression in lambda-lifting"
  92. let rec eta_contract = function
  93. | Decl (n, a, e) as dec ->
  94. match a, e with
  95. | [], _ -> dec
  96. | xs, App (f, Ref v) ->
  97. if v == last xs && not (S.member v (free_vars f)) then
  98. eta_contract (Decl (n, init a, f))
  99. else
  100. dec
  101. | _, _ -> dec
  102. | Data c -> Data c
  103. | Foreign i -> Foreign i
  104. let rec lambda_lift_sc = function
  105. | Decl (n, a, e) ->
  106. match e with
  107. | Lam (v, e) -> lambda_lift_sc (Decl (n, a ++ [v], e))
  108. | _ ->
  109. let! e = lambda_lift true e
  110. let! _ = modify (fun (a, b, s) -> (a, b, S.insert n s))
  111. pure (Decl (n, a, e))
  112. | Data c -> Data c |> pure
  113. | Foreign (Fimport { var } as i) ->
  114. let! _ = modify (second (second (S.insert var)))
  115. Foreign i |> pure
  116. type dlist 'a <- list 'a -> list 'a
  117. let cg_prim (Fimport { var, fent }) =
  118. let prim_math_op x =
  119. [ Push (Arg 0), Eval, Push (Arg 2), Eval, x, Update 2, Pop 2, Unwind ]
  120. let prim_equality =
  121. [ Push (Arg 0), Eval (* x, arg0, arg1, arg2, arg3 *)
  122. , Push (Arg 2), Eval (* y, x, arg0, arg1, arg2, arg3 *)
  123. , Sub (* y - x, arg0, arg1, arg2, arg3 *)
  124. , Iszero ([ Pack (0, 0) ], [ Pack (0, 1) ])
  125. , Update 2, Pop 2, Unwind ]
  126. match fent with
  127. | "add" -> (Sc (var, 2, prim_math_op Add), Add)
  128. | "sub" -> (Sc (var, 2, prim_math_op Sub), Sub)
  129. | "mul" -> (Sc (var, 2, prim_math_op Mul), Mul)
  130. | "div" -> (Sc (var, 2, prim_math_op Div), Div)
  131. | "equ" -> (Sc (var, 2, prim_equality), Unwind)
  132. | "seq" -> (Sc (var, 2, [ Push (Arg 0), Eval, Update 0, Push (Arg 2), Update 2, Pop 2, Unwind]), Eval)
  133. | e -> error @@ "No such primitive " ^ e
  134. type slot = As of int | Ls of int
  135. let offs n = function
  136. | As x -> As (x + n)
  137. | Ls x -> Ls (x + n)
  138. let incr = offs 1
  139. let private prim_scs : ref (M.t string gm_code) = ref M.empty
  140. let private is_arith_op = function
  141. | Add | Sub | Mul | Div | Iszero _ -> true
  142. | _ -> false
  143. let rec compile_lazy (env : M.t string slot) = function
  144. | Ref v ->
  145. match M.lookup v env with
  146. | Some (As i) -> (Push (Arg i) ::)
  147. | Some (Ls i) -> (Push (Local i) ::)
  148. | None -> (Push (Combinator v) ::)
  149. | App (f, x) ->
  150. let f = compile_lazy env f
  151. let x = compile_lazy (map incr env) x
  152. f # x # (Mkap ::)
  153. | Lam _ ->
  154. error "Can not compile lambda expression, did you forget to lift?"
  155. | If _ ->
  156. error "Can not compile if expression, did you forget to TC?"
  157. | Case _ ->
  158. error "Case expression in lazy context"
  159. | Lit i -> (Push (Int i) ::)
  160. | Let (vs, e) ->
  161. compile_let compile_lazy env vs e
  162. and compile_strict (env : M.t string slot) = function
  163. | Case (sc, alts) ->
  164. let rec go_alts = function
  165. | [] -> []
  166. | Cons ((_, args, exp), rest) ->
  167. let c_arity = length args
  168. let env =
  169. args
  170. |> flip zip [Ls k | with k <- [c_arity - 1, c_arity - 2 .. 0]]
  171. |> M.from_list
  172. |> M.union (offs (c_arity + 1) <$> env)
  173. (c_arity, compile_strict env exp [Slide (c_arity + 1)]) :: go_alts rest
  174. compile_strict env sc # (Casejump (go_alts alts) ::)
  175. | App (App (Ref f, x), y) as e ->
  176. match M.lookup f !prim_scs with
  177. | Some op when is_arith_op op ->
  178. compile_strict env x
  179. # compile_strict (incr <$> env) y
  180. # (op ::)
  181. | _ -> compile_lazy env e # (Eval ::)
  182. | e -> compile_lazy env e # (Eval ::)
  183. and compile_tail (env : M.t string slot) = function
  184. | Ref v ->
  185. match M.lookup v env with
  186. | Some (As i) -> (Push (Arg i) ::)
  187. | Some (Ls i) -> (Push (Local i) ::)
  188. | None -> (Push (Combinator v) ::)
  189. | App (f, x) ->
  190. let f = compile_tail env f
  191. let x = compile_lazy (map incr env) x
  192. f # x # (Mkap ::)
  193. | e -> compile_strict env e
  194. and compile_let cont env vs e =
  195. let n = length vs
  196. let env =
  197. vs
  198. |> map (fun (x, _) -> x)
  199. |> flip zip [Ls x | with x <- [n - 1, n - 2 .. 0]]
  200. |> M.from_list
  201. |> M.union (offs n <$> env)
  202. let defs = zip [1..n] vs
  203. let rec go : list (int * string * expr) -> dlist gm_code = function
  204. | [] -> id
  205. | Cons ((k, (_, exp)), rest) ->
  206. compile_lazy env exp # (Update (n - k) ::) # go rest
  207. (Alloc n ::) # go defs # cont env e # (Slide n ::)
  208. let supercomb (_, args, exp) =
  209. let env = M.from_list (zip args [0..length args])
  210. let k = compile_tail (M.from_list (zip args (As <$> [0..length args]))) exp
  211. k [Update (length env), Pop (length env), Unwind]
  212. let compile_cons =
  213. let rec go i = function
  214. | [] -> []
  215. | Cons (Constr (n, args), rest) ->
  216. let arity = length args
  217. let rec pushargs i =
  218. if i < arity then
  219. Push (Arg (2 * i)) :: pushargs (i + 1)
  220. else
  221. []
  222. Sc (n, arity, pushargs 0 ++ [ Pack (arity, i), Update (2 * arity), Pop (2 * arity), Unwind ])
  223. :: go (i + 1) rest
  224. go 0
  225. let program decs =
  226. let rec globals s = function
  227. | [] -> s
  228. | Cons (Decl (n, _, _), r) -> globals (S.insert n s) r
  229. | Cons (Data (_, _, c), r) ->
  230. globals (foldl (fun s (Constr (n, _)) -> S.insert n s) s c) r
  231. | Cons (Foreign (Fimport {var=n}), r) ->
  232. globals (S.insert n s) r
  233. let (decs, (_, lams, _)) =
  234. run_state (traverse (map eta_contract # lambda_lift_sc) decs)
  235. (0, [], globals S.empty decs)
  236. let define nm k =
  237. let! x = get
  238. if nm `S.member` x then
  239. pure []
  240. else
  241. let! _ = modify (S.insert nm)
  242. k
  243. let go =
  244. flip traverse (lams ++ decs) @@ function
  245. | Decl ((nm, args, _) as sc) ->
  246. define nm (
  247. let code = supercomb sc
  248. [Sc (nm, length args, code)] |> pure
  249. )
  250. | Data (_, _, cs) -> pure (compile_cons cs)
  251. | Foreign (Fimport { cc = Prim, var } as fi) ->
  252. define var (
  253. let (code, h) = cg_prim fi
  254. prim_scs := M.insert var h !prim_scs
  255. pure [code]
  256. )
  257. | Foreign f -> pure [Fd f]
  258. let (out, _) = run_state go S.empty
  259. join out