Compare commits

...

5 commits

Author SHA1 Message Date
Théophile Bastian 93e20cf208 Light CPS: cleaner error when lightening non-value 2018-02-16 16:06:36 +01:00
Théophile Bastian f5783f2b2b Light CPS: implement lambdas 2018-02-16 15:48:56 +01:00
Théophile Bastian 613adf0621 Lighter CPS: first tentative version
Try to lighten the CPS transformation, using fewer continuations when
there is no need for one
2018-02-16 15:48:56 +01:00
Théophile Bastian b0cd872baf Make NotValue more explicit 2018-02-16 15:43:01 +01:00
Théophile Bastian 3ca59d6975 Add test for redefinition of variables 2018-02-16 15:42:47 +01:00
3 changed files with 80 additions and 30 deletions

View file

@ -3,7 +3,10 @@ module S = Lambda
(* The target calculus. *)
module T = Tail
exception NotValue (** <- Raised when trying to use a non-value term as such *)
exception NotValue of S.term
(** ^ Raised when trying to use a non-value term as such *)
exception NotLightCPSable of S.term
let freshId =
(** Generates a fresh variable name string *)
@ -26,11 +29,30 @@ let letCont name varName body next =
(** Allocates a block for a continuation, then runs [next] *)
T.LetBlo(name, T.Lam(T.NoSelf, [varName], body), next)
let rec has_calls (t: S.term): bool = match t with
| S.Var _ | S.Lit _ | S.BinOp _ -> false
| S.Lam _ -> false
(* A lambda itself may contain calls, but this call is not evaluated at
* declaration time *)
| S.App _ -> true
| S.IfZero (cond, tIf, tElse) ->
(* Cannot optimize continuation creation
List.exists has_calls [cond; tIf; tElse]
*)
true
| S.Print value ->
(* Cannot optimize continuation creation
has_calls value
*)
true
| S.Let (_, value, next) ->
List.exists has_calls [value; next]
let rec cps_value (t: S.term) : T.value = match t with
| S.Var v -> T.VVar v
| S.Lit v -> T.VLit v
| S.BinOp (l, op, r) -> T.VBinOp (cps_value l, op, cps_value r)
| S.Let _ | S.Lam _ | S.App _ | S.Print _ | S.IfZero _ -> raise NotValue
| S.Let _ | S.Lam _ | S.App _ | S.Print _ | S.IfZero _ -> raise (NotValue t)
let cps_value_as_term (t: S.term) (cont: T.variable): T.term =
T.TailCall(T.vvar cont, [cps_value t])
@ -40,42 +62,63 @@ let rec cps_term_inner (t: S.term) (cont: T.variable) (nameHint: string option)
| S.Var _ -> cps_value_as_term t cont
| S.Lit _ -> cps_value_as_term t cont
| S.BinOp _ -> cps_value_as_term t cont
| S.Lam (self, var, term) ->
let fName = freshBlockVarHinted nameHint
and innerCont = freshBlockVar () in
T.LetBlo(fName,
T.Lam(self, [var; innerCont], cps_term_inner term innerCont None),
T.TailCall(T.vvar cont, T.vvars [fName]))
| S.Lam _ as lambda ->
let fName = freshBlockVarHinted nameHint in
light_term fName lambda None @@
T.TailCall(T.vvar cont, T.vvars [fName])
| S.App (f, x) ->
let xCont = freshBlockVar ()
and fCont = freshBlockVar () in
let xVal = freshVarHinted nameHint
and fVal = freshVar () in
letCont xCont xVal (
letCont fCont fVal
(T.TailCall(T.vvar fVal, T.vvars [xVal; cont])) @@
(cps_term_inner f fCont None)) @@
cps_term_inner x xCont None
light_term xVal x None @@
light_term fVal f None @@
T.TailCall (T.vvar fVal, T.vvars [xVal; cont])
| S.Print term ->
let curCont = freshBlockVar ()
and termVal = freshVar () in
letCont curCont termVal (
T.Print(T.vvar termVal,
T.TailCall(T.vvar cont, T.vvars [termVal])))
(cps_term_inner term curCont None)
let termVal = freshVar () in
light_term termVal term None @@
T.Print (T.vvar termVal,
T.TailCall(T.vvar cont, T.vvars [termVal]))
| S.Let (var, value, next) ->
let curCont = freshBlockVar () in
letCont curCont var (cps_term_inner next cont None) @@
cps_term_inner value curCont (Some (Atom.hint var))
(* TODO still verbose here *)
light_term var value (Some (Atom.hint var)) @@
cps_term_inner next cont None
| S.IfZero (expr, tIf, tElse) ->
let curCont = freshBlockVar ()
and exprVal = freshVar () in
letCont curCont exprVal (T.IfZero(T.vvar exprVal,
(* TODO still verbose here *)
let exprVal = freshVar () in
light_term exprVal expr None @@
(T.IfZero (T.vvar exprVal,
cps_term_inner tIf cont None,
cps_term_inner tElse cont None)) @@
cps_term_inner expr curCont None
cps_term_inner tElse cont None))
and light_term varName valExpr valHint next =
match has_calls valExpr with
| true ->
let contName = freshBlockVar () in
letCont contName varName next @@
cps_term_inner valExpr contName valHint
| false -> (match valExpr with
(* This term has no calls: no need to CPS-transform it *)
| S.Var _ | S.Lit _ | S.BinOp _ ->
T.LetVal (
varName,
cps_value valExpr,
next)
| S.Let (subLetVar, subLetVal, subLetNext) ->
T.LetVal (
subLetVar,
cps_value subLetVal,
light_term varName subLetNext valHint next)
| S.Lam(self, lamVar, lamBody) ->
let lamCont = freshBlockVar () in
T.LetBlo (
varName, T.Lam(
self, [lamVar; lamCont],
cps_term_inner lamBody lamCont None),
next)
| S.App _ | S.Print _ | S.IfZero _ ->
raise (NotLightCPSable valExpr)
)
let cps_term (t: S.term): T.term =
(** Entry point. Transforms a [Lambda] term into a [Tail] term, applying a

1
src/tests/redef.exp Normal file
View file

@ -0,0 +1 @@
42

6
src/tests/redef.lambda Normal file
View file

@ -0,0 +1,6 @@
let increase = fun x -> x + 1 in
let increase = fun x ->
let lop = (increase x) in
lop + 1 in
print (increase 40)