1
#| rep.jl -- inliners for many rep language features
3
$Id: rep.jl,v 1.48 2001/09/03 03:34:32 jsh Exp $
5
Copyright (C) 2000 John Harper <john@dcs.warwick.ac.uk>
7
This file is part of librep.
9
librep is free software; you can redistribute it and/or modify it
10
under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2, or (at your option)
14
librep is distributed in the hope that it will be useful, but
15
WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with librep; see the file COPYING. If not, write to
21
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24
(declare (unsafe-for-call/cc))
26
(define-structure rep.vm.compiler.rep ()
31
rep.vm.compiler.modules
34
rep.vm.compiler.inline
36
rep.vm.compiler.bindings)
38
;; List of side-effect-free functions. They should always return the
39
;; same value when given the same inputs. Used when constant folding.
40
(define constant-functions
41
'(+ - * / % mod max min 1+ 1- car cdr assoc assq rassoc rassq nth nthcdr
42
last member memq arrayp aref substring concat length elt lognot not
43
logior logxor logand equal = /= > < >= <= ash zerop null atom consp
44
listp numberp integerp stringp vectorp bytecodep functionp macrop
45
special-form-p subrp sequencep string-head-eq string-equal
46
string-lessp string-match string-looking-at quote-regexp
47
complete-string time-later-p alpha-char-p upper-case-p lower-case-p
48
digit-char-p alphanumericp space-char-p char-upcase char-downcase
49
quotient floor ceiling truncate round exp log sin cos tan asin acos
50
atan sqrt expt prin1-to-string read-from-string assoc-regexp
51
string= string< nop identity caar cdar cadr cddr caaar cdaar
52
cadar cddar caadr cdadr caddr cdddr positivep negativep oddp
53
evenp abs lcm % modulo lsh string-upper-case-p string-lower-case-p
54
string-capitalized-p))
56
;; List of symbols, when the name of the function called by a top-level
57
;; form is one of these that form is compiled.
58
(define top-level-compiled
59
'(if cond when unless let let* letrec catch unwind-protect condition-case
60
progn prog1 prog2 while and or case define-structure structure))
62
;; List of symbols, when the car of a top-level form is a member of this
63
;; list, don't macroexpand the form before compiling.
64
(define top-level-unexpanded
65
'(defun defmacro defvar defconst defsubst %define require
66
declare eval-when-compile define-structure structure))
71
(defun pass-1 (forms) (add-progns (pass-1* forms)))
73
(defun pass-1* (forms) (lift-progns (mapcar do-pass-1 forms)))
75
;; flatten progn forms into their container
76
(defun lift-progns (forms)
77
(let loop ((rest (reverse forms))
79
(cond ((null rest) out)
80
((eq (caar rest) 'progn)
81
(loop (cdr rest) (append (cdar rest) out)))
82
(t (loop (cdr rest) (cons (car rest) out))))))
84
;; merge `non-top-level' forms into progn blocks. These will then
85
;; get compiled into single run-byte-code forms
86
(defun add-progns (forms)
87
(let loop ((rest forms))
88
(cond ((null rest) forms)
89
((memq (caar rest) top-level-unexpanded) (loop (cdr rest)))
90
(t (unless (eq (caar rest) 'progn)
91
(rplaca rest (list 'progn (car rest))))
93
(not (memq (caadr rest) top-level-unexpanded)))
95
(rplaca rest (nconc (car rest) (list (cadr rest))))
96
(rplacd rest (cddr rest))
98
(loop (cdr rest)))))))
100
(defun do-pass-1 (form)
101
(let-fluids ((current-form form))
102
(unless (or (memq (car form) top-level-unexpanded)
103
(memq (car form) top-level-compiled))
104
(setq form (compiler-macroexpand
105
form (lambda (in out)
107
(memq (car out) top-level-unexpanded)
108
(memq (car out) top-level-compiled))))))
111
(remember-function (nth 1 form) (nth 2 form) (nthcdr 3 form)))
114
(remember-function (nth 1 form) (nth 2 form))
115
(note-macro-def (nth 1 form) (cons 'lambda (nthcdr 2 form))))
118
(fluid-set inline-env (cons (cons (nth 1 form)
119
(cons 'lambda (nthcdr 2 form)))
120
(fluid inline-env))))
123
(remember-variable (nth 1 form)))
126
(remember-variable (nth 1 form))
127
(fluid-set const-env (cons (cons (nth 1 form) (nth 2 form))
130
((%define) (remember-lexical-variable (nth 1 form)))
133
(if (compiler-constant-p (cadr form))
134
(note-require (compiler-constant-value (cadr form)))
139
(note-declaration (cdr form)))
142
(if (and (eq (car (nth 1 form)) 'require)
143
(compiler-constant-p (cadr (nth 1 form))))
144
(note-require (compiler-constant-value (cadr (nth 1 form))))
145
(eval (nth 1 form))))
148
(setq form (cons 'progn (pass-1* (cdr form)))))
150
;; put bare forms into progns so they can be merged in pass-1
151
(t (unless (memq (car form) top-level-unexpanded)
152
(setq form (list 'progn form)))))
159
(defun pass-2 (forms)
160
(let loop ((rest forms)
164
(loop (cdr rest) (cons (do-pass-2 (car rest)) out)))))
166
(defun do-pass-2 (form)
167
(let-fluids ((current-form form))
170
(let ((tmp (assq (nth 1 form) (fluid macro-env))))
171
(let-fluids ((current-fun (nth 1 form)))
172
;;(format standard-error "[%s]\n" (fluid current-fun))
176
(list 'defun (nth 1 form)
177
(compile-lambda (cons 'lambda (nthcdr 2 form))
181
(let ((code (compile-lambda (cons 'lambda (nthcdr 2 form))
183
(tmp (assq (nth 1 form) (fluid macro-env))))
184
(let-fluids ((current-fun (nth 1 form)))
186
(rplacd tmp (make-closure code))
188
"compiled macro `%s' wasn't in environment" (nth 1 form)))
189
(list 'defmacro (nth 1 form) code))))
192
(let ((doc (nth 3 form)))
193
(when (and *compiler-write-docs* (stringp doc))
194
(add-documentation (nth 1 form) (fluid current-module) doc)
195
(setq form (delq doc form)))
196
(unless (memq (nth 1 form) (fluid defvars))
197
(remember-variable (nth 1 form)))
198
(unless (assq (nth 1 form) (fluid const-env))
200
'bindings "unknown constant `%s'" (nth 1 form))))
204
(let ((value (nth 2 form))
206
(when (and (listp value)
207
(not (compiler-constant-p value)))
208
;; Compile the definition. A good idea?
209
(rplaca (nthcdr 2 form) (compile-form (nth 2 form))))
210
(when (and *compiler-write-docs* (stringp doc))
211
(add-documentation (nth 1 form) nil doc)
212
(setq form (delq (nth 3 form) form)))
213
(unless (memq (nth 1 form) (fluid defvars))
214
(remember-variable (nth 1 form))))
218
(let ((sym (nth 1 form))
221
(unless (memq sym (fluid defines))
222
(remember-lexical-variable (compiler-constant-value sym)))
223
(when (and *compiler-write-docs* (stringp doc))
224
(add-documentation sym (fluid current-module) doc)
225
(setq form (delq doc form)))
226
(when (and (listp value) (not (compiler-constant-p value)))
227
;; Compile the definition. A good idea?
228
(rplaca (nthcdr 2 form) (compile-form (nth 2 form))))
232
(compile-top-level-define-structure form))
235
(compile-top-level-structure form))
237
((eval-when-compile) nil)
239
(t (if (memq (car form) top-level-compiled)
244
;;; Source code transformations. These are basically macros that are only
245
;;; used at compile-time.
247
;; tells the constant-folder which functions can be removed
248
(defun foldablep (name)
249
(memq name constant-functions))
251
(defun trans-setq (form)
254
(setq form (cdr form))
256
(unless (consp (cdr form))
257
(compiler-error "odd number of args to setq"))
258
(setq lst (cons `(set ',(car form) ,(nth 1 form)) lst))
259
(setq form (nthcdr 2 form)))
260
(cons 'progn (nreverse lst))))
261
(put 'setq 'rep-compile-transform trans-setq)
263
(defun trans-defvar (form)
268
(remember-variable name)
269
(when (and (compiler-constant-p doc)
270
(stringp (compiler-constant-value doc))
271
*compiler-write-docs*)
272
(add-documentation name nil (compiler-constant-value doc))
275
,@(and doc (list `(put ',name 'variable-documentation ,doc)))
276
(make-variable-special ',name)
277
(unless (boundp ',name)
278
(setq ,name ,value)))))
279
(put 'defvar 'rep-compile-transform trans-defvar)
281
(defun trans-require (form)
283
((feature (nth 1 form)))
284
(when (compiler-constant-p feature)
285
(note-require (compiler-constant-value feature)))
286
;; Must transform to something other than (require FEATURE) to
287
;; prevent infinite regress
288
`(funcall require ,feature)))
289
(put 'require 'rep-compile-transform trans-require)
291
(defun trans-/= (form)
292
`(not (= ,@(cdr form))))
293
(put '/= 'rep-compile-transform trans-/=)
296
;;; Functions which compile non-standard functions (ie special-forms)
298
;; module compilers from compiler-modules
299
(put 'structure 'rep-compile-fun compile-structure)
300
(put 'define-structure 'rep-compile-fun compile-define-structure)
301
(put 'structure-ref 'rep-compile-fun compile-structure-ref)
303
(defun compile-declare (form)
304
(note-declaration (cdr form))
305
(compile-constant nil))
306
(put 'declare 'rep-compile-fun compile-declare)
308
(defun compile-quote (form)
309
(compile-constant (car (cdr form))))
310
(put 'quote 'rep-compile-fun compile-quote)
312
(defun compile-function (form)
313
(compile-form-1 (cadr form)))
314
(put 'function 'rep-compile-fun compile-function)
316
(defun compile-lambda-form (form)
317
(compile-lambda-constant form))
318
(put 'lambda 'rep-compile-fun compile-lambda-form)
320
(defun compile-while (form)
322
((top-label (make-label))
323
(test-label (make-label)))
324
(emit-insn `(jmp ,test-label))
325
(fix-label top-label)
326
(compile-body (nthcdr 2 form))
329
(fix-label test-label)
330
(compile-form-1 (nth 1 form))
331
(emit-insn `(jpt ,top-label))))
332
(put 'while 'rep-compile-fun compile-while)
334
(defun compile-%define (form)
335
(compile-constant (nth 1 form))
336
(compile-form-1 (nth 2 form))
337
(emit-insn '(%define))
339
(put '%define 'rep-compile-fun compile-%define)
341
;; Compile mapc specially if we can open code the function call
342
(defun compile-mapc (form)
346
(if (constant-function-p fun)
347
;; We can open code the function
349
((top-label (make-label))
350
(test-label (make-label)))
351
(setq fun (constant-function-value fun))
353
(emit-insn `(jmp ,test-label))
354
(fix-label top-label)
358
(compile-lambda-inline fun nil 1)
362
(fix-label test-label)
363
;; I don't have a jump-if-t-but-never-pop instruction, so
364
;; make one out of "jpt TOP; nil". If I ever get a peep hole
365
;; optimiser working, the nil should be fodder for it..
366
(emit-insn `(jtp ,top-label))
367
(emit-insn '(push ())))
368
;; The function must be called, so just use the mapc opcode
373
(put 'mapc 'rep-compile-fun compile-mapc)
375
(defun compile-progn (form #!optional return-follows)
376
(compile-body (cdr form) return-follows))
377
(put 'progn 'rep-compile-fun compile-progn)
379
(defun compile-prog1 (form)
380
(compile-form-1 (nth 1 form))
381
(compile-body (nthcdr 2 form))
384
(put 'prog1 'rep-compile-fun compile-prog1)
386
(defun compile-set (form)
387
(let ((sym (nth 1 form))
389
(if (compiler-constant-p sym)
392
(setq sym (compiler-constant-value sym))
393
(unless (symbolp sym)
394
(compiler-error "trying to set value of a non-symbol: %s" sym))
399
(note-binding-modified sym)
401
;; need to preserve left-right evaluation order
406
(put 'set 'rep-compile-fun compile-set)
408
;; compile let* specially to coalesce all bindings into a single frame
409
(defun compile-let* (form #!optional return-follows)
411
((lst (car (cdr form))))
414
(emit-insn '(init-bind))
417
(cond ((consp (car lst))
418
(let ((tmp (car lst)))
419
(compile-body (cdr tmp))
420
(test-variable-bind (car tmp))
421
(note-binding (car tmp))
422
(emit-binding (car tmp))))
423
(t (emit-insn '(push ()))
425
(test-variable-bind (car lst))
426
(note-binding (car lst))
427
(emit-binding (car lst))))
429
(setq lst (cdr lst)))
430
(compile-body (nthcdr 2 form) return-follows)
431
(emit-insn '(unbind))
432
(decrement-b-stack)))))
433
(put 'let* 'rep-compile-fun compile-let*)
435
;; let can be compiled straight from its macro definition
437
;; compile letrec specially to handle tail recursion elimination
438
(defun compile-letrec (form #!optional return-follows)
439
(let ((bindings (car (cdr form))))
443
(emit-insn '(init-bind))
446
;; create the bindings, should really be to void values, but use nil..
448
(let ((var (or (car cell) cell)))
449
(test-variable-bind var)
450
(compile-constant nil)
453
(decrement-stack))) bindings)
454
;; then set them to their values
456
(let ((var (or (car cell) cell)))
457
(compile-body (cdr cell) nil var)
459
(decrement-stack))) bindings)
461
;; Test if we can inline it away.
462
;; Look for forms like (letrec ((foo (lambda (..) body..))) (foo ..))
463
;; where `foo' only appears in inlinable tail calls in body
465
(unless (= (length bindings) 1)
467
(let ((var (or (caar bindings) (car bindings)))
468
(value (cdar bindings)))
469
(unless (and (binding-tail-call-only-p var)
470
value (not (cdr value))
471
(eq (caar value) 'lambda))
473
(setq value (car value))
474
(let ((body (nthcdr 2 form)))
475
(unless (= (length body) 1)
477
(setq body (car body))
478
(when (and (eq (car body) (get-language-property
479
'compiler-sequencer))
481
(setq body (cadr body)))
482
(unless (eq (car body) var)
486
(let-fluids ((silence-compiler t))
488
;; XXX what if this clashes?
489
(remember-function var (cadr value))
490
(compile-lambda-inline value (cdr body)
491
nil return-follows var)
492
(forget-function var)
495
;; no, keep on the usual track
496
(compile-body (nthcdr 2 form) return-follows)
497
(emit-insn '(unbind))
500
(put 'letrec 'rep-compile-fun compile-letrec)
502
(defun compile-let-fluids (form)
503
(let ((bindings (cadr form))
507
(fluid-set lexically-pure nil)
508
;; compile each fluid, value pair onto the stack
510
(compile-form-1 (car cell))
511
(compile-body (cdr cell))) bindings)
512
(emit-insn '(init-bind))
514
(mapc (lambda (unused)
515
(declare (unused unused))
516
(emit-insn '(fluid-bind))
517
(decrement-stack 2)) bindings)
519
(emit-insn '(unbind))
520
(decrement-b-stack)))))
521
(put 'let-fluids 'rep-compile-fun compile-let-fluids)
523
(defun compile-defun (form)
524
(remember-function (nth 1 form) (nth 2 form))
525
(compile-constant (nth 1 form))
526
(compile-lambda-constant (cons 'lambda (nthcdr 2 form)) (nth 1 form))
527
(emit-insn '(%define))
529
(put 'defun 'rep-compile-fun compile-defun)
531
(defun compile-defmacro (form)
532
(remember-function (nth 1 form) (nth 2 form))
533
(compile-constant (nth 1 form))
534
(compile-constant 'macro)
535
(compile-lambda-constant (cons 'lambda (nthcdr 2 form)) (nth 1 form))
537
(emit-insn '(%define))
539
(put 'defmacro 'rep-compile-fun compile-defmacro)
541
(defun compile-cond (form #!optional return-follows)
543
((end-label (make-label))
544
(need-trailing-nil t))
545
(setq form (cdr form))
549
(condition (car subl))
550
(next-label (make-label)))
551
;; See if we can squash a constant condition to t or nil
552
(when (compiler-constant-p condition)
553
(setq condition (not (not (compiler-constant-value condition)))))
556
;; condition t -- always taken
557
(if (consp (cdr subl))
558
;; There's something besides the condition
560
(compile-body (cdr subl) return-follows)
562
(if (eq condition (car subl))
563
(emit-insn '(push t))
564
(compile-form-1 (car subl) #:return-follows return-follows)
566
(when (consp (cdr form))
568
;; 'misc "unreachable conditions after t in cond statement")
569
;; Ignore the rest of the statement
571
(setq need-trailing-nil nil))
573
;; condition nil -- never taken
576
;; 'misc "unreachable forms after nil in cond statement")
579
;; non t-or-nil condition
580
(compile-form-1 (car subl)
581
#:return-follows (and return-follows
585
(if (consp (cdr subl))
586
;; Something besides the condition
588
;; This isn't the last condition list
590
(emit-insn `(jn ,next-label))
591
(compile-body (cdr subl) return-follows)
593
(emit-insn `(jmp ,end-label))
594
(fix-label next-label))
595
;; It is the last condition list, use the result
596
;; of this condition for the return value when it's
598
(emit-insn `(jnp ,end-label))
599
(compile-body (cdr subl) return-follows)
601
(setq need-trailing-nil nil))
604
;; This isn't the last condition list
605
(emit-insn `(jtp ,end-label))
606
;; This is the last condition list, since there's no
607
;; action to take, just fall out the bottom, with the
608
;; condition as value.
609
(setq need-trailing-nil nil))))))
610
(setq form (cdr form)))
611
(when need-trailing-nil
612
(emit-insn '(push ())))
614
(fix-label end-label)))
615
(put 'cond 'rep-compile-fun compile-cond)
617
(defun compile-case (form #!optional return-follows)
619
((end-label (make-label))
621
(setq form (cdr form))
623
(compiler-error "no key value in case statement"))
624
;; XXX if key is constant optimise case away..
625
(compile-form-1 (car form))
626
(setq form (cdr form))
629
(compiler-error "badly formed clause in case statement"))
633
(next-label (make-label)))
637
(if (consp (cdr cases))
640
(compile-constant cases)
641
(emit-insn '(memql)))
642
;; only one case, use eql
643
(compile-constant (car cases))
646
(emit-insn `(jn ,next-label))
648
((eq cases t) (setq had-default t))
650
"badly formed clause in case statement" #:form cases)))
651
(compile-body forms return-follows)
653
(emit-insn `(jmp ,end-label))
654
(fix-label next-label)
655
(setq form (cdr form))))
657
(emit-insn '(push ())))
659
(fix-label end-label)
662
(put 'case 'rep-compile-fun compile-case)
664
(defun compile-catch (form)
666
((catch-label (make-label))
667
(start-label (make-label))
668
(end-label (make-label)))
669
(let-fluids ((lexically-pure nil))
672
(emit-insn `(jmp ,start-label))
677
(increment-stack) ;enter with one arg on stack
678
(fix-label catch-label)
679
(compile-form-1 (nth 1 form))
682
(emit-insn `(ejmp ,end-label))
691
(fix-label start-label)
692
(push-label-addr catch-label)
693
(emit-insn '(binderr))
696
(compile-body (nthcdr 2 form))
697
(emit-insn '(unbind))
699
(fix-label end-label))))
700
(put 'catch 'rep-compile-fun compile-catch)
702
(defun compile-unwind-pro (form)
704
((cleanup-label (make-label))
705
(start-label (make-label))
706
(end-label (make-label)))
707
(let-fluids ((lexically-pure nil))
710
(emit-insn `(jmp ,start-label))
716
;; [overall, stack +1]
718
(fix-label cleanup-label)
719
(compile-body (nthcdr 2 form))
721
(emit-insn `(ejmp ,end-label))
731
;; [overall, stack +2]
732
(fix-label start-label)
733
(push-label-addr cleanup-label)
734
(emit-insn '(binderr))
737
(compile-form-1 (nth 1 form))
738
(emit-insn '(unbind))
740
(emit-insn '(push ()))
742
(emit-insn `(jmp ,cleanup-label))
745
(fix-label end-label))))
746
(put 'unwind-protect 'rep-compile-fun compile-unwind-pro)
748
(defun compile-condition-case (form)
750
((cleanup-label (make-label))
751
(start-label (make-label))
752
(end-label (make-label))
753
(handlers (nthcdr 3 form)))
754
(let-fluids ((lexically-pure nil))
758
(emit-insn `(jmp ,start-label))
759
(fix-label cleanup-label)
761
(increment-stack) ;reach here with one item on stack
765
(if (and (nth 1 form) (not (eq (nth 1 form) 'nil)))
766
(let ((var (nth 1 form)))
767
(when (spec-bound-p var)
769
"condition-case can't bind to special variable `%s'" var))
770
(test-variable-bind var)
772
;; XXX errorpro instruction always heap binds..
773
(tag-binding var 'heap-allocated))
774
;; something always gets bound
775
(let ((tem (gensym)))
777
(tag-binding tem 'heap-allocated)
778
;; avoid `unused variable' warnings
779
(note-binding-referenced tem)))
780
;; Loop over all but the last handler
781
(while (consp (cdr handlers))
782
(if (consp (car handlers))
784
((next-label (make-label)))
791
(compile-constant (car (car handlers)))
792
(emit-insn '(errorpro))
794
(emit-insn `(jtp ,next-label))
796
(compile-body (cdr (car handlers)))
797
(emit-insn `(jmp ,end-label))
798
(fix-label next-label))
800
"badly formed condition-case handler: `%s'"
801
(car handlers) #:form handlers))
802
(setq handlers (cdr handlers)))
804
(if (consp (car handlers))
806
((pc-label (make-label)))
812
(compile-constant (car (car handlers)))
813
(emit-insn '(errorpro))
815
(emit-insn `(ejmp ,pc-label))
818
(compile-body (cdr (car handlers)))
819
(emit-insn `(jmp ,end-label)))
821
"badly formed condition-case handler: `%s'"
822
(car handlers) #:form (car handlers)))))
823
(compiler-error "no handlers in condition-case"))
830
(fix-label start-label)
831
(push-label-addr cleanup-label)
832
(emit-insn '(binderr))
835
(compile-form-1 (nth 2 form))
838
;; unbind ;unbind error handler or VAR
839
(fix-label end-label)
840
(emit-insn '(unbind))
841
(decrement-b-stack))))
842
(put 'condition-case 'rep-compile-fun compile-condition-case)
844
(defun compile-list (form)
845
(do ((args (cdr form) (cdr args))
846
(count 0 (1+ count)))
848
;; merge the arguments into a single list
849
(compile-constant '())
854
(compile-form-1 (car args))))
855
(put 'list 'rep-compile-fun compile-list)
857
(defun compile-list* (form)
858
(do ((args (cdr form) (cdr args))
859
(count 0 (1+ count)))
861
;; merge the arguments into a single list
866
(compile-form-1 (car args))))
867
(put 'list* 'rep-compile-fun compile-list*)
869
;; Funcall normally translates to a single call instruction. However,
870
;; if the function being called is a constant lambda expression, open
872
(defun compile-funcall (form #!optional return-follows)
875
(args (nthcdr 2 form))
877
(open-code (constant-function-p fun)))
879
(compile-form-1 fun))
881
(compile-form-1 (car args))
882
(setq args (cdr args)
883
arg-count (1+ arg-count)))
886
(compile-lambda-inline
887
(constant-function-value fun) nil arg-count return-follows)
888
;; We push one less value than when using 'call
889
(if (zerop arg-count)
891
(decrement-stack (1- arg-count))))
892
(emit-insn `(call ,arg-count))
893
(note-function-call-made)
894
(decrement-stack arg-count))))
895
(put 'funcall 'rep-compile-fun compile-funcall)
897
(defun compile-apply (form)
898
(compile-form-1 (nth 1 form))
899
(do ((args (nthcdr 2 form) (cdr args))
900
(count 0 (1+ count)))
902
;; merge the arguments into a single list
907
(compile-form-1 (car args)))
910
(put 'apply 'rep-compile-fun compile-apply)
912
(defun compile-nth (form)
914
((insn (cdr (assq (nth 1 form) byte-nth-insns))))
917
(compile-form-1 (nth 2 form))
918
(emit-insn (list insn)))
919
(compile-2-args form))))
920
(put 'nth 'rep-compile-fun compile-nth)
921
(put 'nth 'rep-compile-opcode 'nth)
923
(defun compile-nthcdr (form)
925
((insn (assq (nth 1 form) byte-nthcdr-insns)))
928
(compile-form-1 (nth 2 form))
930
(emit-insn (list (cdr insn)))))
931
(compile-2-args form))))
932
(put 'nthcdr 'rep-compile-fun compile-nthcdr)
933
(put 'nthcdr 'rep-compile-opcode 'nthcdr)
935
(defun compile-minus (form)
936
(if (/= (length form) 2)
937
(compile-binary-op form)
938
(compile-form-1 (car (cdr form)))
940
(put '- 'rep-compile-fun compile-minus)
941
(put '- 'rep-compile-opcode 'sub)
943
(defun compile-make-closure (form)
944
(when (nthcdr 3 form)
946
'parameters "more than two parameters to `%s'; rest ignored"
948
(compile-form-1 (nth 1 form))
949
(compile-form-1 (nth 2 form))
950
(emit-insn '(make-closure))
953
(put 'make-closure 'rep-compile-fun compile-make-closure)
955
(defun compile-log (form)
956
(cond ((nthcdr 3 form)
958
'parameters "more than two parameters to `log'; rest ignored"))
960
;; dual argument form of log. compiles to
961
(compile-form-1 (nth 1 form))
963
(compile-form-1 (nth 2 form))
968
;; single argument form
969
(compile-form-1 (nth 1 form))
971
(t (compiler-warning 'parameters "too few parameters to `log'"))))
972
(put 'log 'rep-compile-fun compile-log)
974
(defun get-form-opcode (form)
975
(cond ((symbolp form) (get form 'rep-compile-opcode))
976
;; must be a structure-ref
977
((eq (car form) 'structure-ref)
978
(get (caddr form) 'rep-compile-opcode))
979
(t (compiler-error "don't know opcode for `%s'" form))))
981
;; Instruction with no arguments
982
(defun compile-0-args (form)
985
'parameters "all parameters to `%s' ignored" (car form)))
986
(emit-insn (list (get-form-opcode (car form))))
989
;; Instruction taking 1 arg on the stack
990
(defun compile-1-args (form)
991
(when (nthcdr 2 form)
993
'parameters "more than one parameter to `%s'; rest ignored" (car form)))
994
(compile-form-1 (nth 1 form))
995
(emit-insn (list (get-form-opcode (car form)))))
997
;; Instruction taking 2 args on the stack
998
(defun compile-2-args (form)
999
(when (nthcdr 3 form)
1001
'parameters "more than two parameters to `%s'; rest ignored"
1003
(compile-form-1 (nth 1 form))
1004
(compile-form-1 (nth 2 form))
1005
(emit-insn (list (get-form-opcode (car form))))
1008
;; Instruction taking 3 args on the stack
1009
(defun compile-3-args (form)
1010
(when (nthcdr 4 form)
1012
'parameters "More than three parameters to `%s'; rest ignored"
1014
(compile-form-1 (nth 1 form))
1015
(compile-form-1 (nth 2 form))
1016
(compile-form-1 (nth 3 form))
1017
(emit-insn (list (get-form-opcode (car form))))
1018
(decrement-stack 2))
1020
;; Compile a form `(OP ARG1 ARG2 ARG3 ...)' into as many two argument
1021
;; instructions as needed (PUSH ARG1; PUSH ARG2; OP; PUSH ARG3; OP; ...)
1022
(defun compile-binary-op (form)
1024
((opcode (get-form-opcode (car form))))
1025
(setq form (cdr form))
1026
(unless (>= (length form) 2)
1028
"too few arguments to binary operator `%s'" (car form)))
1029
(compile-form-1 (car form))
1030
(setq form (cdr form))
1032
(compile-form-1 (car form))
1033
(emit-insn (list opcode))
1035
(setq form (cdr form)))))
1037
;; Used for >, >=, < and <=
1038
(defun compile-transitive-relation (form)
1040
((<= (length form) 2)
1041
(compiler-error "too few args to relation `%s'" (car form)))
1042
((= (length form) 3)
1044
((opcode (get-form-opcode (car form))))
1045
;; Simple case, only two arguments, i.e. `(OP ARG1 ARG2)' into:
1046
;; PUSH ARG1; PUSH ARG2; OP;
1047
(compile-form-1 (nth 1 form))
1048
(compile-form-1 (nth 2 form))
1049
(emit-insn (list opcode))
1052
;; Tricky case, >2 args,
1054
;; Originally I did `(OP ARG1 ARG2 ARG3... ARGN)' as:
1056
;; PUSH ARG1; PUSH ARG2; DUP; SWAP2; OP; JNP Fail;
1057
;; PUSH ARG3; DUP; SWAP2; OP; JNP Fail;
1059
;; PUSH ARGN; OP; JMP End;
1064
;; But that doesn't always evaluate all arguments..
1065
(compile-funcall (cons 'funcall form)))))
1068
;;; Opcode properties for the generic instructions, in a progn for compiled
1072
(put 'cons 'rep-compile-fun compile-2-args)
1073
(put 'cons 'rep-compile-opcode 'cons)
1074
(put 'car 'rep-compile-fun compile-1-args)
1075
(put 'car 'rep-compile-opcode 'car)
1076
(put 'cdr 'rep-compile-fun compile-1-args)
1077
(put 'cdr 'rep-compile-opcode 'cdr)
1078
(put 'rplaca 'rep-compile-fun compile-2-args)
1079
(put 'rplaca 'rep-compile-opcode 'rplaca)
1080
(put 'rplacd 'rep-compile-fun compile-2-args)
1081
(put 'rplacd 'rep-compile-opcode 'rplacd)
1082
(put 'aset 'rep-compile-fun compile-3-args)
1083
(put 'aset 'rep-compile-opcode 'aset)
1084
(put 'aref 'rep-compile-fun compile-2-args)
1085
(put 'aref 'rep-compile-opcode 'aref)
1086
(put 'length 'rep-compile-fun compile-1-args)
1087
(put 'length 'rep-compile-opcode 'length)
1088
(put '+ 'rep-compile-fun compile-binary-op)
1089
(put '+ 'rep-compile-opcode 'add)
1090
(put '* 'rep-compile-fun compile-binary-op)
1091
(put '* 'rep-compile-opcode 'mul)
1092
(put '/ 'rep-compile-fun compile-binary-op)
1093
(put '/ 'rep-compile-opcode 'div)
1094
(put 'remainder 'rep-compile-fun compile-2-args)
1095
(put 'remainder 'rep-compile-opcode 'rem)
1096
(put 'mod 'rep-compile-fun compile-2-args)
1097
(put 'mod 'rep-compile-opcode 'mod)
1098
(put 'lognot 'rep-compile-fun compile-1-args)
1099
(put 'lognot 'rep-compile-opcode 'lnot)
1100
(put 'not 'rep-compile-fun compile-1-args)
1101
(put 'not 'rep-compile-opcode 'not)
1102
(put 'logior 'rep-compile-fun compile-binary-op)
1103
(put 'logior 'rep-compile-opcode 'lor)
1104
(put 'logxor 'rep-compile-fun compile-binary-op)
1105
(put 'logxor 'rep-compile-opcode 'lxor)
1106
(put 'logand 'rep-compile-fun compile-binary-op)
1107
(put 'logand 'rep-compile-opcode 'land)
1108
(put 'ash 'rep-compile-fun compile-2-args)
1109
(put 'ash 'rep-compile-opcode 'ash)
1110
(put 'equal 'rep-compile-fun compile-2-args)
1111
(put 'equal 'rep-compile-opcode 'equal)
1112
(put 'eq 'rep-compile-fun compile-2-args)
1113
(put 'eq 'rep-compile-opcode 'eq)
1114
(put '= 'rep-compile-fun compile-transitive-relation)
1115
(put '= 'rep-compile-opcode 'num-eq)
1116
(put '> 'rep-compile-fun compile-transitive-relation)
1117
(put '> 'rep-compile-opcode 'gt)
1118
(put '< 'rep-compile-fun compile-transitive-relation)
1119
(put '< 'rep-compile-opcode 'lt)
1120
(put '>= 'rep-compile-fun compile-transitive-relation)
1121
(put '>= 'rep-compile-opcode 'ge)
1122
(put '<= 'rep-compile-fun compile-transitive-relation)
1123
(put '<= 'rep-compile-opcode 'le)
1124
(put '1+ 'rep-compile-fun compile-1-args)
1125
(put '1+ 'rep-compile-opcode 'inc)
1126
(put '1- 'rep-compile-fun compile-1-args)
1127
(put '1- 'rep-compile-opcode 'dec)
1128
(put 'zerop 'rep-compile-fun compile-1-args)
1129
(put 'zerop 'rep-compile-opcode 'zerop)
1130
(put 'null 'rep-compile-fun compile-1-args)
1131
(put 'null 'rep-compile-opcode 'not)
1132
(put 'atom 'rep-compile-fun compile-1-args)
1133
(put 'atom 'rep-compile-opcode 'atom)
1134
(put 'consp 'rep-compile-fun compile-1-args)
1135
(put 'consp 'rep-compile-opcode 'consp)
1136
(put 'listp 'rep-compile-fun compile-1-args)
1137
(put 'listp 'rep-compile-opcode 'listp)
1138
(put 'numberp 'rep-compile-fun compile-1-args)
1139
(put 'numberp 'rep-compile-opcode 'numberp)
1140
(put 'stringp 'rep-compile-fun compile-1-args)
1141
(put 'stringp 'rep-compile-opcode 'stringp)
1142
(put 'vectorp 'rep-compile-fun compile-1-args)
1143
(put 'vectorp 'rep-compile-opcode 'vectorp)
1144
(put 'throw 'rep-compile-fun compile-2-args)
1145
(put 'throw 'rep-compile-opcode 'throw)
1146
(put 'boundp 'rep-compile-fun compile-1-args)
1147
(put 'boundp 'rep-compile-opcode 'boundp)
1148
(put 'symbolp 'rep-compile-fun compile-1-args)
1149
(put 'symbolp 'rep-compile-opcode 'symbolp)
1150
(put 'get 'rep-compile-fun compile-2-args)
1151
(put 'get 'rep-compile-opcode 'get)
1152
(put 'put 'rep-compile-fun compile-3-args)
1153
(put 'put 'rep-compile-opcode 'put)
1154
(put 'signal 'rep-compile-fun compile-2-args)
1155
(put 'signal 'rep-compile-opcode 'signal)
1156
(put 'quotient 'rep-compile-fun compile-2-args)
1157
(put 'quotient 'rep-compile-opcode 'quotient)
1158
(put 'reverse 'rep-compile-fun compile-1-args) ; new 12/7/94
1159
(put 'reverse 'rep-compile-opcode 'reverse)
1160
(put 'nreverse 'rep-compile-fun compile-1-args)
1161
(put 'nreverse 'rep-compile-opcode 'nreverse)
1162
(put 'assoc 'rep-compile-fun compile-2-args)
1163
(put 'assoc 'rep-compile-opcode 'assoc)
1164
(put 'assq 'rep-compile-fun compile-2-args)
1165
(put 'assq 'rep-compile-opcode 'assq)
1166
(put 'rassoc 'rep-compile-fun compile-2-args)
1167
(put 'rassoc 'rep-compile-opcode 'rassoc)
1168
(put 'rassq 'rep-compile-fun compile-2-args)
1169
(put 'rassq 'rep-compile-opcode 'rassq)
1170
(put 'last 'rep-compile-fun compile-1-args)
1171
(put 'last 'rep-compile-opcode 'last)
1172
(put 'mapcar 'rep-compile-fun compile-2-args)
1173
(put 'mapcar 'rep-compile-opcode 'mapcar)
1174
(put 'member 'rep-compile-fun compile-2-args)
1175
(put 'member 'rep-compile-opcode 'member)
1176
(put 'memq 'rep-compile-fun compile-2-args)
1177
(put 'memq 'rep-compile-opcode 'memq)
1178
(put 'delete 'rep-compile-fun compile-2-args)
1179
(put 'delete 'rep-compile-opcode 'delete)
1180
(put 'delq 'rep-compile-fun compile-2-args)
1181
(put 'delq 'rep-compile-opcode 'delq)
1182
(put 'delete-if 'rep-compile-fun compile-2-args)
1183
(put 'delete-if 'rep-compile-opcode 'delete-if)
1184
(put 'delete-if-not 'rep-compile-fun compile-2-args)
1185
(put 'delete-if-not 'rep-compile-opcode 'delete-if-not)
1186
(put 'copy-sequence 'rep-compile-fun compile-1-args)
1187
(put 'copy-sequence 'rep-compile-opcode 'copy-sequence)
1188
(put 'sequencep 'rep-compile-fun compile-1-args)
1189
(put 'sequencep 'rep-compile-opcode 'sequencep)
1190
(put 'functionp 'rep-compile-fun compile-1-args)
1191
(put 'functionp 'rep-compile-opcode 'functionp)
1192
(put 'special-form-p 'rep-compile-fun compile-1-args)
1193
(put 'special-form-p 'rep-compile-opcode 'special-form-p)
1194
(put 'subrp 'rep-compile-fun compile-1-args)
1195
(put 'subrp 'rep-compile-opcode 'subrp)
1196
(put 'eql 'rep-compile-fun compile-2-args)
1197
(put 'eql 'rep-compile-opcode 'eql)
1198
(put 'max 'rep-compile-fun compile-binary-op)
1199
(put 'max 'rep-compile-opcode 'max)
1200
(put 'min 'rep-compile-fun compile-binary-op)
1201
(put 'min 'rep-compile-opcode 'min)
1202
(put 'filter 'rep-compile-fun compile-2-args)
1203
(put 'filter 'rep-compile-opcode 'filter)
1204
(put 'macrop 'rep-compile-fun compile-1-args)
1205
(put 'macrop 'rep-compile-opcode 'macrop)
1206
(put 'bytecodep 'rep-compile-fun compile-1-args)
1207
(put 'bytecodep 'rep-compile-opcode 'bytecodep)
1208
(put 'closurep 'rep-compile-fun compile-1-args)
1209
(put 'closurep 'rep-compile-opcode 'closurep)
1210
(put 'thread-forbid 'rep-compile-fun compile-0-args)
1211
(put 'thread-forbid 'rep-compile-opcode 'forbid)
1212
(put 'thread-permit 'rep-compile-fun compile-0-args)
1213
(put 'thread-permit 'rep-compile-opcode 'permit)
1214
(put 'fluid 'rep-compile-fun compile-1-args)
1215
(put 'fluid 'rep-compile-opcode 'fluid-ref)
1216
(put 'fluid-set 'rep-compile-fun compile-2-args)
1217
(put 'fluid-set 'rep-compile-opcode 'fluid-set)
1219
(put 'caar 'rep-compile-fun compile-1-args)
1220
(put 'caar 'rep-compile-opcode 'caar)
1221
(put 'cadr 'rep-compile-fun compile-1-args)
1222
(put 'cadr 'rep-compile-opcode 'cadr)
1223
(put 'cdar 'rep-compile-fun compile-1-args)
1224
(put 'cdar 'rep-compile-opcode 'cdar)
1225
(put 'cddr 'rep-compile-fun compile-1-args)
1226
(put 'cddr 'rep-compile-opcode 'cddr)
1227
(put 'caddr 'rep-compile-fun compile-1-args)
1228
(put 'caddr 'rep-compile-opcode 'caddr)
1229
(put 'cadddr 'rep-compile-fun compile-1-args)
1230
(put 'cadddr 'rep-compile-opcode 'cadddr)
1232
(put 'floor 'rep-compile-fun compile-1-args)
1233
(put 'floor 'rep-compile-opcode 'floor)
1234
(put 'ceiling 'rep-compile-fun compile-1-args)
1235
(put 'ceiling 'rep-compile-opcode 'ceiling)
1236
(put 'truncate 'rep-compile-fun compile-1-args)
1237
(put 'truncate 'rep-compile-opcode 'truncate)
1238
(put 'round 'rep-compile-fun compile-1-args)
1239
(put 'round 'rep-compile-opcode 'round)
1240
(put 'exp 'rep-compile-fun compile-1-args)
1241
(put 'exp 'rep-compile-opcode 'exp)
1242
(put 'sin 'rep-compile-fun compile-1-args)
1243
(put 'sin 'rep-compile-opcode 'sin)
1244
(put 'cos 'rep-compile-fun compile-1-args)
1245
(put 'cos 'rep-compile-opcode 'cos)
1246
(put 'tan 'rep-compile-fun compile-1-args)
1247
(put 'tan 'rep-compile-opcode 'tan)
1248
(put 'sqrt 'rep-compile-fun compile-1-args)
1249
(put 'sqrt 'rep-compile-opcode 'sqrt)
1250
(put 'expt 'rep-compile-fun compile-2-args)
1251
(put 'expt 'rep-compile-opcode 'expt)
1254
(put 'string= 'rep-compile-fun compile-2-args)
1255
(put 'string= 'rep-compile-opcode 'equal)
1256
(put 'string< 'rep-compile-fun compile-transitive-relation)
1257
(put 'string< 'rep-compile-opcode 'lt)
1258
(put '% 'rep-compile-fun compile-2-args)
1259
(put '% 'rep-compile-opcode 'rem)
1260
(put 'modulo 'rep-compile-fun compile-2-args)
1261
(put 'modulo 'rep-compile-opcode 'mod)
1262
(put 'lsh 'rep-compile-fun compile-2-args)
1263
(put 'lsh 'rep-compile-opcode 'ash))
1265
;; setup properties to tell the compiler where to look for symbols
1266
;; in the `rep' package
1267
(unless (get 'rep 'compiler-handler-property)
1268
(put 'rep 'compiler-handler-property 'rep-compile-fun)
1269
(put 'rep 'compiler-transform-property 'rep-compile-transform)
1270
(put 'rep 'compiler-sequencer 'progn)
1271
(put 'rep 'compiler-pass-1 pass-1)
1272
(put 'rep 'compiler-pass-2 pass-2)
1273
(put 'rep 'compiler-foldablep foldablep)))