summaryrefslogtreecommitdiffstats
Commit message (Collapse)AuthorAgeFilesLines
...
* compiler: improve register removal optimization.Kaz Kylheku2021-02-272-20/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The register removal optimization now works for registers initialized from variables. For instance mov t13 v00000 mov t12 v00001 gcall t7 3 t13 d0 gcall t8 4 t12 t19 can, under the right conditions, be replaced with gcall t7 3 v00000 d0 gcall t8 4 v00001 t19 where the useless copies of the v0 and v1 registers to t13 and t12 are gone, and the refernces to those registers are renamed to those v registers. * share/txr/stdlib/optimize.tl (basic-blocks local-liveness): We now use the def field of a live-info structure differently. The def field holds a register, instead of a t register number. For any instruction that defines a register, the register is stored, whether it is v or t register. (basic-blocks peephole-block): The rule is simplified and extended to cover t-regs that receive a v-reg. A special additional condition applies in this case: v-registers are tied to a frame, and must not be accessed if their frame has ended. Our optimization carries the risk that the variable was copied into a register precisely for the purpose that the v register is going out of scope, and the value is needed outside of the frame. We don't have frame level information in the basic block, so to be conservative, we guess like this: if any end instructions occur (potentially ending a frame), and if the register is used after an end instruction, then we don't do the replacement. * share/txr/stdlib/compiler.tl (compiler comp-catch): Remove inappropriate jend. Control definitely flows past this instruction, because we jump here in the case when no exception has taken place to continue the program. This bug has resulted in some blocks being declared unreachable by the control flow graph construction, and thus not included in register liveness calculations, resulting in having a nil in the live slot. This was exposed by the new new optimization.
* list-builder: methods return object.Kaz Kylheku2021-02-262-15/+31
| | | | | | | | | | | | The list-builder methods, other than del, del* and get, now return the object instead of nil. * share/txr/stdlib/build.tl (list-builder (add, add*, pend, pend*, ncon, ncon*): Return the object, self. (list-builder-flets): Do not return the object out of the local functions which invoke the above methods. * txr.1: Documented.
* compiler: new optimization.Kaz Kylheku2021-02-261-25/+54
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Using liveness information, if we are very careful about the circumstances, we can can eliminate instructions of the form mov tN src and replace every subsequent occurrence of tN in the basic block by src. For instance, simple case: if a function ends with mov t13 d5 end t13 that can be rewriten as end d5 The most important condition is that t13 is not live on exit from that basic block. There are other conditions. For now, one of the conditions is that src cannot be a v register. * share/txr/stdlib/optimize.tl (struct live-info): New slot, def. This indicates which t register is being clobbered, if any, by the instruction to which this info is attached. (basic-blocks local-liveness): Adjust the propagation of the defined info. If an instruction both consumes a register and overwrites it, we track that as both a use and a definition. We set up the def fields of live-info. We do that by mutation, so we must be careful to copy the structure. The def field pertains to just one instruction, but the same info can be attached to multiple instructions. (subst-preserve): New function. (basic-blocks peephole-block): New optimization added. Now takes a basic-block argument, bl. (basic-blocks peephole): Pass bl to peephole-block.
* compiler: data flow analysis for t registers.Kaz Kylheku2021-02-242-22/+197
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The optimizer now calculates t liveness information for the t registers. In every basic block, it now knows which t regs are live on exit, and which are used in the block, at every instruction. One small optimization is based on this so far: the removal of a move instruction targeting a dead register. This appears stable. * share/txr/stdlib/compiler.tl (compiler comp-unwind-protect): The protected code of a uwprot must terminate with a regular end instruction, rather than the jend pseudo-instruction. This is because the clean-up block is executed after the protected block and references values generated in it: t registers are live between he pfrag and the cfrag. Without this, the compile-file-conditionally function was wrongly optimized, causing it to return false due to the setting of the success flag (that having been moved into a t register) having being optimized away. (compiler optimize): Add the call the basic-blocks method to calculate liveness. * share/txr/stdlib/optimize.tl (struct live-info, struct basic-block): New structure types. The basic-block structure type now representes basic blocks instead of raw lists. (struct basic-blocks): New slots, root, li-hash. (basic-blocks jump-ops): We add few instructions that reference labels, just to be safe. (basic-blocks :postinit): Refactor division into basic blocks so that it generates basic-block objects instead of just lists of instructions. Also, the new method link-graph is called which analyzes the tail instructions of all the blocks to determine connectivity and sets the next and links fields of the objects to build a graph. (basic-blocks (get-insns, cut-blocks)): Refactor for struct represenation of basic blocks. (basic-blocks (link-graph, local-liveness, calc-liveness): New methods. (basic-blocks thread-jumps-block): Refactor for struct representation of basic blocks. (basic-blocks peephole-blocks): Likewise, and new pattern for removing moves into dead t-registers, assisted by liveness information. (basic-blocks (peephole, thread-jumps)): Refactor for basic-blocks representation.
* compiler: bugfix: internal error in sys:switch.Kaz Kylheku2021-02-241-1/+1
| | | | | | | | | | | | | | Compiling a form like (caseq op ((a b c d e f g h i j k) 42))) Results in a run-time error in the compiler, similar to: list-vec: (#:l0048) is not of type vec * share/txr/stdlib/compiler.tl (compiler comp-switch): Make sure cases is also still a vector in the complex case when it's not just a copy of cases-vec.
* mpi: bugfix: out-of-bounds access in or, xor.Kaz Kylheku2021-02-241-4/+16
| | | | | | | | * mpi/mpi.c (mp_or, mp_xor): The main loop must only iterate up to the minimum number of digits between the two source operands, not the maximum number of digits, because otherwise it will access past the end of the shorter bignum's digit array.
* compiler: wrong close pattern in jump threading.Kaz Kylheku2021-02-231-2/+2
| | | | | | | * share/txr/stdlib/optimize.tl (thread-jumps-block): Add missing argument to close instruction pattern. This causes us to miss a threading opportunity due to the new ntregs parameter being mistaken for a label, which is not found.
* txr: tighten keyword arg parsing in @(next).Kaz Kylheku2021-02-221-13/+17
| | | | | | | | | | | | This fixes the bug of not allowing @(next :list nil). Also the bug of @(next :string) or @(next :string nil) reporting a nonsensical error message, instead of correctly complaining that nil isn't a string. * match.c (v_next_impl): Capture the conses returned by assoc, so we know whether a keyword is present. Then use those conses in tests which detect whether the keyword is present, rather than the values, which could be nil.
* txr: typo in comment.Kaz Kylheku2021-02-221-1/+1
| | | | * match.c (match_files): Fix bungled wording.
* txr: bugfix: give @(call) same semantics as direct call.Kaz Kylheku2021-02-223-10/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | The @(call) directive is buggy in the following ways, which cause an indirect call to behave differently from a direct call. It creates a new context, and so if the opening of a data source is deferred into the indirectly called function, that data source is lost when the indirect call terminates. Furthermore, if a data source is already established, there is no progress through the data: two consecutive @(call ...) directives operate on the same data. It also fails to implement vertical to horizontal fallback; if a function is not vertically defined, the directive fails. * match.c (v_call): Rewrite the core logic in the following way: we rewrite the indirect @(call) syntax into direct call syntax, substitute that into c->spec, and then just call v_fun. * tests/008/call-2.expected: New file. * tests/008/call-2.txr: New file. Test fails before this commit because both calls are matching against the same "A" element of the list.
* txr: pattern function calls are non-matching.Kaz Kylheku2021-02-214-22/+29
| | | | | | | | | | | | | | | | | | | | | | | | | | | This patch causes TXR to treat calls to verticatl functions, as well as the @(call) directive to be considered non-matching directives, so that opening the data source is deferred. This allows included .txr files to call the funtions that they define, without the side effect of standard input being read. * match.c (open_data_source): Function refactored to reduce duplication. c->data is checked first, and if it is not t, nothing is done, making the function cheaper in the frequent case. The non_matching_dir condition changes. We now check that the first element of the first spec is a non-nil symbol. If it has a function binding as a vertical function, then that is considered non_matching. (dir_tables_init): Treat @(call) as a non-matching directive. * Makefile (tst/tests/008/no-stdin-hang.ok): Add -n argument for non-interactive, which will cause stdin to be read in that test case if there is a regression in this change. If make tests is run in a terminal, this will hang make tests. * tests/no-stdin-hang.txr: New file. * tests/no-stdin-hang.expected: New file.
* configure: reconfigure: spaces in argumentsKaz Kylheku2021-02-211-0/+3
| | | | | | | * configure (cmdline): We are missing the simple case when the argument contains spaces or tabs, and no quotes or special characters. This causes a badly formatted command line in reconfigure in common situations like --opt-flags="-O3 -W".
* compiler: constant folding: avoid shadowed funs.Kaz Kylheku2021-02-201-7/+7
| | | | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-arith-form): Pass env to reduce-constant. (compiler comp-fun-form): Likewise, and don't bother checking %const-foldable% because reduce-constant does that again. (compiler comp-apply-call): Pass env to reduce-constant. (reduce-constant): Take env argument. If the function is constant foldable, check that there is no lexical function call binding shadowing it. If so, it's not the function we think it is, and we must not constant-fold it.
* compiler: constant-fold [...] forms.Kaz Kylheku2021-02-201-23/+28
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-apply-call): Constant-fold the arguments. Check for special cases involving call and route to regular function call. (compiler comp-dwim): Don't wrap all arguments with sys:lisp1-value, only those that are bindable symbols. This way constant expressions, including keywords, t and nil, are not wrapped, and detectable by constantp.
* compiler: constant-fold more basic functions.Kaz Kylheku2021-02-201-1/+17
| | | | | | | | * share/txr/stdlib/compiler.tl (%const-foldable-funs%): Add numerous eligible functions that are registered in eval.c. We avoid anything with functional arguments, environmental dependencies or anything that may be relied upon to produce a fresh object.
* compiler: constant-fold all cadr cons accessors.Kaz Kylheku2021-02-191-1/+7
| | | | | | | * share/txr/stdlib/compiler.tl (%const-foldable-funs%): Add all of the cadr, caddr, and other functions. Take out first and second; these will be later added together with other things that are being registered in eval.c.
* compiler: constant-fold most arithmetic functionsKaz Kylheku2021-02-191-6/+15
| | | | | | | | * share/txr/stdlib/compiler.tl (%const-foldable-funs%): Add most functions from arith module. (%const-foldable%): New variable, hash built from list. (compiler comp-fun-form, reduce-constant): Refer to %const-foldable% hash instead of %const-foldable-funs% list.
* compiler: constant fold pred/succ functions.Kaz Kylheku2021-02-193-5/+8
| | | | | | | | | | | | * share/txr/stdlib/compiler.tl (%const-foldable-funs%): Add pred, succ and their sisters. * share/txr/stdlib/vm-param.tl (%max-lev-idx%, %max-v-lev%, %max-sm-lev-idx%): Get rid of macro-time wrapping in calculation, which are there for manual constant folding. * share/txr/stdlib/asm.tl (with-lev-idx): Remove macro-time providing manual constant folding.
* compiler: start of constant-folding implementation.Kaz Kylheku2021-02-181-0/+46
| | | | | | | | | | | | | | | | | Introducing folding of certain expressions that can be evaluated at compile time, with some special handling for common arithmetic functions, in which we can collapse consecutive arguments that are constant integer expressions. * share/txr/stdlib/compiler.tl (%const-foldable-funs%): New global variable. (compiler compile): Send multiplication and division through new methods that that treat integer arguments. (compiler comp-arith-form, compiler comp-neg-arith-form): New methods. (comp-fun-form): Apply constant folding to a proper function call whose operator is listed in %const-foldable-funs%. (reduce-constant): New function.
* compiler: reduce (if (not (eq ...) ...)).Kaz Kylheku2021-02-181-0/+3
| | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-if): Recognize the pattern (if (not (eq ...) ..), and convert to (if (neq ...) ...) and likewise for eql and equal. This is fed back to comp-if, whereby it may be further reduced.
* compiler: use fixed-point macro for reduce-lisp.Kaz Kylheku2021-02-181-27/+32
| | | | | | * share/txr/stdlib/compiler.tl (fixed-point): New macro. (reduce-lisp): Hide irrelevant iteration details by using fixed-point macro.
* compiler: reduce (not (eq ...)) and related exprs.Kaz Kylheku2021-02-181-0/+3
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-fun-form): Reduce negated eq, eql, equal to neq, neql, nequal.
* compiler: strength reduction of nequal.Kaz Kylheku2021-02-181-4/+6
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-if): Support reduction of nequal in the same way as equal.
* compiler: reduce (list* x) to x.Kaz Kylheku2021-02-181-1/+1
| | | | | | | * share/txr/stdlib/compiler.tl (reduce-lisp): Add one more reduction case. There is a "hit" for this somewhere, because even though this adds code, overall 200 bytes are saved over the entire library.
* expander: improve diagnosis of invalid dotted syntax.Kaz Kylheku2021-02-181-17/+33
| | | | | | | | | | * eval.c (dotted_form_error): Use eval_error instead of throwing direcly, so the error message has location info and consistent formatting. (expand_forms, expand_forms_ss, expand_forms_lisp1): Check for the dotting error one level above, at the cons cell. The cons cell will have line number information attached to it for a better error message.
* compiler: add list construction optimizations.Kaz Kylheku2021-02-171-0/+35
| | | | | | | | | | | | The raw size of the library compiled files shrinks by over 2% from this optimization, not to mention that some list construction code is faster. * share/txr/stdlib/compiler.tl (compiler comp-fun-form): Reduce common list construction primitives via reduce-lisp function which algebraically transforms to a form with fewer function calls. (reduce-lisp): New function.
* compiler: condense if with pattern matching.Kaz Kylheku2021-02-171-59/+47
| | | | | | | | | | * share/txr/stdlib/compiler.tl (compiler comp-if): Remove the pointless cases which check for test being nil, since that is subsumed under constantp. Move all the constantp cases up, making them match-case clauses. The handling of %test-funs% in several places becomes a single pattern case. The remaining cases don't have any more sub-cases to test, so the cond forms are gone.
* compiler: strength reduction of equal.Kaz Kylheku2021-02-171-6/+29
| | | | | | | | | | | | | | | Here, we look for (equal x y) expressions that can be reduced to (eql x y) or (eq x y) and compiled that way. Also, we look for (if (equal x y) ...) expressions that can be turned into (if (eql x y) ...) or (if (eq x y) ...) which then compile into ifq or ifql instructions. * share/txr/stdlib/compiler.tl (compiler comp-if): Convert tree-case into match case, and then handle the (if (equal ...)) pattern. (comp-fun-form): Add recognition for (equal x y) expressions, and reduce their strength, if possible. (eq-comparable, eql-comparable): New functions.
* compiler: fix jump-threading regression.Kaz Kylheku2021-02-171-48/+48
| | | | | | | | | | * share/txr/stdlib/optimize.tl (basic-blocks thread-jumps-block): We want a set here, not a pset, otherwise we are processing the old-instruction again rather than iterating. This breaks jump threading where multiple iterations are required to get to the ultimate target. It showed up as a difference in the compiled image of the sys:compile-match function.
* compiler: use pattern matching for function formKaz Kylheku2021-02-171-11/+7
| | | | | * share/txr/stdlib/compiler.tl (compiler comp-fun-form): Rewritten more compactly and extensibly using match-case.
* doc: fix misleading @(call @'foo).Kaz Kylheku2021-02-171-9/+4
| | | | | | * txr.1: The documentation wrongly refers to @(call @'foo) which hasn't worked that way since version 144. The first argument is a Lisp expression.
* @(call): bugfix: matching doesn't continue.Kaz Kylheku2021-02-173-1/+17
| | | | | | | | | | | * match.c (v_call): This function must propagate the next_spec_k return value, rather than return a short-circuiting match object, which causes the parent to immediately succeed. * tests/008/call.txr: New test case, from Frank Schwidom. * tests/008/call.expected: Likewise.
* doc: improve quote operator.Kaz Kylheku2021-02-171-8/+28
| | | | * txr.1: Improved description of quote operator.
* compiler: separate jump threading from peepholeKaz Kylheku2021-02-172-51/+65
| | | | | | | | | | | | | | | Jump threading just needs to looks at the last instruction in a basic blocks now; it's a waste of cycles to be pattern matching on jump intruction patterns while peephole scanning. * share/txr/stdlib/compiler.tl (compiler optimize): Invoke new thread-jumps after peephole. * share/txr/stdlib/optimize.tl (basic-blocks thread-jumps-block): New method. (basic-blocks peephole-block): Remove jump-threading cases; they are in thread-jumps block. (basic-blocks thread-jumps): New method.
* compiler: remove unreachable optimization.Kaz Kylheku2021-02-161-7/+0
| | | | | | | | * share/txr/stdlib/optimize.tl (basic-blocks peephole-block): Remove the special optimization involving an unconditional jump followed by an if, to a block which tests the same register with another if. This optimization can't match because a jmp and if cannot be in a basic block together.
* compiler: re-scan block altered by frame-move.Kaz Kylheku2021-02-151-0/+1
| | | | | | | | | | | * share/txr/stdlib/optimize.tl (basic-blocks peephole-block): If we move a frame instruction past a jump into the next block, we must add that block's label to the rescan list. There may be an opportunity to propagate the frame instruction deeper into that block. I'm not seeing a difference from this change in the compilation of the standard library, which indicates that this is happening by fluke; the alteration of that block is happening before it has been visited.
* compiler: close instructions terminate basic block.Kaz Kylheku2021-02-151-1/+1
| | | | | | | | * share/txr/stdlib/optimize.tl (struct basic-blocks): Include the close instruction in the set which terminate a basic block. A close is an unconditional jump; execution never continues after a close instruction, but goes unconditionally to a branch target.
* compiler: peephole newly added blocks.Kaz Kylheku2021-02-151-90/+100
| | | | | | | | | | | | | | | | If cut-block is called during peephole optimization, it can introduce blocks that can be missed, in which there might be some opportunity for peephole reduction. Let's keep track of newly added blocks in a re-scan list. * share/txr/stdlib/optimize.tl (struct basic-blocks): New slot, rescan. (basic-blocks cut-block): Add new block's label to rescan list. (basic-blocks peephole-block): New method, formed out of the bulk of basic-blocks peephole. (basic-blocks peephole): After processing the blocks from the hash table, iterate on the rescan list.
* compiler: basic blocks replace extended basic blocks.Kaz Kylheku2021-02-151-12/+27
| | | | | | | | | | | | | | | | * share/txr/stdlib/optimize.tl (struct basic-blocks): jump-ops, new static member. (basic-blocks :postinit): Cut the code into basic blocks rather than extended basic blocks. This means that the insruction which follows every jumping instructions is now a block leader. Every block needs a label, so we add them. (basic-blocks peephole): The optimization which slides a frame instruction past a jump must be refactored to move the frame instruction into the next block. Firstly, moving anything past a jump instruction is no longer allowed, because the result is no longer a basic block. Secondly, doing so prevents further frame movements, because the block no longer has any instructions after the jump over which the frame can be moved.
* asm/vm/compiler: introduce jend pseudo-instruction.Kaz Kylheku2021-02-142-5/+10
| | | | | | | | | | | | | | | | | | | | | | The jend pseudo-instruction is a simple alias for end. It indicates a jumping end: an end that does not fall through to the next instruction but could go somewhere else. This is for "future correctness" as well as clarity. The difference is important in analysis of code into basic blocks. Currently this won't make a difference because all the jend instructions except for the one at the end of compiled top-level form are followed by a label which kicks off a basic block anyway. * share/txr/stdlib/asm.tl (defopcode-alias): New macro. (jend): New opcode, defined as alias for end. * share/txr/stdlib/compiler.tl (comp-unwind-protect, comp-lambda-impl, compile-toplevel): Use jend instruction for a jumping end: the one after the protected code block of a uwprot, the one at the end of a function, and the one at the end of a top-level form.
* vm/asm: housecleaning: remove deprecated opcodes.Kaz Kylheku2021-02-143-137/+35
| | | | | | | | | | | | | | | | | | Since we have are breaking binary compatibility in the upcoming TXR 252, we might as well take the opportunity to remove deprecated opcodes that the compiler doesn't use. * share/txr/stdlib/asm.tl (op-fin): Opcode removed. (op-pprof): Derive directly from op-end rather than op-fin. (op-movrsi, op-movsmi, op-movrbi, op-movi-pseudo): Opcodes removed. * vm.c (vm_fin, vm_movrsi, vm_movsmi, vm_movrbi): Functions removed. (vm_execute): FIN, MOVRSI, MOVSMI, MOVRBI cases removed. * vmop.h: Regenerated. (vm_op_t): Enum members FIN, MOVRSI, MOVSMI, MOVRBI removed.
* printer: lambda bugfix.Kaz Kylheku2021-02-121-1/+1
| | | | | | | | | | | * lib.c (obj_print_impl): Don't pass non-symbols to fboundp. This causes a problem in the case where we are printing an object like ((lambda ...) ...). The car of this object is the (lambda ...) form. When when pass this to fboundp, the underlying function lookup mechanism wants to turn it into a function object and tries to expand it. This can error out if the lambda has bad syntax, which can happen because it's just data that we are trying to print.
* compiler: eliminate block from recursive functions.Kaz Kylheku2021-02-122-10/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The block elimination logic doesn't work for self-recursive functions, even if they invoke no block returning, and use only system functions that don't have anything to do with block returns. This is because the recursive call is not recognized, and treated as a call to an unknown function. Let's put in a simple hack. The defun and defmacro operators will use a new secret special operator called sys:blk instead of block to generate the block. The compilation of sys:blk will assume that (sys:blk name ...) is only used in a defun or defmacro by that same name, and include name in the list of OK functions. So that functions created using the interpreter and then dynamically compiled will also benefit, we add this operator to the interpreter. * eval.c (sys_blk_s): New symbol variable. (op_defun): For defun and defmacro, use sys:blk for the block for the block (eval_init): Initialize sys_blk_s with the interned symbol sys:blk. Register the sys:blk operator. * share/txr/stdlib/compiler.tl (compiler compile): Recognize the sys:blk special form and handle via comp-block. (comp-block): If sys:blk is being compiled, then include the block name in the list of functions that do not perform block returns. (If this is false, other checks will fail before use that.) (expand-defun): Use sys:blk for defun and defmacro.
* doc: wording improvements in pattern matching intro.Kaz Kylheku2021-02-121-9/+20
|
* compiler/vm: more compact frame size for closures.Kaz Kylheku2021-02-115-130/+161
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Closures do not share t-registers with surrounding code; they do not store a value into such a register that code outside the closure would read and vice versa. When compiling closures, we can can temporarily reset the compiler's t-register allocator machinery to get low t-register values. Then, when executing the closure, we reserve space just for the registers it needs, not based off the containing vm description. Here we make a backwards-incompatible change. The VM close instruction needs an extra parameter indicating the number of t-regisers. This is stored into the closure and used for allocating the frame when it is dispatched. * parser.c (read_file_common): We read nothing but version 6 tlo files now. * share/txr/stdlib/asm.tl (op-close asm): Parse new ntreg argument from close syntax, and put it out as an extra word. Here is where we pay for this improvement in extra code size. (op-close dis): Extract the new argument from the machine code and add it to the disassembled format. * share/txr/stdlib/compiler.tl (compile-in-toplevel): Save and restore the t-reg discards list also. Don't bother with a gensym for the compiler; the argument is always a symbol, which we can use unhygienically like in with-var-spy. (compile-with-fresh-tregs): New macro based on compile-in-toplevel: almost the same but doesn't reset the level. (comp-lambda-impl): Use compile-with-fresh-tregs to compile the entire closure with a minimized register set. Place the treg-cntr into the closure instruction to indicate the number of registers the closure requires. * vm.c (struct vm): New member, nreg. (vm_make_closure): New parameter, nreg, stored into the closure. (vm_close): Extract a third opcode word, and pull the nreg value from the bottom half. Pass this to vm_make_closure. (vm_execute_closure, vm_funcall_common): Calculate frame size based on the closur's nreg rather than the VM description's. * txr.1: Document that the upcoming version 252 produces version 6.0 object files and only loads version 6.
* compiler: frame-eliminating optimization.Kaz Kylheku2021-02-113-154/+265
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This optimization identifies let blocks whose variables are not captured by closures. The variables are relocated to registers and the frame M N ... end reg wrapping is removed. * parser.c (read_file_common): Load version 6 files. We remain backwards-compatible. * share/txr/stdlib/compiler.tl (var-spy, capture-var-spy): New structure types. (struct compiler): New slot, var-spies. (with-var-spy): New macro. (compiler (alloc-new-treg, unalloc-reg-count, push-var-spy, pop-var-spy)): New methods. (compiler (comp-atom, compt-setq, comp-list-setq, comp-lisp1-value)): Inform the spies in the spy notification stack about assignments and accesses. (compiler eliminate-frame): New method. (compiler comp-let): Use spies to determine which variables from this frame are captured, and if none are, then use eliminate-frame to rename all the variables to t-registers and drop the frame setup/teardown. (compiler comp-lambda): Set up a capture-var-spy which intercepts accesses and assignments within a lambda, and informs other spies about the captures. (%tlo-ver%): Bump compiled file version to to (6 0), because of some behavioral changes necessary in the VM. We might revert this if the issues are solved differently. * vm.c (vm_getz): Do not null out T registers. (vm_execute_toplevel, vm_execute_closure): Use zalloca to allocate the register part of the frame, so T registers are initialized to nil.
* compiler: use rewrite-case in dedup-labels.Kaz Kylheku2021-02-101-8/+6
| | | | | | | * share/txr/stdlib/optimize.tl (dedup-labels): Use rewrite-case macro defined in the same file instead of rewrite/lambda/match-case. Also change two-argument list* to cons.
* vm: remove hard-coded constants.Kaz Kylheku2021-02-103-6/+8
| | | | | | | | | | * genvmop.txr: Define VM_LEV_SIZE from %lev-size%. * vm.c (vm_make_desc): Use VM_MAX_LEV and VM_LEV_SIZE instead of incorrect hard-coded values of 256 that were right for an old version of the vm. * vmop.h: Regenerated.
* compiler: bug: trivial unwind-protect return valueKaz Kylheku2021-02-101-1/+1
| | | | | | | | | | | | | Bad test case: (unwind-protect 42 1 2 3) -> 3 ;; should be 42 * share/txr/stdlib/compiler.tl (compile comp-unwind-protect): In the case when the protected code compiles to zero code, because it is a simple variable or constant, the code that we return must still nominate the that fragment's output register as its output, and not the output register of the cleanup forms.
* matcher: diagnose syntax problems in hash pattern.Kaz Kylheku2021-02-091-1/+1
| | | | | | * share/txr/stdlib/match.tl (compile-hash-match): Use mac-param-bind instead of tree-bind, like in the other functions.