diff options
-rw-r--r-- | autoload.c | 2 | ||||
-rw-r--r-- | stdlib/comp-opts.tl | 9 | ||||
-rw-r--r-- | stdlib/compiler.tl | 14 | ||||
-rw-r--r-- | txr.1 | 39 |
4 files changed, 48 insertions, 16 deletions
@@ -686,7 +686,7 @@ static val compiler_set_entries(val fun) }; val slname[] = { lit("shadow-fun"), lit("shadow-var"), lit("shadow-cross"), - lit("unused"), lit("log-level"), nil + lit("unused"), lit("log-level"), lit("opt-tail-calls"), nil }; autoload_sys_set(al_struct, sys_name, fun); autoload_set(al_struct, sname, fun); diff --git a/stdlib/comp-opts.tl b/stdlib/comp-opts.tl index bc0e7c59..c964f341 100644 --- a/stdlib/comp-opts.tl +++ b/stdlib/comp-opts.tl @@ -31,12 +31,11 @@ usr:shadow-cross usr:unused usr:constant-throws - usr:log-level) + usr:log-level + usr:opt-tail-calls) -(defsymacro %warning-syms% '(shadow-fun shadow-var shadow-cross - unused log-level constant-throws)) - -(defvar usr:*compile-opts* (new compile-opts unused t constant-throws t)) +(defvar usr:*compile-opts* (new compile-opts unused t constant-throws t + opt-tail-calls :)) (defmacro when-opt (compile-opt . forms) (with-gensyms (optval) diff --git a/stdlib/compiler.tl b/stdlib/compiler.tl index 37c5df56..6a49551a 100644 --- a/stdlib/compiler.tl +++ b/stdlib/compiler.tl @@ -342,7 +342,7 @@ ;; 0 - no optimization ;; 1 - constant folding, algebraics. -;; 2 - block elimination, frame elimination +;; 2 - block elimination, frame elimination, self tail calls ;; 3 - lambda/combinator lifting ;; 4 - control-flow: jump-threading, dead code ;; 5 - data-flow: dead registers, useless regisers @@ -1127,6 +1127,7 @@ (*top-level* nil) (tfn *tail-fun*) (tpos nil) + (tco *compile-opts*.opt-tail-calls) (pars (new (fun-param-parser par-syntax form))) (need-frame (or (plusp pars.nfix) pars.rest)) (nenv (if need-frame (new env up env co me) env)) @@ -1134,7 +1135,10 @@ (when (> pars.nfix %max-lambda-fixed-args%) (compile-warning form "~s arguments in a lambda (max is ~s)" pars.nfix %max-lambda-fixed-args%)) - (when (and tfn (eq tfn.lambda form)) + (when (and (caseq tco + (: (>= *opt-level* 2)) + ((t) t)) + tfn (eq tfn.lambda form)) (set tfn.env nenv tfn.label (gensym "l") tpos t)) @@ -2846,11 +2850,11 @@ (defmacro usr:with-compile-opts (:form form . clauses) (match-case clauses (() ()) - (((@(as op @(or nil t :warn :error @(integerp))) . @syms) . @rest) + (((@(as op @(or nil t :warn :error : @(integerp))) . @syms) . @rest) (each ((s syms)) - (unless (member s %warning-syms%) + (unless (member s (load-time (slots 'compile-opts))) (compile-error form - "~s isn't a recognized warning option" s))) + "~s isn't a recognized compile option" s))) ^(compiler-let ((*compile-opts* (let ((co (copy *compile-opts*))) (set ,*(mappend (ret ^(co.,@1 ,op)) syms)) @@ -95824,7 +95824,10 @@ are translated into calls to more efficient two-argument internal functions. .IP 2 Blocks which can be easily confirmed not to be used as exit points are removed. Variable frames in which no lexically captured variables are bound, and no -dynamic variables are bound, are eliminated. +dynamic variables are bound, are eliminated. Self tail-calls are optimized, +which is also controlled by the +.code opt-tail-calls +option. .IP 3 Lambda expressions and calls to combinator functions such as .code chain @@ -96084,12 +96087,13 @@ and not to propagate compiled versions of the macros which produced it. .mets (defstruct compile-opts () .mets \ \ shadow-fun shadow-var shadow-cross unused .mets \ \ log-level constant-throws) +.mets \ \ opt-tail-calls) .syne .desc The .code compile-opts structure represents compiler options: its slots are variables which affect -compiler behavior. +compiler behavior, including diagnostics and code generation. The compiler expects the special variable .code *compile-opts* to hold a @@ -96098,9 +96102,6 @@ structure. It is recommended to manipulate options using the .code with-compile-opts macro. -Currently, all of the options are diagnostic. In the future, there may be other -kinds of options. - Diagnostic options which are Boolean take on the values .codn nil , .codn t , @@ -96124,6 +96125,20 @@ The .code :error value indicates that the diagnostic will be an error. +Boolean code generation options are three-valued, taking on the symbols +.codn t , +.code nil +and +.code : +(colon). The +.code : +value indicates that the compiler decides whether the option is on or off, +in a way specific to that option. The +.code t +and +.code nil +values specify it directly, overriding any such logic. + The slots of .code compile-opts are as follows: @@ -96189,6 +96204,20 @@ by default. Controls whether the compiler issues diagnostics when it encounters a constant expression, whose evaluation throws an exception, such as .codn "(/ 0 0)" . +.coIP opt-tail-calls +Code generation option, controlling whether the compiler optimizes tail calls. +The default behavior, requested by the default value +.code : +is to turn on the optimization when the +.code *opt-level* +is at least 2. Optimizing tail calls means that when a function calls itself +by name, and the call occurs in a tail position, the call is translated to an +assignment of the parameter values from the call arguments, and a backwards +jump to the start of the function. All argument defaulting works as usual. If +the tail call requires default values for optional arguments, those expressions +are evaluated, even if they were previously evaluated on entry into the +function. Most contexts where the function returns the value of the self +call are tail positions. .RE .coNP Special Variable @ *compile-opts* |