summaryrefslogtreecommitdiffstats
path: root/share
Commit message (Collapse)AuthorAgeFilesLines
...
* compiler: implement unwind-protect.Kaz Kylheku2018-03-241-0/+25
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Wire in unwind-protect case via comp-unwind-protect method. (compiler comp-unwind-protect): New method.
* compiler: implement mac-param-bind.Kaz Kylheku2018-03-241-0/+12
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Wire in tree-bind case via comp-mac-param-bind method. (compiler comp-mac-param-bind): New method.
* compiler: hoist quoting out of bind expander.Kaz Kylheku2018-03-231-8/+12
| | | | | | | | | | | * share/txr/stdlib/compiler.tl (expand-bind-mac-params): Take the context form and error forms as separate arguments instead of calculating one from the other. Moreover, they are no longer assumed to be objects to be quoted and inserted but rather expressions to be substituted into the code directly. This gives the caller flexibility to make them calculated. (compiler comp-tree-bind, compiler comp-tree-case): Make the compensating adjustments to preserve the behavior.
* asm: report instruction count in disassembly.Kaz Kylheku2018-03-231-2/+7
| | | | | | * share/txr/stdlib/asm.tl (assembler dis-listing): Return the number of instructions that were traversed. (disassemble-c-d): Print count after instruction listing.
* tree-bind et al: don't retain full form for errors.Kaz Kylheku2018-03-231-2/+3
| | | | | | | | | * share/txr/stdlib/compiler.tl (expand-bind-mac-params): We don't need the full form for error reporting, because only the leading symbol is reported in diagnostics. We do need the full form if the :form parameter is used. If :form is not used, then a compiled function need not carry the entire form in its data table.
* compiler: avoid using var symbol.Kaz Kylheku2018-03-231-5/+5
| | | | | | | | | var is sys:var when we're working in the system package. This sometimes confuses the code walker, because (sys:var X) is the implementation of the @X notation. * share/txr/stdlib/compiler.tl (expand-bind-mac-params): Use sym instead of var.
* compiler: constant-optimize prog1Kaz Kylheku2018-03-231-1/+2
| | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-prog1): prog1 already uses progn. When using progn, though, it should append the nil form to the tail, otherwise progn will spare the last from from being eliminated, leaving an unused constant in the data table.
* compiler: basic optimization in progn.Kaz Kylheku2018-03-231-2/+6
| | | | | | * share/txr/stdlib/compiler.tl (compiler comp-progn): Eliminate any form which is a constant or a symbol, unless it appears in the last position.
* compiler: optimizations in cond and if.Kaz Kylheku2018-03-231-34/+58
| | | | | | | | | | | | We optimize based on test being constant expressions. * share/txr/stdlib/compiler.tl (compiler comp-cond): Whenever a test is a constant null, we need not evaluate the forms in that case; the entire case basically disappears so we compile it to nil. We also need not consider any cases after the first case whose test is a constant true. (compiler comp-if): Optimize all situations when the test is constant.
* compiler: last cond case: don't jmp to end.Kaz Kylheku2018-03-231-5/+11
| | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-cond): Don't generate the jmp instruction at the end of the last case. Why do I bother; a simple peephole optimizer will eliminate these. I want a little better code, now! That's why.
* vm: change encoding of getv, setv and related.Kaz Kylheku2018-03-231-6/+6
| | | | | | | | | | | | | | | | | | | | | | | In most compiler uses of bindv, getv and setv, the operand which names the dynamic symbol is the data table: a d0-dff register. The source or destination register of the transfer could be anything. Therefore, the existing encoding is suboptimal: the symbol is being put into the full sized operand field of the instruction, and the source or destination register into the small, ten-bit extra field in the upper half. This breaks on cases like (set x y) where x is a deeply nested lexical variable and y is a dynamic variable. Let's reverse the encoding. * share/txr/stdlib/asm.tl (op-getv, op-setv): Reverse the operands. All derived opcodes follow this since they reuse the code via inheritance. * vm.c (vm_get_binding): Fetch the symbol from the small operand field rather than the main operand field. (vm_getsym, vm_getbind, vm_setsym, vm_bindv): Pull the destination or source from the main operand of the instruction rather than the small opreand.
* compiler: streamline tree-caseKaz Kylheku2018-03-231-20/+9
| | | | | | | | | | | | | | | | | | | | | | | | | The setting of an error variable upon destructuring mismatch is not useful; it just takes extra instructions to check for a colon return out of the body or that variable being set. Let's have expand-bind-mac-params generate code which returns that symbol itself of assigning to it. The caller can then specify : for the strict parameter. A destructuring mismatch turns into a : return value, exactly the same as the value which indicates "fall through to next case". * share/txr/stdlib/compiler.tl (compiler comp-tree-case): Don't generate the err-var; remove all references to it. Pass : to expand-bind-mac-params as the strict parameter, rather than err-var.sym. Generate much simplified code after the cfrag: just test for a colon and continue through to the next case or else branch to the end. In the last case, the fall through path precipiates to the end, so we insert an instruction to clobber the : in the return register with a nil. (expand-bind-mac-params): Eliminate assignments to strict; it doesn't function as a variable any longer. Return that symbol in the return-from forms.
* compiler: bug: dynamic var assignment.Kaz Kylheku2018-03-231-1/+1
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-setq): Fix reversed setv instruction operands.
* compiler: implement tree-case.Kaz Kylheku2018-03-221-0/+52
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Add tree-case case, handled via comp-tree-case method. (compiler comp-tree-case): New method.
* compiler: implement tree-bind special op.Kaz Kylheku2018-03-221-0/+134
| | | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Wire in tree-bind case via comp-tree-bind method. (compiler comp-tree-bind): New method. (expand-bind-mac-parse-params, expand-bind-mac-params): New functions.
* compiler: implement return-from and return.Kaz Kylheku2018-03-221-0/+18
| | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle return and return-from special forms. (compiler comp-return-from, compiler comp-return): New methods.
* compiler: sys:setq bug: wrong way mov.Kaz Kylheku2018-03-221-1/+1
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-setq): Fix reversed mov instruction arguments in lexical case.
* new special op sys:upenvKaz Kylheku2018-03-211-0/+1
| | | | | | | | | | | | | | | | | | | | | | | This is something that will be useful in compiling some forms. At first I added it to the compiler only, but it seems wise to have it in the interpreter also. (sys:upenv form) causes form to be treated as if it were not in the immediately surrounding lexical environment but its parent. Thus (let ((a 1)) (let ((a 2)) (list a (sys:upenv a)))) yields (2 1). This operator needs no special treatment in the expander; it is expanded as a function call. This is not 100% correct in the face of all conceivable use. For instance given (symacrolet ((a 1)) (let ((a 2)) (sys:upenv a))), we probably want sys:upenv to skip the inner environment at expansion time too so that a is replaced by 1. However, it is not documented for application use, and will never be used in such a situation in the compiler. * eval.c (op_upenv): New static function. (eval_init): Register sys:upenv special operator. * compiler.tl (compiler compile): Implement compiled version of sys:upenv.
* compiler: append-each: bugfix for non-lists.Kaz Kylheku2018-03-211-1/+1
| | | | | | | | | * share/txr/stdlib/compiler.tl: If a non-list sequence like a string or vector is being accumulated, we must have an append call, because the accumulation cell is never extended with new cells. After we replace the cdr of ,accum with a string or vector atom, (last ,accum) just finds ,accum and so then the cdr will be clobbered on the next iteration.
* compiler: let* bugfix: not extending env.Kaz Kylheku2018-03-211-2/+8
| | | | | | | | | | * share/txr/stdlib/compiler.tl (sys:env extend-var*): New method. (compiler comp-let): When doing sequential bindings, we must still add the variable to the environment even if there is no init-form. Oops! Since we're not doing any gensym renaming trick in this case but binding the real symbol directly, we need a binding method that allows duplicates.
* compiler: disallow duplicate symbols in same env.Kaz Kylheku2018-03-211-3/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We want to diagnose (let (a a)) and (lambda (a a)), as well as the analogous situations for function bindings. This is certainly ambiguous: if the code accesses a, which one was intended? The choice is undocumented and so this is a likely programming error; nobody will write code this deliberately, investigate what the implementation actually does, and then rely on that. However, multiple bindings of special variables are allowed. Duplicates are also allowed in sequential binding. Handling duplicates in let* binding creates the following problem: (a a) means that a should be initialized from the previous a. We would like to compile the init form in the environment in which the second a doesn't exist, yet indicate the destination location of the new a. Since we are clobbering one environment as we go by adding bindings to it, this is not possible. The solution is a rename hack: we introduce the new a as a gensym, so that it is invisible. We indicate the gensym's location as the destination register for the init-form code fragment. Then immediately after compiling the init-form, we rename the gensym variable. * share/txr/stdlib/compiler.tl (sys:env extend-var, sys:env extend-fun): Diagnose duplicates. (sys:env rename-var): New methods. * share/txr/stdlib/compiler.tl (compile comp-let): Bind to a gensym instead of the real symbol when binding sequentially. Then rename the symbol.
* compiler: handle sys:each-op special form.Kaz Kylheku2018-03-211-0/+21
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle sys:each-op with help of expand-each. (expand-each): New function.
* compiler: handle special forms and or.Kaz Kylheku2018-03-201-0/+27
| | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle and and or cases via comp-and-or method. (compiler comp-and-or): New method. This is based on comp-progn.
* compiler: handle dohash special formKaz Kylheku2018-03-201-0/+12
| | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle dohash by rewriting the form via expand-dohash, then compiling result. (expand-dohash): New function.
* compiler: lambda bug: wrong reg in defaulting.Kaz Kylheku2018-03-201-1/+1
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-lambda): To determine whether the argument is missing, we must test it for equivalence to the : symbol. What we're testing here is the wrong thing: the register which will hold the output of the default initform. That fragment would even be executed yet at this spot in the code, never mind being the wrong value to test.
* compiler: improve progn.Kaz Kylheku2018-03-201-6/+15
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-progn): If the suggested output register is a variable, progn should not use it for the discarded values of the leading forms, only for the last form. Writes to the variable space of the display are costly because in closures, the underlying vector of a given level has to be passed to gc_mutated. We use a new temp register for the discarded forms.
* compiler: bugfix: arg passing in progn dispatch.Kaz Kylheku2018-03-201-1/+1
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Fix nonsensical fourth argument expression in comp-progn call.
* compiler: let bugfix: wrong output register designated.Kaz Kylheku2018-03-201-1/+1
| | | | | | * share/txr/stdlib/compiler.tl (compiler comp-let): The returned fragment must specify boreg not oreg, because the output is either in oreg or bfrag.oreg.
* compiler: factor recurring conditional mov.Kaz Kylheku2018-03-201-29/+19
| | | | | | | | | | | | | Anyway, this kind of thing should really be (and will be) taken care of peephole optimization. But for now, it's nice to get somewhat better code without doing too much work. * share/txr/stdlib/compiler.tl (compiler comp-setq, compiler comp-cond, compiler cond-if, compiler cond-let, compiler comp-lambda, compiler comp-for): Replace occurrences of (if (nequal reg1 reg2) ^((mov ,reg ,reg2))) with call to maybe-mov. (maybe-mov): New function.
* compiler: handle if special formKaz Kylheku2018-03-201-0/+52
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle if case via comp-if method. (compiler comp-if): New method.
* compiler: handle cond special form.Kaz Kylheku2018-03-201-0/+54
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Handle cond case via comp-cond method. (compiler comp-cond): New method.
* compiler: dump warnings from form expansion.Kaz Kylheku2018-03-191-1/+3
| | | | | | | * share/txr/stdlib/compiler.tl (usr:compile-toplevel): Call release-deferred-warnings to dump accumulated warnings. Otherwise when we are working in the listener, the pent-up warnings get dumped in relation to the next input line.
* vm: bug: vm-desc created with incorrect display depth.Kaz Kylheku2018-03-191-3/+3
| | | | | | | | | | | | | | | | | | * share/txr/stdlib/compiler.tl (sys:env :postinit): The call to register the environment with the compiler must be outside of the unless form. Otherwise it never takes place, and so the compiler doesn't find the maximum number of environment levels, keeping the value at 2. The executing vm then accesses out of bounds memory when setting up display frames. (usr:compile-toplevel): Give the root environment the compiler. Not strictly necessary since we are constent in doing this elsewhere, so we are not relying on inheritance of the compiler from parent environment to child. * vm.c (vm_make_closure): assert added for the environment levels of the closure not exceeding the display depth given in the machine description. This was added during debugging and going off; I'm keeping it.
* vm: variadic arg closures bug 3/3.Kaz Kylheku2018-03-191-1/+1
| | | | | | | | | * share/txr/stdlib/asm.tl (op-close asm): Fix argument count check being incorrect in the variadic argument case, causing the assembler to blow up on a correct (close ...) instruction. The integer indicating the number of fixed args is one *less* than the number of arguments given to the instruction not one *more*.
* compiler: bug: inappropriate clobber in block.Kaz Kylheku2018-03-191-2/+2
| | | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-block): Don't use bfrag.oreg as the output register of block. Firstly, bfrag.oreg might be (t 0) which is read-only. Worse, bfrag.oreg could just be a variable from which the block obtains its return value; we mustn't clobber that location with block's dynamic return value. Not only mustn't but possibly we cannot: the location could be out of scope!
* compiler: bug: nil entered into data tab by block.Kaz Kylheku2018-03-191-1/+1
| | | | | | * share/txr/stdlib/compiler.tl (compiler comp-block): If the block is anonymous, just refer to (t 0) as the name; don't intern nil via get-dreg.
* compiler: use VM's function table for global calls.Kaz Kylheku2018-03-191-4/+23
| | | | | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler): New slots fidx-cntr, fidx and ftab. (compiler get-fidx, compiler get-funvec): New methods. (compiler comp-call-impl): New method. (compiler comp-call): Look up the symbol to determine whether the function lexical or global. Call comp-call-impl appropriately to generate a gcall or call. (usr:compile-toplevel): Obtain the funvec from the compiler and pass to vm-make-desc.
* asm: return original object from disassemble function.Kaz Kylheku2018-03-191-1/+2
| | | | | | | | * share/txr/stdlib/asm.tl (usr:disassemble): Return the object that was disassembled, rather than nil. This is useful in the listener: we can compile and disassemble something in one step, then have access to the compiled object via a listener variable.
* compiler: bug: lambda body uses inappropriate output reg.Kaz Kylheku2018-03-191-3/+5
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-lambda): The incoming oreg, which indicates where the surrounding context would like to put the closure, cannot be used for the output location of the lambda body. Because then when the closure is called, its return value will overwrite the location where the closure was placed. We must allocate a a new temporary register for this, and be sure to free it.
* compiler: bugfix: misused assoc in function lookup.Kaz Kylheku2018-03-191-1/+1
| | | | | * share/txr/stdlib/compiler.tl (sys:env lookup-fun): Fix swapped args in assoc call.
* vm: function table for faster calls.Kaz Kylheku2018-03-182-3/+36
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The vm now supports gcall and gapply opcodes which index numerically (using an immediate integer field in the instruction word) into a table of pre-resolved global function bindings. * share/txr/stdlib/asm.tl (op-gcall, op-gapply): New opcodes. (disassemble-c-d): Take the function vector as an argument and dump it too. (usr:disassemble): Extract function vector from VM description and pass it to disassemble-c-d. * share/txr/stdlib/compiler.tl (usr:compile-toplevel): Pass empty function symbol vector to vm-make-desc; it's now a required argument. * vm.c (struct vm_desc): New members funvec and ftab. (struct vm_ftent): New struct type. (vm_make_desc): New argument, funvec. Store funvec in the descriptor. Allocate a table of vm_ftent structures equal in number of elements to the function table, and populate it with resolved bindings. (vm_desc_funvec, vm_desc_destroy): New static functions. (vm_desc_mark): Mark the captured bindings in vd->ftab. (vm_gcall, vm_gapply): New static functions. (vm_execute): Handle GCALL and GAPPLY opcodes. (vm_desc_ops): Wire vm_desc_destroy in place of cobj_destroy_free_op. (vm_init): Add argument to vm-make-desc intrinsic. Register vm-desc-funvec intrinsic. * vm.h (vm_make_desc): Declaration updated. * vmop.h: Regenerated
* compiler: change in output register protocol.Kaz Kylheku2018-03-181-108/+107
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | With this change we get better code, as well fewer situations in which tregs are manually released. There are some subtleties. Previously, a compiled fragment of code would dictate the identity of the location into which it has placed output; then the higher level compile had to work with that location. The new protocol is that the caller specifies a suggested output register to the recursive compile call. If the recursive compile requires a temporary register for the output, it uses the suggested one. If it doesn't require a temporary register, it specifies its own output (for instance a (v x y) entry in the display). The caller has to deal with the output not being in the suggested register. The binding constructs lambda and let also have to deal with the possibility that the body specifies an output which is going out of scope, rather than the suggested register, and in that case must generate a move instruction to transfer from there to the suggested register before the (end ...). * share/txr/stdlib/compiler.tl (sys:env out-of-scope): New method. (compiler compile): Restructured handling of atom forms. Function takes output register argument and passes it down to the special form compile methods. (compiler comp-atom): Bugfix: this must handle nil by returning (t 0) rather than wastefully interning nil into the data table. (quote nil) triggered this. We no longer need to allocate a temporary register in this function; we just use oreg when we need it. (compiler comp-var): Don't alloc temporary, use oreg. (compiler comp-setq): We don't have to free the temporary register from compiling the value expression. When the target is a lexical variable, we pass its location to the sub-compile, so the result is placed in the variable directly. Thus we don't have to generate an additional mov instruction any more, except if that compile wasn't able to use the suggested location. (compiler comp-block): Pass oreg to compile of block bodies. Then use whatever register that block specifies as the block output. (compiler comp-let): Binding of variables is streamlined with oreg in a manner similar to assignment in comp-setq. The body is compiled with the suggested oreg as its output. Because it may put the output in a location that is going out of scope, we have to do the scope check and insert a mov. (compiler comp-lambda): Similar changes as in comp-let. (compiler comp-progn): Just use the incoming oreg as the destination for every form. Use the actual output register of the last frag as the output register, unless there were no frags in which case the nil register is specified as the output. (compiler comp-prog1): Allocate a register for the ignored values of the second and subsequent forms. Use oreg for compiling the first form. (compiler comp-quasi): Take oreg param and pass down. (compiler comp-call): Now allocates a batch of suggested registers for each of the argument compiles, and passes each down to its corresponding argument compile. These registers are freed, and the actual output are used in generating the call. The output of the call goes into oreg; no need to allocate. (compiler comp-for): Mostly the obvious changes here. (usr:compile-toplevel): Here we need to allocate an output register for the top-level call into the compiler.
* compiler: use mac-param-bindKaz Kylheku2018-03-171-15/+15
| | | | | | | | | | | | It's better to use mac-param-bind than tree-bind because it provides diagnostics related to the form being destructured. * share/txr/stdlib/compiler.tl (compiler compile): Pass the whole form rather than (cdr form) to a number of special form handlers. (compiler comp-seq, compiler comp-block, compiler comp-let, compiler comp-lambda, compiler comp-for): Destructure arguments with mac-param-bind.
* compiler: replace invalid compound form message.Kaz Kylheku2018-03-171-1/+1
| | | | | | * share/txr/stdlib/compiler.tl (compiler compile): The message will show (car form) followed by a colon, so the wording should refer to that object rather than the entire form.
* compile-toplevel: expand with warnings.Kaz Kylheku2018-03-171-1/+1
| | | | | | | | * eval.c (eval_init): Expose raw expand function as sys:expand*, since sys:expand squelches warnings. * share/txr/stdlib/compiler.tl (usr:compile-toplevel): Use expand* instead of expand.
* compiler: compile string quasiliterals.Kaz Kylheku2018-03-171-0/+84
| | | | | | | | * share/txr/stdlib/compiler.tl (compiler compile): Add sys:quasi case, dispatching new comp-quasi method. (compiler comp-quasi): New method. (expand-quasi-mods, expand-quasi-args, expand-quasi): New functions.
* compiler: closure bug: (dframe ...) without (end ...).Kaz Kylheku2018-03-161-0/+2
| | | | | | * share/txr/stdlib/compiler.tl (compiler comp-lambda): When we have specials we must generate an extra (end ...), to terminate the (dframe ...) that we inserted.
* compiler: fix wrong, undersized frame size in closure.Kaz Kylheku2018-03-161-3/+3
| | | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-lambda): Frame size can't be calculated from nfixed, because that doesn't account for the extra variables in optional parameters. It can't be calculated from the number of lexical variables either, because parameters that are special variables consume vXXYY frame entries without being counted as lexicals. Rather, the accurate frame size is given to us by the value of the counter in the newly created environment.
* Adding compiler.Kaz Kylheku2018-03-161-0/+402
| | | | | | | | | * lisplib.c (compiler_instantiate, compiler_set_entries): New static functions. (lisplib_init): Register auto-load for compiler via new functions. * share/txr/stdlib/compiler.tl: New file.
* asm: add copyright header.Kaz Kylheku2018-03-161-0/+26
| | | | | * share/txr/stdlib/asm.tl: block comment with copyright and BSD license added.