# HG changeset patch # User Adam Chlipala # Date 1312319054 14400 # Node ID a71223513c77d59de09d7fccae7ee4008d5bfe38 # Parent 52fbd8534ef3bf53f485d536cc0755d41fc6355c Compile self-tail-calls as gotos diff -r 52fbd8534ef3 -r a71223513c77 src/cjr_print.sml --- a/src/cjr_print.sml Tue Aug 02 14:45:19 2011 -0400 +++ b/src/cjr_print.sml Tue Aug 02 17:04:14 2011 -0400 @@ -1319,7 +1319,9 @@ | ESetval {seq = e1, count = e2} => potentiallyFancy e1 orelse potentiallyFancy e2 | EUnurlify _ => true -fun p_exp' par env (e, loc) = +val self = ref (NONE : int option) + +fun p_exp' par tail env (e, loc) = case e of EPrim p => Prim.p_t_GCC p | ERel n => p_rel env n @@ -1337,7 +1339,7 @@ | SOME t => t in if isUnboxable t then - p_exp' par env e + p_exp' par tail env e else box [string "({", newline, @@ -1355,7 +1357,7 @@ space, string "=", space, - p_exp' par env e, + p_exp' par false env e, string ";", newline, string "tmp;", @@ -1394,7 +1396,7 @@ space, string "=", space, - p_exp env e, + p_exp' false false env e, string ";", newline], string "tmp;", @@ -1404,7 +1406,7 @@ | ENone _ => string "NULL" | ESome (t, e) => if isUnboxable t then - p_exp' par env e + p_exp' par tail env e else box [string "({", newline, @@ -1422,7 +1424,7 @@ space, string "=", space, - p_exp' par env e, + p_exp' par false env e, string ";", newline, string "tmp;", @@ -1440,7 +1442,7 @@ string "uw_error(ctx, FATAL, \"", string (ErrorMsg.spanToString loc), string ": %s\", ", - p_exp env e, + p_exp' false false env e, string ");", newline, string "tmp;", @@ -1454,9 +1456,9 @@ string "tmp;", newline, string "uw_return_blob(ctx, ", - p_exp env blob, + p_exp' false false env blob, string ", ", - p_exp env mimeType, + p_exp' false false env mimeType, string ");", newline, string "tmp;", @@ -1470,16 +1472,16 @@ string "tmp;", newline, string "uw_redirect(ctx, ", - p_exp env e, + p_exp' false false env e, string ");", newline, string "tmp;", newline, string "})"] | EApp ((EError (e, (TFun (_, ran), _)), loc), _) => - p_exp env (EError (e, ran), loc) + p_exp' false false env (EError (e, ran), loc) | EApp ((EReturnBlob {blob, mimeType, t = (TFun (_, ran), _)}, loc), _) => - p_exp env (EReturnBlob {blob = blob, mimeType = mimeType, t = ran}, loc) + p_exp' false false env (EReturnBlob {blob = blob, mimeType = mimeType, t = ran}, loc) | EFfiApp ("Basis", "strcat", [e1, e2]) => let @@ -1490,12 +1492,12 @@ in case flatten e1 @ flatten e2 of [e1, e2] => box [string "uw_Basis_strcat(ctx, ", - p_exp env e1, + p_exp' false false env e1, string ",", - p_exp env e2, + p_exp' false false env e2, string ")"] | es => box [string "uw_Basis_mstrcat(ctx, ", - p_list (p_exp env) es, + p_list (p_exp' false false env) es, string ", NULL)"] end @@ -1510,35 +1512,88 @@ string "_", p_ident x, string "(ctx, ", - p_list (p_exp env) es, + p_list (p_exp' false false env) es, string ")"] | EApp (f, args) => - parenIf par (box [p_exp' true env f, - string "(ctx,", - space, - p_list_sep (box [string ",", space]) (p_exp env) args, - string ")"]) + let + fun default () = parenIf par (box [p_exp' true false env f, + string "(ctx,", + space, + p_list_sep (box [string ",", space]) (p_exp' false false env) args, + string ")"]) + + fun isSelf n = + let + val (_, t) = E.lookupENamed env n + + fun getSig (t, args) = + case #1 t of + TFun (dom, t) => getSig (t, dom :: args) + | _ => (args, t) + + val (argts, ret) = getSig (t, []) + in + parenIf par (box [string "({", + newline, + p_list_sepi newline + (fn i => fn (e, t) => + box [p_typ env t, + space, + string ("rearg" ^ Int.toString i), + space, + string "=", + space, + p_exp' false false env e, + string ";"]) + (ListPair.zip (args, argts)), + newline, + p_typ env ret, + space, + string "tmp;", + newline, + p_list_sepi newline + (fn i => fn _ => + box [p_rel env (E.countERels env - 1 - i), + space, + string "=", + space, + string ("rearg" ^ Int.toString i ^ ";")]) args, + newline, + string "goto restart;", + newline, + string "tmp;", + newline, + string "})"]) + end + in + case #1 f of + ENamed n => if SOME n = !self andalso tail then + isSelf n + else + default () + | _ => default () + end | EUnop (s, e1) => parenIf par (box [string s, space, - p_exp' true env e1]) + p_exp' true false env e1]) | EBinop (s, e1, e2) => if Char.isAlpha (String.sub (s, size s - 1)) then box [string s, string "(", - p_exp env e1, + p_exp' false false env e1, string ",", space, - p_exp env e2, + p_exp' false false env e2, string ")"] else - parenIf par (box [p_exp' true env e1, + parenIf par (box [p_exp' true false env e1, space, string s, space, - p_exp' true env e2]) + p_exp' true false env e2]) | ERecord (0, _) => string "0" @@ -1554,14 +1609,14 @@ space, string "{", p_list (fn (_, e) => - p_exp env e) xes, + p_exp' false false env e) xes, string "};", space, string "tmp;", space, string "})" ] | EField (e, x) => - box [p_exp' true env e, + box [p_exp' true false env e, string ".__uwf_", p_ident x] @@ -1574,7 +1629,7 @@ space, string "=", space, - p_exp env e, + p_exp' false false env e, string ";", newline, newline, @@ -1588,11 +1643,11 @@ string "?", space, if E.countERels env' = E.countERels env then - p_exp env e + p_exp' false tail env e else box [string "({", pb, - p_exp env' e, + p_exp' false tail env' e, string ";", newline, string "})"], @@ -1619,7 +1674,7 @@ string "})"] | EWrite e => box [string "(uw_write(ctx, ", - p_exp env e, + p_exp' false false env e, string "), 0)"] | ESeq (e1, e2) => @@ -1632,7 +1687,7 @@ space] else box [], - p_exp env e1, + p_exp' false false env e1, string ",", space, if useRegion then @@ -1640,7 +1695,7 @@ space] else box [], - p_exp env e2, + p_exp' false tail env e2, string ")"] end | ELet (x, t, e1, e2) => @@ -1663,7 +1718,7 @@ space] else box [], - p_exp env e1, + p_exp' false false env e1, if useRegion then string ")" else @@ -1675,7 +1730,7 @@ newline] else box [], - p_exp (E.pushERel env x t) e2, + p_exp' false tail (E.pushERel env x t) e2, string ";", newline, string "})"] @@ -1745,10 +1800,10 @@ space, string "=", space, - p_exp (E.pushERel - (E.pushERel env "r" (TRecord rnum, loc)) - "acc" state) - body, + p_exp' false false (E.pushERel + (E.pushERel env "r" (TRecord rnum, loc)) + "acc" state) + body, string ";", newline] in @@ -1764,7 +1819,7 @@ space, string "=", space, - p_exp env initial, + p_exp' false false env initial, string ";", newline, string "int dummy = (uw_begin_region(ctx), 0);", @@ -1773,7 +1828,7 @@ case prepared of NONE => box [string "char *query = ", - p_exp env query, + p_exp' false false env query, string ";", newline, newline, @@ -1792,7 +1847,7 @@ space, string "=", space, - p_exp env e, + p_exp' false false env e, string ";"]) inputs, newline, @@ -1827,7 +1882,7 @@ newline, case prepared of NONE => box [string "char *dml = ", - p_exp env dml, + p_exp' false false env dml, string ";", newline, newline, @@ -1845,7 +1900,7 @@ space, string "=", space, - p_exp env e, + p_exp' false false env e, string ";"]) inputs, newline, @@ -1877,7 +1932,7 @@ case prepared of NONE => #nextval (Settings.currentDbms ()) {loc = loc, - seqE = p_exp env seq, + seqE = p_exp' false false env seq, seqName = case #1 seq of EPrim (Prim.String s) => SOME s | _ => NONE} @@ -1896,8 +1951,8 @@ newline, #setval (Settings.currentDbms ()) {loc = loc, - seqE = p_exp env seq, - count = p_exp env count}, + seqE = p_exp' false false env seq, + count = p_exp' false false env count}, newline, newline, @@ -1929,7 +1984,7 @@ box [string "({", newline, string "uw_Basis_string request = uw_maybe_strdup(ctx, ", - p_exp env e, + p_exp' false false env e, string ");", newline, newline, @@ -1964,7 +2019,7 @@ box [string "({", newline, string "uw_Basis_string request = uw_maybe_strdup(ctx, ", - p_exp env e, + p_exp' false false env e, string ");", newline, newline, @@ -1974,7 +2029,7 @@ string "})"] end -and p_exp env = p_exp' false env +and p_exp env = p_exp' false true env fun p_fun isRec env (fx, n, args, ran, e) = let @@ -1995,6 +2050,11 @@ string ")", space, string "{", + if isRec then + box [string "restart:", + newline] + else + box [], newline, if isRec andalso Settings.getDeadlines () then box [string "uw_check_deadline(ctx);", @@ -2127,7 +2187,10 @@ (fn (_, dom) => p_typ env dom) args, string ");"]) vis, newline, - p_list_sep newline (p_fun true env) vis, + p_list_sep newline (fn vi as (_, n, _, _, _) => + (self := SOME n; + p_fun true env vi + before self := NONE)) vis, newline] end | DTable (x, _, pk, csts) => box [string "/* SQL table ", @@ -2249,7 +2312,8 @@ val () = (clearUrlHandlers (); unurlifies := IS.empty; urlifies := IS.empty; - urlifiesL := IS.empty) + urlifiesL := IS.empty; + self := NONE) val (pds, env) = ListUtil.foldlMap (fn (d, env) => let diff -r 52fbd8534ef3 -r a71223513c77 tests/fact.ur --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/fact.ur Tue Aug 02 17:04:14 2011 -0400 @@ -0,0 +1,5 @@ +fun fact n = if n <= 1 then 1 else n * fact (n - 1) + +fun factTr n acc = if n <= 1 then acc else factTr (n - 1) (n * acc) + +fun main () : transaction page = return {[fact 10]}, {[factTr 10 1]}