1 ;;;;------------------------------------------------------------------
3 ;;;; Copyright (C) 2000-2005,
4 ;;;; Department of Computer Science, University of Tromso, Norway
6 ;;;; Filename: special-operators-cl.lisp
7 ;;;; Description: Special operators in the COMMON-LISP package.
8 ;;;; Author: Frode Vatvedt Fjeld <frodef@acm.org>
9 ;;;; Created at: Fri Nov 24 16:31:11 2000
10 ;;;; Distribution: See the accompanying file COPYING.
12 ;;;; $Id: special-operators-cl.lisp,v 1.53 2007/04/11 22:09:39 ffjeld Exp $
14 ;;;;------------------------------------------------------------------
18 (define-special-operator progn
(&all all
&form form
&top-level-p top-level-p
&result-mode result-mode
)
19 (compiler-call #'compile-implicit-progn
23 (defun expand-to-operator (operator form env
)
24 "Attempt to compiler-macroexpand FORM to having operator OPERATOR."
25 (if (and (listp form
) (eq operator
(first form
)))
27 (multiple-value-bind (expansion expanded-p
)
28 (like-compile-macroexpand-form form env
)
30 (expand-to-operator operator expansion env
)
33 (defun parse-let-var-specs (let-var-specs)
34 "Given a list of LET variable specifiers (i.e. either VAR or (VAR INIT-FORM)),~
35 return a list on the canonical form (VAR INIT-FORM)."
36 (loop for var-spec in let-var-specs
38 collect
`(,var-spec nil
)
39 else if
(and (listp var-spec
)
40 (= 1 (length var-spec
)))
41 collect
`(,(first var-spec
) nil
)
42 else do
(assert (and (listp var-spec
)
43 (= 2 (length var-spec
))))
44 and collect var-spec
))
46 (define-special-operator let
(&all all
&form form
&funobj funobj
&env env
&result-mode result-mode
)
47 "An extent-nested let is this: (let ((foo ..) (bar (.. (let ((zot ..)) ..)))))
48 where zot is not in foo's scope, but _is_ in foo's extent."
49 (destructuring-bind (operator let-var-specs
&body forms
)
51 (declare (ignore operator
))
52 (multiple-value-bind (body declarations
)
53 (parse-declarations-and-body forms
)
54 (if (and (null let-var-specs
)
56 (compiler-call #'compile-implicit-progn
59 (let* ((let-modifies nil
)
60 (let-vars (parse-let-var-specs let-var-specs
))
61 (local-env (make-local-movitz-environment env funobj
63 :declarations declarations
))
64 (init-env #+ignore env
65 (make-instance 'movitz-environment
68 :extent-uplink local-env
))
71 (loop for
(var init-form
) in let-vars
72 if
(movitz-env-get var
'special nil local-env
)
73 ;; special... see losp/cl/run-time.lisp
77 (append (if (= 0 (num-specials local-env
)) ; first special? .. binding tail
78 `((:locally
(:pushl
(:edi
(:edi-offset dynamic-env
)))))
80 (compiler-call #'compile-form
; binding value
81 :with-stack-used
(incf stack-used
)
85 :modify-accumulate let-modifies
87 `((:pushl
:edi
)) ; scratch
88 (compiler-call #'compile-form
; binding name
89 :with-stack-used
(incf stack-used
2)
92 :form
`(muerte.cl
:quote
,var
)
94 (prog1 nil
(incf stack-used
)))
96 and do
(movitz-env-add-binding local-env
(make-instance 'dynamic-binding
98 and do
(incf (num-specials local-env
))
101 (let ((binding (make-instance 'located-binding
:name var
)))
102 (movitz-env-add-binding local-env binding
)
103 (compiler-values-bind (&code init-code
&functional-p functional-p
104 &type type
&returns init-register
105 &final-form final-form
)
107 (compiler-call #'compile-form-unprotected
114 (compiler-call #'compile-form-to-register
119 :modify-accumulate let-modifies
)
120 (when (eq binding init-register
)
121 (setf init-register nil
))
122 ;;; (warn "var ~S, type: ~S" var type)
123 ;;; (warn "var ~S init: ~S.." var init-form)
124 ;;; (warn "bind: ~S reg: ~S" binding init-register)
125 ;;; (print-code 'init init-code)
130 (let ((init-type (type-specifier-primary type
)))
132 "The init-form ~S yielded the empty primary type!" type
)
135 (:non-local-exit
:edi
)
136 (:multiple-values
:eax
)
139 (setf (stack-used local-env
) stack-used
)
140 (flet ((compile-body ()
141 (if (= 0 (num-specials local-env
))
142 (compiler-call #'compile-implicit-progn
146 (compiler-call #'compile-form
147 :result-mode
(case result-mode
149 (:function
:multiple-values
)
152 :form
`(muerte.cl
:progn
,@body
)
153 :modify-accumulate let-modifies
155 (compiler-values-bind (&all body-values
&code body-code
&returns body-returns
)
157 ;; (print-code 'body body)
158 ;; (print-code 'body-code body-code)
159 (let ((first-binding (movitz-binding (caar binding-var-codes
) local-env nil
)))
161 ;; Is this (let ((#:foo <form>)) (setq bar #:foo)) ?
162 ;; If so, make it into (setq bar <form>)
163 ((and (= 1 (length binding-var-codes
))
164 (typep first-binding
'lexical-binding
)
165 (instruction-is (first body-code
) :load-lexical
)
166 (instruction-is (second body-code
) :store-lexical
)
167 (null (cddr body-code
))
168 (eq first-binding
; same binding?
169 (second (first body-code
)))
170 (eq (third (first body-code
)) ; same register?
171 (third (second body-code
))))
172 (let ((dest-binding (second (second body-code
))))
173 (check-type dest-binding lexical-binding
)
174 (compiler-call #'compile-form
177 :result-mode dest-binding
178 :form
(second (first binding-var-codes
)))))
180 ((and (= 1 (length binding-var-codes
))
181 (typep (movitz-binding (caar binding-var-codes
) local-env nil
)
183 (member (movitz-binding (caar binding-var-codes
) local-env nil
)
184 (find-read-bindings (first body-code
)))
185 (not (code-uses-binding-p (rest body-code
) (second (first body-code
))
186 :load t
:store nil
)))
187 (let ((tmp-binding (second (first body-code
))))
188 (print-code 'body body-code
)
189 (break "Yuhu: tmp ~S" tmp-binding
)
195 for
((var init-form init-code functional-p type init-register
199 as binding
= (movitz-binding var local-env nil
)
200 ;; for bb in binding-var-codes
201 ;; do (warn "bind: ~S" bb)
203 (assert (not (binding-lended-p binding
)))
206 ((and (typep binding
'located-binding
)
207 (not (binding-lended-p binding
))
208 (typep final-form
'lexical-binding
)
209 (let ((target-binding final-form
))
210 (and (typep target-binding
'lexical-binding
)
211 (eq (binding-funobj binding
)
212 (binding-funobj target-binding
))
214 (sub-env-p (binding-env binding
)
215 (binding-env target-binding
))
216 (or (and (not (code-uses-binding-p body-code
220 (not (code-uses-binding-p body-code
224 (and (= 1 (length body-code
))
225 (eq :add
(caar body-code
)))
226 (and (>= 1 (length body-code
))
227 (warn "short let body: ~S" body-code
))
228 ;; This is the best we can do now to determine
229 ;; if target-binding is ever used again.
230 (and (eq result-mode
:function
)
231 (not (and (bindingp body-returns
)
232 (binding-eql target-binding
234 (not (code-uses-binding-p body-code
238 (notany (lambda (code)
239 (code-uses-binding-p (third code
)
244 ;; replace read-only binding with the outer binding
245 (compiler-values-bind (&code new-init-code
&final-form target
247 (compiler-call #'compile-form-unprotected
253 (check-type target lexical-binding
)
254 (change-class binding
'forwarding-binding
255 :target-binding target
)
256 (let ((btype (if (multiple-value-call #'encoded-allp
257 (type-specifier-encode
258 (type-specifier-primary type
)))
260 (type-specifier-primary type
))))
261 #+ignore
(warn "forwarding ~S -[~S]> ~S"
262 binding btype target
)
263 (append new-init-code
266 :init-with-register
,target
267 :init-with-type
,btype
))))))
268 ((and (typep binding
'located-binding
)
269 (type-specifier-singleton type
)
270 (not (code-uses-binding-p body-code binding
271 :load nil
:store t
)))
272 ;; replace read-only lexical binding with
273 ;; side-effect-free form
275 (warn "Constant binding: ~S => ~S => ~S"
276 (binding-name binding
)
278 (car (type-specifier-singleton type
)))
279 (change-class binding
'constant-object-binding
280 :object
(car (type-specifier-singleton type
)))
282 nil
; only inject code if it's got side-effects.
283 (compiler-call #'compile-form-unprotected
289 :modify-accumulate let-modifies
)))
290 ((typep binding
'lexical-binding
)
291 (let ((init (type-specifier-singleton
292 (type-specifier-primary type
))))
294 ((and init
(eq *movitz-nil
* (car init
)))
295 (append (if functional-p
297 (compiler-call #'compile-form-unprotected
303 :modify-accumulate let-modifies
))
304 `((:init-lexvar
,binding
305 :init-with-register
:edi
306 :init-with-type null
))))
307 ((and (typep final-form
'lexical-binding
)
308 (eq (binding-funobj final-form
)
310 (compiler-values-bind (&code new-init-code
312 &final-form new-binding
)
313 (compiler-call #'compile-form-unprotected
319 :modify-accumulate let-modifies
)
320 (append (if functional-p
323 (let ((ptype (type-specifier-primary new-type
)))
324 `((:init-lexvar
,binding
325 :init-with-register
,new-binding
326 :init-with-type
,ptype
328 ((typep final-form
'constant-object-binding
)
330 (warn "type: ~S or ~S" final-form
331 (type-specifier-primary type
))
332 (append (if functional-p
334 (compiler-call #'compile-form-unprotected
340 :modify-accumulate let-modifies
))
343 :init-with-register
,final-form
344 :init-with-type
,(type-specifier-primary type
)
346 (t ;; (warn "for ~S ~S ~S" binding init-register final-form)
350 :init-with-register
,init-register
351 :init-with-type
,(type-specifier-primary type
))))))))
353 (when (plusp (num-specials local-env
))
354 `((:locally
(:call
(:edi
,(bt:slot-offset
'movitz-run-time-context
355 'dynamic-variable-install
))))
356 (:locally
(:movl
:esp
(:edi
(:edi-offset dynamic-env
))))))
358 (when (and (plusp (num-specials local-env
))
359 (not (eq :non-local-exit body-returns
)))
361 (warn "let spec ret: ~S, want: ~S ~S"
362 body-returns result-mode let-var-specs
)
363 `((:movl
(:esp
,(+ -
4 (* 16 (num-specials local-env
)))) :edx
)
364 (:locally
(:call
(:edi
,(bt:slot-offset
'movitz-run-time-context
365 'dynamic-variable-uninstall
))))
366 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
367 (:leal
(:esp
,(* 16 (num-specials local-env
))) :esp
))))))
368 (compiler-values (body-values)
369 :returns body-returns
370 :producer
(default-compiler-values-producer)
371 :functional-p
(and (body-values :functional-p
)
372 (every #'fourth binding-var-codes
))
373 :modifies let-modifies
374 :code code
))))))))))))
376 (define-special-operator symbol-macrolet
(&all forward
&form form
&env env
&funobj funobj
)
377 (destructuring-bind (symbol-expansions &body declarations-and-body
)
379 (multiple-value-bind (body declarations
)
380 (parse-declarations-and-body declarations-and-body
)
381 (let ((local-env (make-local-movitz-environment
384 :declarations declarations
)))
385 (loop for symbol-expansion in symbol-expansions
386 do
(destructuring-bind (symbol expansion
)
388 (movitz-env-add-binding local-env
(make-instance 'symbol-macro-binding
390 :expander
#'(lambda (form env
)
391 (declare (ignore form env
))
393 (compiler-values-bind (&all body-values
&code body-code
)
394 (compiler-call #'compile-implicit-progn
398 :top-level-p
(forward :top-level-p
))
399 (compiler-values (body-values)
400 :code body-code
))))))
402 (define-special-operator macrolet
(&all forward
&form form
&funobj funobj
&env env
)
403 (destructuring-bind (macrolet-specs &body declarations-and-body
)
405 (multiple-value-bind (body declarations
)
406 (parse-declarations-and-body declarations-and-body
)
407 (let ((local-env (make-local-movitz-environment env funobj
409 :declarations declarations
)))
410 (loop for
(name local-lambda-list . local-body-decl-doc
) in macrolet-specs
411 as cl-local-lambda-list
= (translate-program local-lambda-list
:muerte.cl
:cl
)
412 as
(local-body local-declarations
) =
413 (multiple-value-list (parse-docstring-declarations-and-body local-body-decl-doc
))
414 as cl-local-body
= (translate-program local-body
:muerte.cl
:cl
)
415 as cl-local-declarations
= (translate-program local-declarations
:muerte.cl
:cl
)
416 as expander
= `(lambda (form env
)
417 (declare (ignorable env
))
418 (destructuring-bind ,cl-local-lambda-list
419 (translate-program (rest form
) :muerte.cl
:cl
)
420 (declare ,@cl-local-declarations
)
421 (translate-program (block ,name
(let () ,@cl-local-body
))
423 do
(movitz-env-add-binding
425 (make-instance 'macro-binding
427 :expander
(movitz-macro-expander-make-function expander
430 (compiler-values-bind (&all body-values
&code body-code
)
431 (compiler-call #'compile-implicit-progn
435 :top-level-p
(forward :top-level-p
))
436 (compiler-values (body-values)
437 :code body-code
))))))
439 (define-special-operator multiple-value-prog1
(&all all
&form form
&result-mode result-mode
&env env
)
440 (destructuring-bind (first-form &rest rest-forms
)
442 (compiler-values-bind (&code form1-code
&returns form1-returns
&type type
)
443 (compiler-call #'compile-form-unprotected
445 :result-mode
(case (result-mode-type result-mode
)
446 ((:boolean-branch-on-true
:boolean-branch-on-false
)
450 (compiler-call #'special-operator-with-cloak
451 ;; :with-stack-used t
453 :form
`(muerte::with-cloak
(,form1-returns
,form1-code t
,type
)
456 (define-special-operator multiple-value-call
(&all all
&form form
&funobj funobj
)
457 (destructuring-bind (function-form &rest subforms
)
459 (let* ((local-env (make-instance 'let-env
463 (numargs-binding (movitz-env-add-binding local-env
464 (make-instance 'located-binding
465 :name
(gensym "m-v-numargs-"))))
466 (arg-code (loop for subform in subforms
468 (compiler-values-bind (&code subform-code
&returns subform-returns
)
469 (compiler-call #'compile-form-unprotected
473 :result-mode
:multiple-values
)
474 (case subform-returns
478 ,@(make-compiled-push-current-values)
479 (:load-lexical
,numargs-binding
:eax
)
481 (:store-lexical
,numargs-binding
:eax
:type fixnum
)))
482 (t (list :single
; marker, used below
484 (number-of-multiple-value-subforms (count :multiple arg-code
:key
#'car
))
485 (number-of-single-value-subforms (count :single arg-code
:key
#'car
)))
487 ((= 0 number-of-multiple-value-subforms
)
488 (compiler-call #'compile-form
490 :form
`(muerte.cl
::funcall
,function-form
,@subforms
)))
491 (t (compiler-values ()
492 :returns
:multiple-values
493 :code
(append `((:load-constant
,(1+ number-of-single-value-subforms
) :eax
)
494 (:store-lexical
,numargs-binding
:eax
:type fixnum
))
495 (compiler-call #'compile-form
500 (loop for ac in arg-code
501 append
(ecase (car ac
)
503 (compiler-call #'compile-form
510 `((:load-lexical
,numargs-binding
:ecx
)
511 ;; (:store-lexical ,numargs-binding :ecx :type t)
512 (:movl
(:esp
(:ecx
1) -
4) :eax
)
513 (:movl
(:esp
(:ecx
1) -
8) :ebx
)
514 (:shrl
,+movitz-fixnum-shift
+ :ecx
)
515 (:load-constant muerte.cl
::funcall
:edx
)
516 (:movl
(:edx
,(slot-offset 'movitz-symbol
'function-value
))
517 :esi
) ; load new funobj from symbol into ESI
518 (:call
(:esi
,(slot-offset 'movitz-funobj
'code-vector
)))
519 (:load-lexical
,numargs-binding
:edx
)
520 ;; Use LEA so as not to modify CF
521 (:leal
(:esp
:edx
) :esp
)))))))))
525 (define-special-operator multiple-value-bind
(&all forward
&form form
&env env
&funobj funobj
526 &result-mode result-mode
)
527 (destructuring-bind (variables values-form
&body body-and-declarations
)
529 (multiple-value-bind (body declarations
)
530 (parse-declarations-and-body body-and-declarations
)
531 (compiler-values-bind (&code values-code
&returns values-returns
&type values-type
)
532 (compiler-call #'compile-form
535 :result-mode
:multiple-values
#+ignore
(list :values
(length variables
)))
536 ;;; (warn "mv-code: ~W ~W => ~W ~W" values-form (list :values (length variables)) values-returns (last values-code 10))
537 (let* ((local-env (make-local-movitz-environment
540 :declarations declarations
))
542 (loop for variable in variables
543 as new-binding
= (make-instance 'located-binding
545 do
(check-type variable symbol
)
548 ((movitz-env-get variable
'special nil env
)
549 (let* ((shadowed-variable (gensym (format nil
"m-v-bind-shadowed-~A"
551 (movitz-env-add-binding local-env new-binding shadowed-variable
)
552 (push (list variable shadowed-variable
)
553 (special-variable-shadows local-env
))))
554 (t (movitz-env-add-binding local-env new-binding
)))))
556 (case (first (operands values-returns
))
559 (make-result-and-returns-glue :multiple-values values-returns
)
560 (case (length lexical-bindings
)
562 (1 `((:init-lexvar
,(first lexical-bindings
)
564 :protect-registers
'(:eax
))
565 (:store-lexical
,(first lexical-bindings
) :eax
566 :type
,(type-specifier-primary values-type
))))
567 (2 (let ((done-label (gensym "m-v-bind-done-")))
568 `((:init-lexvar
,(first lexical-bindings
)
570 :protect-registers
(:eax
:ebx
))
571 (:store-lexical
,(first lexical-bindings
) :eax
572 :type
,(type-specifier-primary values-type
)
573 :protect-registers
(:ebx
))
574 (:init-lexvar
,(second lexical-bindings
)
576 :protect-registers
(:ebx
))
577 (:store-lexical
,(second lexical-bindings
) :edi
582 (:store-lexical
,(second lexical-bindings
) :ebx
583 :type
,(type-specifier-nth-value 1 values-type
))
585 (t (with-labels (m-v-bind (ecx-ok-label))
586 `((:jc
',ecx-ok-label
)
587 ,@(make-immediate-move 1 :ecx
) ; CF=0 means arg-count=1
589 ,@(loop for binding in lexical-bindings as pos upfrom
0
590 as skip-label
= (gensym "m-v-bind-skip-")
591 as type
= (type-specifier-nth-value pos values-type
)
594 (0 `((:init-lexvar
,binding
595 :protect-registers
(:eax
:ebx
:ecx
))
596 (:store-lexical
,binding
:eax
:type
,type
597 :protect-registers
(:eax
:ebx
:ecx
))))
598 (1 `((:init-lexvar
,binding
599 :protect-registers
(:ebx
:ecx
))
600 (:store-lexical
,binding
:edi
:type null
601 :protect-registers
(:ecx
))
604 (:store-lexical
,binding
:ebx
:type
,type
605 :protect-registers
(:ecx
))
607 (t (if *compiler-use-cmov-p
*
608 `((:init-lexvar
,binding
:protect-registers
'(:ecx
))
611 (:locally
(:cmova
(:edi
(:edi-offset values
614 (:store-lexical
,binding
:eax
:type
,type
615 :protect-registers
(:eax
)))
616 `((:init-lexvar
,binding
:protect-registers
'(:ecx
))
620 (:locally
(:movl
(:edi
(:edi-offset values
624 (:store-lexical
,binding
:eax
:type
,type
625 :protect-registers
(:ecx
))))))))))))))))
626 (compiler-values-bind (&code body-code
&returns body-returns-mode
)
627 (compiler-call #'compile-form-unprotected
629 :form
`(muerte.cl
:let
,(special-variable-shadows local-env
) ,@body
)
632 :returns body-returns-mode
633 :code
(append values-code
637 (define-special-operator setq
(&all forward
&form form
&env env
&funobj funobj
&result-mode result-mode
)
638 (let ((pairs (cdr form
)))
639 (unless (evenp (length pairs
))
640 (error "Odd list of SETQ pairs: ~S" pairs
))
641 (let* ((last-returns :nothing
)
644 for
(var value-form
) on pairs by
#'cddr
645 as binding
= (movitz-binding var env
)
646 as pos downfrom
(- (length pairs
) 2) by
2
647 as sub-result-mode
= (if (zerop pos
) result-mode
:ignore
)
648 do
(pushnew binding bindings
)
651 (symbol-macro-binding
652 (compiler-values-bind (&code code
&returns returns
)
653 (compiler-call #'compile-form-unprotected
655 :result-mode sub-result-mode
656 :form
`(muerte.cl
:setf
,var
,value-form
))
657 (setf last-returns returns
)
660 (case (operator sub-result-mode
)
662 ;; (setf last-returns :nothing)
663 (compiler-values-bind (&code sub-code
&returns sub-returns
)
664 (compiler-call #'compile-form
667 :result-mode binding
)
668 (setf last-returns sub-returns
)
669 ;; (warn "sub-returns: ~S" sub-returns)
672 (t (let ((register (accept-register-mode sub-result-mode
)))
673 (compiler-values-bind (&code code
&type type
)
674 (compiler-call #'compile-form
677 :result-mode register
)
678 (setf last-returns register
)
680 `((:store-lexical
,binding
,register
681 :type
,(type-specifier-primary type
)))))))))
682 (t (unless (movitz-env-get var
'special nil env
)
683 (warn "Assuming destination variable ~S with binding ~S is special."
685 (setf last-returns
:ebx
)
686 (append (compiler-call #'compile-form
690 `((:load-constant
,var
:eax
)
691 (:locally
(:call
(:edi
(:edi-offset dynamic-variable-store
)))))))))))
694 :returns last-returns
695 :functional-p nil
))))
697 (define-special-operator tagbody
(&all forward
&funobj funobj
&form form
&env env
)
698 (let* ((save-esp-variable (gensym "tagbody-save-esp"))
699 (lexical-catch-tag-variable (gensym "tagbody-lexical-catch-tag-"))
700 (label-set-name (gensym "label-set-"))
701 (tagbody-env (make-instance 'tagbody-env
704 :save-esp-variable save-esp-variable
705 :lexical-catch-tag-variable lexical-catch-tag-variable
706 :exit-result-mode
:ignore
))
707 (save-esp-binding (make-instance 'located-binding
708 :name save-esp-variable
))
709 (lexical-catch-tag-binding (make-instance 'located-binding
710 :name lexical-catch-tag-variable
)))
711 (movitz-env-add-binding tagbody-env save-esp-binding
)
712 (movitz-env-add-binding tagbody-env lexical-catch-tag-binding
)
713 (movitz-env-load-declarations `((muerte.cl
::ignorable
,save-esp-variable
,lexical-catch-tag-variable
))
715 ;; First generate an assembly-level label for each tag.
716 (let* ((label-set (loop with label-id
= 0
717 for tag-or-statement in
(cdr form
)
718 as label
= (when (or (symbolp tag-or-statement
)
719 (integerp tag-or-statement
))
720 (gensym (format nil
"go-tag-~A-" tag-or-statement
)))
722 do
(setf (movitz-env-get tag-or-statement
'go-tag nil tagbody-env
)
724 (setf (movitz-env-get tag-or-statement
'go-tag-label-id nil tagbody-env
)
725 (post-incf label-id
))
728 (loop for tag-or-statement in
(cdr form
)
729 if
(or (symbolp tag-or-statement
) ; Tagbody tags are "compiled" into..
730 (integerp tag-or-statement
)) ; ..their assembly-level labels.
731 collect
(movitz-env-get tag-or-statement
'go-tag nil tagbody-env
)
733 (compiler-call #'compile-form
735 :form tag-or-statement
737 :result-mode
:ignore
))))
738 (let* ((unlexical-target-p (some (lambda (code)
740 (code-uses-binding-p code save-esp-binding
)))
742 (maybe-store-esp-code
743 (when (or unlexical-target-p
746 (operators-present-in-code-p code
'(:lexical-control-transfer
) nil
748 (eq tagbody-env
(fifth x
))))))
750 `((:init-lexvar
,save-esp-binding
751 :init-with-register
:esp
752 :init-with-type t
)))))
753 (if (not unlexical-target-p
)
755 :code
(append maybe-store-esp-code
756 (loop for code in tagbody-codes
759 else append
(list code
)))
761 (let ((code (append `((:declare-label-set
,label-set-name
,label-set
)
763 (:locally
(:pushl
(:edi
(:edi-offset dynamic-env
))))
764 (:pushl
',label-set-name
)
765 (:locally
(:pushl
(:edi
(:edi-offset unbound-function
))))
767 (:locally
(:movl
:esp
(:edi
(:edi-offset dynamic-env
)))))
769 (loop for code in tagbody-codes
772 else append
(list code
'(:movl
(:esp
) :ebp
)))
773 `((:movl
(:esp
12) :edx
)
774 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
775 (:leal
(:esp
16) :esp
))
777 (setf (num-specials tagbody-env
) 1
778 (stack-used tagbody-env
) 4)
781 :returns
:nothing
)))))))
784 (define-special-operator go
(&all all
&form form
&env env
&funobj funobj
)
785 (destructuring-bind (operator tag
)
787 (declare (ignore operator
))
788 (multiple-value-bind (label tagbody-env
)
789 (movitz-env-get tag
'go-tag nil env
)
790 (assert (and label tagbody-env
) ()
791 "Go-tag ~W is not visible." tag
)
792 (multiple-value-bind (stack-distance num-dynamic-slots unwind-protects
)
793 (stack-delta env tagbody-env
)
794 (declare (ignore stack-distance
))
795 (if (and (eq funobj
(movitz-environment-funobj tagbody-env
))
796 ;; A well-known number of dynamic-slots?
797 (not (eq t num-dynamic-slots
))
798 ;; any unwind-protects between here and there?
799 (null unwind-protects
))
801 :returns
:non-local-exit
802 :code
`((:lexical-control-transfer nil
:nothing
,env
,tagbody-env
,label
)))
803 ;; Perform a lexical "throw" to the tag. Just like a regular (dynamic) throw.
804 (let ((save-esp-binding (movitz-binding (save-esp-variable tagbody-env
) env
))
805 (label-id (movitz-env-get tag
'go-tag-label-id nil tagbody-env nil
)))
808 :returns
:non-local-exit
809 :code
`((:load-lexical
,save-esp-binding
:edx
)
811 ,@(when (plusp label-id
)
812 ;; The target jumper points to the tagbody's label-set.
813 ;; Now, install correct jumper within tagbody as target.
814 `((:addl
,(* 4 label-id
) (:edx
8))))
815 (:locally
(:call
(:edi
(:edi-offset dynamic-unwind-next
))))
816 ;; have next-continuation in EAX, final-continuation in EDX
817 (:locally
(:movl
:edx
(:edi
(:edi-offset raw-scratch0
)))) ; final continuation
818 (:locally
(:movl
:eax
(:edi
(:edi-offset dynamic-env
)))) ; new dynamic-env
821 (:locally
(:call
(:edi
(:edi-offset dynamic-jump-next
))))))))))))
823 ;;; (:locally (:movl :edx (:edi (:edi-offset dynamic-env)))) ; exit to next-env
824 ;;; (:movl :edx :esp) ; enter non-local jump stack mode.
825 ;;; (:movl (:esp) :edx) ; target stack-frame EBP
826 ;;; (:movl (:edx -4) :esi) ; get target funobj into ESI
827 ;;; (:movl (:esp 8) :edx) ; target jumper number
828 ;;; (:jmp (:esi :edx ,(slot-offset 'movitz-funobj 'constant0)))))))))))
830 (define-special-operator block
(&all forward
&funobj funobj
&form form
&env env
831 &result-mode result-mode
)
832 (destructuring-bind (block-name &body body
)
834 (let* ((exit-block-label (gensym (format nil
"exit-block-~A-" block-name
)))
835 (save-esp-variable (gensym (format nil
"block-~A-save-esp-" block-name
)))
836 (lexical-catch-tag-variable (gensym (format nil
"block-~A-lexical-catch-tag-" block-name
)))
837 (block-result-mode (case result-mode
838 ((:eax
:eax
:multiple-values
:function
:ebx
:ecx
:ignore
)
841 (block-returns-mode (case (result-mode-type block-result-mode
)
842 (:function
:multiple-values
)
844 ((:boolean-branch-on-true
:boolean-branch-on-false
) :eax
)
845 (t block-result-mode
)))
846 (block-env (make-instance 'lexical-exit-point-env
849 :save-esp-variable save-esp-variable
850 :lexical-catch-tag-variable lexical-catch-tag-variable
851 :exit-label exit-block-label
852 :exit-result-mode block-result-mode
))
853 (save-esp-binding (make-instance 'located-binding
854 :name save-esp-variable
)))
855 (movitz-env-add-binding block-env save-esp-binding
)
856 (movitz-env-load-declarations `((muerte.cl
::ignorable
,save-esp-variable
))
858 (setf (movitz-env-get block-name
:block-name nil block-env
)
860 (compiler-values-bind (&code block-code
&functional-p block-no-side-effects-p
)
861 (compiler-call #'compile-form
863 :result-mode
(case block-result-mode
864 (:function
:multiple-values
) ; must restore stack
865 (t block-result-mode
))
866 :form
`(muerte.cl
:progn
,@body
)
868 (let ((label-set-name (gensym "block-label-set-"))
869 (maybe-store-esp-code
870 (when (and #+ignore
(not (eq block-result-mode
:function
))
871 (operators-present-in-code-p block-code
'(:lexical-control-transfer
) nil
872 :test
(lambda (x) (eq block-env
(fifth x
)))))
873 `((:init-lexvar
,save-esp-binding
874 :init-with-register
:esp
875 :init-with-type t
)))))
876 (if (not (code-uses-binding-p block-code save-esp-binding
))
878 :code
(append maybe-store-esp-code
880 (list exit-block-label
))
881 :returns block-returns-mode
882 :functional-p block-no-side-effects-p
)
883 (multiple-value-bind (new-code new-returns
)
884 (make-result-and-returns-glue :multiple-values block-returns-mode block-code
)
885 (assert (eq :multiple-values new-returns
))
886 (incf (stack-used block-env
) 4)
887 (setf (num-specials block-env
) 1) ; block-env now has one dynamic slot
889 :code
(append `((:declare-label-set
,label-set-name
(,exit-block-label
))
891 (:locally
(:pushl
(:edi
(:edi-offset dynamic-env
))))
892 (:pushl
',label-set-name
)
893 (:locally
(:pushl
(:edi
(:edi-offset unbound-function
))))
895 (:locally
(:movl
:esp
(:edi
(:edi-offset dynamic-env
)))))
896 `((:init-lexvar
,save-esp-binding
897 :init-with-register
:esp
902 (:movl
(:esp
0) :ebp
)
903 (:movl
(:esp
12) :edx
)
904 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
905 (:leal
(:esp
16) :esp
)))
906 :returns
:multiple-values
907 :functional-p block-no-side-effects-p
))))))))
909 (define-special-operator return-from
(&all all
&form form
&env env
&funobj funobj
)
910 (destructuring-bind (block-name &optional result-form
)
912 (let ((block-env (movitz-env-get block-name
:block-name nil env
)))
913 (assert block-env
(block-name)
914 "Block-name not found for return-from: ~S." block-name
)
915 (multiple-value-bind (stack-distance num-dynamic-slots unwind-protects
)
916 (stack-delta env block-env
)
917 (declare (ignore stack-distance
))
919 ((and (eq funobj
(movitz-environment-funobj block-env
))
920 (not (eq t num-dynamic-slots
))
921 (null unwind-protects
))
922 (compiler-values-bind (&code return-code
&returns return-mode
)
923 (compiler-call #'compile-form
926 :result-mode
(exit-result-mode block-env
))
928 :returns
:non-local-exit
929 :code
(append return-code
930 `((:lexical-control-transfer nil
,return-mode
,env
,block-env
))))))
931 ((not (and (eq funobj
(movitz-environment-funobj block-env
))
932 (not (eq t num-dynamic-slots
))
933 (null unwind-protects
)))
934 (compiler-call #'compile-form-unprotected
936 :form
`(muerte::exact-throw
,(save-esp-variable block-env
)
939 (define-special-operator require
(&form form
)
940 (let ((*require-dependency-chain
*
941 (and (boundp '*require-dependency-chain
*)
942 (symbol-value '*require-dependency-chain
*))))
943 (declare (special *require-dependency-chain
*))
944 (destructuring-bind (module-name &optional path-spec
)
946 (declare (ignore path-spec
))
947 (push module-name
*require-dependency-chain
*)
948 (unless (member module-name
(image-movitz-modules *image
*))
949 (when (member module-name
(cdr *require-dependency-chain
*))
950 (error "Circular Movitz module dependency chain: ~S"
951 (reverse (subseq *require-dependency-chain
* 0
952 (1+ (position module-name
*require-dependency-chain
* :start
1))))))
953 (let* ((require-path (movitz-module-path form
)))
954 (movitz-compile-file-internal require-path
)
955 (unless (member module-name
(image-movitz-modules *image
*))
956 (error "Compiling file ~S didn't provide module ~S."
957 require-path module-name
))))))
958 (compiler-values ()))
960 (define-special-operator provide
(&form form
&funobj funobj
&top-level-p top-level-p
)
962 (warn "Provide form not at top-level."))
963 (destructuring-bind (module-name &key load-priority
)
965 (declare (special *default-load-priority
*))
966 (pushnew module-name
(image-movitz-modules *image
*))
968 (setf *default-load-priority
* load-priority
))
969 (let ((new-priority *default-load-priority
*))
970 (let ((old-tf (member module-name
(image-load-time-funobjs *image
*) :key
#'second
)))
972 ((and new-priority old-tf
)
973 (setf (car old-tf
) (list funobj module-name new-priority
)))
974 ((and new-priority
(not old-tf
))
975 (push (list funobj module-name new-priority
)
976 (image-load-time-funobjs *image
*)))
978 (setf (car old-tf
) (list funobj module-name
(third (car old-tf
)))))
979 (t (warn "No existing or provided load-time priority for module ~S, will not be loaded!"
981 (compiler-values ()))
983 (define-special-operator eval-when
(&all forward
&form form
&top-level-p top-level-p
)
984 (destructuring-bind (situations &body body
)
986 (multiple-value-prog1
987 (if (or (member :execute situations
)
988 (and (member :load-toplevel situations
)
990 (compiler-call #'compile-implicit-progn
992 :top-level-p top-level-p
994 (compiler-values ()))
995 (when (member :compile-toplevel situations
)
996 (with-compilation-unit ()
997 (dolist (toplevel-form (translate-program body
:muerte.cl
:cl
999 :remove-double-quotes-p t
))
1000 (with-host-environment ()
1001 (if *compiler-compile-eval-whens
*
1002 (funcall (compile () `(lambda () ,toplevel-form
)))
1003 (eval toplevel-form
)))))))))
1005 (define-special-operator function
(&funobj funobj
&form form
&result-mode result-mode
&env env
)
1006 (destructuring-bind (name)
1008 (flet ((function-of-symbol (name)
1009 "Look up name in the local function namespace."
1010 (let ((movitz-name (movitz-read name
))
1011 (register (case result-mode
1012 ((:ebx
:ecx
:edx
) result-mode
)
1015 :code
`((:load-constant
,movitz-name
,register
)
1016 (:movl
(,register
,(bt:slot-offset
'movitz-symbol
'function-value
))
1018 (:globally
(:cmpl
(:edi
(:edi-offset unbound-function
))
1020 (:je
'(:sub-program
()
1021 (:load-constant
,movitz-name
:edx
)
1026 :returns register
))))
1028 (null (error "Can't compile (function nil)."))
1030 (multiple-value-bind (binding)
1031 (movitz-operator-binding name env
)
1033 (null ; not lexically bound..
1034 (function-of-symbol name
))
1037 :code
(make-compiled-lexical-load binding result-mode
)
1039 :returns result-mode
1043 (let ((flet-funobj (funobj-binding-funobj binding
)))
1044 (assert (null (movitz-funobj-borrowed-bindings flet-funobj
)))
1045 (compiler-call #'compile-self-evaluating
; <name> is lexically fbound..
1048 :result-mode result-mode
1049 :form flet-funobj
)))
1051 ((or closure-binding borrowed-binding
)
1053 :code
(make-compiled-lexical-load binding binding-env result-mode
)
1055 :returns result-mode
1056 :functional-p t
)))))
1057 ((cons (eql muerte.cl
:setf
))
1058 (function-of-symbol (movitz-env-setf-operator-name
1059 (muerte::translate-program
(second name
)
1061 ((cons (eql muerte.cl
:lambda
))
1062 (multiple-value-bind (lambda-forms lambda-declarations
)
1063 (parse-docstring-declarations-and-body (cddr name
))
1064 (let ((lambda-funobj
1065 (make-compiled-funobj-pass1 '(muerte.cl
:lambda
)
1068 `(muerte.cl
:progn
,@lambda-forms
)
1070 (let ((lambda-binding (make-instance 'lambda-binding
1071 :name
(gensym "anonymous-lambda-")
1072 :parent-funobj funobj
1073 :funobj lambda-funobj
)))
1074 (movitz-env-add-binding (find-function-env env funobj
) lambda-binding
)
1075 (let ((lambda-result-mode (accept-register-mode result-mode
)))
1079 :returns lambda-result-mode
1081 :code
`((:load-lambda
,lambda-binding
,lambda-result-mode
,env
))))))))))))
1083 (define-special-operator flet
(&all forward
&form form
&env env
&funobj funobj
)
1084 (destructuring-bind (flet-specs &body declarations-and-body
)
1086 (multiple-value-bind (body declarations
)
1087 (parse-declarations-and-body declarations-and-body
)
1088 (let* ((flet-env (make-local-movitz-environment env funobj
1090 :declarations declarations
))
1092 (loop for
(flet-name flet-lambda-list . flet-dd-body
) in flet-specs
1094 (multiple-value-bind (flet-body flet-declarations flet-docstring
)
1095 (parse-docstring-declarations-and-body flet-dd-body
)
1096 (declare (ignore flet-docstring
))
1098 (make-compiled-funobj-pass1 (list 'muerte.cl
::flet
1099 (movitz-funobj-name funobj
)
1103 (list* 'muerte.cl
:block
1104 (compute-function-block-name flet-name
)
1107 (when (find-if (lambda (declaration)
1108 (and (eq 'muerte.cl
:dynamic-extent
(car declaration
))
1109 (member `(muerte.cl
:function
,flet-name
)
1113 (setf (movitz-funobj-extent flet-funobj
) :dynamic-extent
)
1114 (warn "dynamic-extent flet: ~S" flet-name
))
1115 (make-instance 'function-binding
1117 :parent-funobj funobj
1118 :funobj flet-funobj
)))
1119 do
(movitz-env-add-binding flet-env flet-binding
)
1120 collect
`(:local-function-init
,flet-binding
))))
1121 (compiler-values-bind (&all body-values
&code body-code
)
1122 (compiler-call #'compile-implicit-progn
1126 (compiler-values (body-values)
1127 :code
(append init-code body-code
)))))))
1129 (define-special-operator progv
(&all all
&form form
&funobj funobj
&env env
&result-mode result-mode
)
1130 (destructuring-bind (symbols-form values-form
&body body
)
1132 (compiler-values-bind (&code body-code
&returns body-returns
)
1133 (let ((body-env (make-instance 'progv-env
1138 ;; amount of stack used and num-specials is not known until run-time.
1139 (compiler-call #'compile-implicit-progn
1141 :result-mode
(case result-mode
1143 (:function
:multiple-values
)
1148 :returns
(if (eq :push body-returns
) :eax body-returns
)
1149 :code
(append (make-compiled-two-forms-into-registers symbols-form
:ebx
1152 (with-labels (progv (no-more-symbols no-more-values loop zero-specials
))
1153 `((:xorl
:ecx
:ecx
) ; count number of bindings (fixnum)
1154 (:locally
(:pushl
(:edi
(:edi-offset dynamic-env
)))) ; first tail
1156 (:je
'(:sub-program
(,zero-specials
)
1157 ;; Insert dummy binding
1158 (:pushl
:edi
) ; biding value
1159 (:pushl
:edi
) ; scratch
1160 (:pushl
:edi
) ; binding name
1163 (:jmp
',no-more-symbols
)))
1165 (:cmpl
:edi
:ebx
) ; (endp symbols)
1166 (:je
',no-more-symbols
) ; .. (go no-more-symbols)
1167 (:globally
(:movl
(:edi
(:edi-offset new-unbound-value
)) :edx
))
1168 (:cmpl
:edi
:eax
) ; (endp values)
1169 (:je
',no-more-values
) ; .. (go no-more-values)
1170 (:movl
(:eax -
1) :edx
)
1171 (:movl
(:eax
3) :eax
) ; (pop values)
1173 (:pushl
:edx
) ; push (car values) [[ binding value ]]
1174 (:pushl
:edi
) ; push binding scratch
1175 (:pushl
(:ebx -
1)) ; push (car symbols) [[ binding name ]]
1176 (:movl
(:ebx
3) :ebx
) ; (pop symbols)
1178 (:pushl
:esp
) ; push next tail
1181 (:popl
:eax
) ; remove extra pre-pushed tail
1183 (:locally
(:call
(:edi
,(bt:slot-offset
'movitz-run-time-context
1184 'dynamic-variable-install
))))
1185 (:locally
(:movl
:esp
(:edi
(:edi-offset dynamic-env
)))) ; install env
1187 ;; (:shll 4 :ecx) ; ecx = 16*N
1188 ;; (:leal (:esp :ecx -4) :eax) ; eax = esp + 16*N - 4
1189 (:pushl
:edx
) ; Save number of bindings.
1190 #+ignore
(:pushl
:eax
))) ; push address of first binding's tail
1192 (when (eq body-returns
:push
)
1193 `((:popl
:eax
))) ; glue :push => :eax
1194 `((:movl
(:esp
) :edx
) ; number of bindings
1195 (:movl
(:esp
(:edx
4)) :edx
) ; previous dynamic-env
1196 (:locally
(:call
(:edi
,(bt:slot-offset
'movitz-run-time-context
1197 'dynamic-variable-uninstall
))))
1198 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
1199 (:popl
:edx
) ; number of bindings
1200 (:leal
(:esp
(:edx
4)) :esp
)))))))
1202 (define-special-operator labels
(&all forward
&form form
&env env
&funobj funobj
)
1203 (destructuring-bind (labels-specs &body declarations-and-body
)
1205 (multiple-value-bind (body declarations
)
1206 (parse-declarations-and-body declarations-and-body
)
1207 (let* ((labels-env (make-local-movitz-environment env funobj
1209 :declarations declarations
))
1211 (loop for
(labels-name) in labels-specs
1212 do
(check-type labels-name symbol
)
1214 (movitz-env-add-binding labels-env
(make-instance 'function-binding
1216 :funobj
(make-instance 'movitz-funobj-pass1
)
1217 :parent-funobj funobj
))))
1219 (loop for
(labels-name labels-lambda-list . labels-dd-body
) in labels-specs
1220 as labels-binding in labels-bindings
1221 do
(multiple-value-bind (labels-body labels-declarations labels-docstring
)
1222 (parse-docstring-declarations-and-body labels-dd-body
)
1223 (declare (ignore labels-docstring
))
1224 (make-compiled-funobj-pass1 (list 'muerte.cl
::labels
1225 (movitz-funobj-name funobj
)
1229 (list* 'muerte.cl
:block
1230 (compute-function-block-name labels-name
)
1233 :funobj
(function-binding-funobj labels-binding
)))
1234 collect
`(:local-function-init
,labels-binding
))))
1235 (compiler-values-bind (&all body-values
&code body-code
)
1236 (compiler-call #'compile-implicit-progn
1240 (compiler-values (body-values)
1241 :code
(append init-code body-code
)))))))
1243 (define-special-operator catch
(&all forward
&form form
&funobj funobj
&env env
)
1244 (destructuring-bind (tag &rest forms
)
1246 (let ((catch-env (make-instance 'simple-dynamic-env
:uplink env
:funobj funobj
)))
1247 (compiler-values-bind (&all body-values
&code body-code
&returns body-returns
)
1248 (compiler-call #'compile-form
1250 :result-mode
:multiple-values
1252 :form
`(muerte.cl
:progn
,@forms
))
1253 (multiple-value-bind (stack-used code
)
1254 (make-compiled-catch-wrapper tag funobj env body-returns body-code
)
1255 (incf (stack-used catch-env
) stack-used
)
1256 (compiler-values (body-values)
1257 :returns body-returns
1258 :type
'(values &rest t
)
1261 (defun make-compiled-catch-wrapper (tag-form funobj env body-returns body-code
)
1262 (assert (member body-returns
'(:multiple-values
:non-local-exit
)))
1263 (values 4 ; stack-used, must be added to body-code's env.
1264 (with-labels (catch (label-set exit-point
))
1265 (append `((:declare-label-set
,label-set
(,exit-point
))
1266 (:locally
(:pushl
(:edi
(:edi-offset dynamic-env
)))) ; push dynamic-env
1267 (:pushl
',label-set
))
1268 (compiler-call #'compile-form
1274 `((:pushl
:ebp
) ; push stack frame
1275 (:locally
(:movl
:esp
(:edi
(:edi-offset dynamic-env
))))) ; install catch
1279 (:movl
(:esp
12) :edx
)
1280 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
1281 (:leal
(:esp
16) :esp
)
1284 (define-special-operator unwind-protect
(&all all
&form form
&env env
)
1285 (destructuring-bind (protected-form &body cleanup-forms
)
1287 (if (null cleanup-forms
)
1288 (compiler-call #'compile-form-unprotected
1290 :form protected-form
)
1291 (let* ((continuation-env (make-instance 'let-env
1293 :funobj
(movitz-environment-funobj env
)))
1294 (next-continuation-step-binding
1295 (movitz-env-add-binding continuation-env
1296 (make-instance 'located-binding
1297 :name
(gensym "up-next-continuation-step-"))))
1298 (unwind-protect-env (make-instance 'unwind-protect-env
1299 :cleanup-form
(cons 'muerte.cl
:progn cleanup-forms
)
1300 :uplink continuation-env
1301 :funobj
(movitz-environment-funobj env
))))
1302 (with-labels (unwind-protect (cleanup-label cleanup-entry continue continue-label
))
1304 :returns
:multiple-values
1306 ;; install default continuation dynamic-env..
1307 `((:locally
(:pushl
(:edi
(:edi-offset dynamic-env
))))
1308 (:declare-label-set
,cleanup-label
(,cleanup-entry
))
1309 (:declare-label-set
,continue-label
(,continue
))
1310 (:pushl
',cleanup-label
) ; jumper index
1311 (:globally
(:pushl
(:edi
(:edi-offset unwind-protect-tag
)))) ; tag
1312 (:pushl
:ebp
) ; stack-frame
1313 (:locally
(:movl
:esp
(:edi
(:edi-offset dynamic-env
))))) ; install up-env
1314 ;; Execute protected form..
1315 (compiler-call #'compile-form
1316 :env unwind-protect-env
1317 :with-stack-used t
;; XXX Not really true, is it?
1319 :result-mode
:multiple-values
1320 :form protected-form
)
1321 ;; From now on, take care not to touch current-values from protected-form.
1322 `((:locally
(:movl
:esp
(:edi
(:edi-offset raw-scratch0
))))
1324 ;; First, restore stack-frame in EBP
1326 ;; Now, modify unwind-protect dyn-env-entry to be normal continuation
1327 (:locally
(:movl
(:edi
(:edi-offset unbound-function
)) :edx
))
1328 (:movl
:edx
(:esp
4)) ; not unwind-protect-tag
1329 (:movl
',continue-label
(:esp
8)) ; new jumper index
1331 (:locally
(:pushl
(:edi
(:edi-offset raw-scratch0
))))) ; push final-continuation
1332 ;; Execute cleanup-forms.
1333 (compiler-call #'compile-form-unprotected
1335 :env continuation-env
1337 :result-mode
:multiple-values
1338 :form
`(muerte::with-cloak
(:multiple-values
)
1339 ;; Inside here we don't have to mind current-values.
1340 (muerte::with-inline-assembly
(:returns
:nothing
)
1341 ;; First, save final-continuation across cleanup-forms.
1342 (:locally
(:pushl
(:edi
(:edi-offset raw-scratch0
)))))
1344 (muerte::with-inline-assembly
(:returns
:nothing
)
1345 ;; Now, find next-continuation-step..
1346 (:popl
:eax
) ; final-continuation
1347 (:locally
(:call
(:edi
(:edi-offset dynamic-unwind-next
))))
1348 (:locally
(:bound
(:edi
(:edi-offset stack-bottom
)) :eax
))
1349 (:store-lexical
,next-continuation-step-binding
:eax
:type t
))))
1350 `((:locally
(:popl
(:edi
(:edi-offset raw-scratch0
)))) ; pop final continuation
1351 (:load-lexical
,next-continuation-step-binding
:edx
)
1352 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
1353 (:locally
(:call
(:edi
(:edi-offset dynamic-jump-next
))))
1356 (:movl
(:esp
12) :edx
)
1357 (:locally
(:movl
:edx
(:edi
(:edi-offset dynamic-env
))))
1358 (:leal
(:esp
16) :esp
)))))))))
1360 (define-special-operator if
(&all all
&form form
&env env
&result-mode result-mode
)
1361 (destructuring-bind (test-form then-form
&optional else-form
)
1363 (compiler-values-bind (&all then
)
1364 (compiler-call #'compile-form-unprotected
1367 (compiler-values-bind (&all else
)
1368 (compiler-call #'compile-form-unprotected
1371 #+ignore
(warn "p1: ~S/~S/~S, p2: ~S/~S/~S"
1372 (then :producer
) (then :final-form
) (then :modifies
)
1373 (else :producer
) (else :final-form
) (else :modifies
))
1375 ((and (eq result-mode
:ignore
)
1376 (then :functional-p
)
1377 (else :functional-p
))
1378 (compiler-call #'compile-form-unprotected
1382 ((and (valid-finals (then :final-form
) (else :final-form
))
1383 (equal (then :final-form
) (else :final-form
)))
1384 (warn "if's then and else are equal: ~S both were ~S." form
(then :final-form
))
1385 (compiler-call #'compile-form-unprotected
1387 :form
`(muerte.cl
:progn
,test-form
,then-form
)))
1390 ((and (typep (then :final-form
) 'movitz-immediate-object
)
1391 (typep (else :final-form
) 'movitz-immediate-object
))
1392 (let ((then-value (movitz-immediate-value (then :final-form
)))
1393 (else-value (movitz-immediate-value (else :final-form
)))
1394 (true-label (gensym "if-true-")))
1395 (warn "immediate if: ~S vs. ~S"
1396 then-value else-value
)
1397 (compiler-values-bind (&all test
)
1398 (compiler-call #'compile-form
1401 :result-mode
(cons :boolean-branch-on-true true-label
))
1402 (compiler-values (test)
1403 :code
(append (test :code
)
1404 (make-immediate-move then-value
:eax
)
1405 (make-immediate-move else-value
:eax
)
1408 (t (compiler-call #'compile-form-unprotected
1410 :form
`(muerte::compiled-cond
1411 (,test-form
,then-form
)
1412 (muerte.cl
::t
,else-form
)))))))))
1414 (define-special-operator the
(&all all
&form form
)
1415 (destructuring-bind (value-type sub-form
)
1417 (compiler-values-bind (&all sub-form
)
1418 (compiler-call #'compile-form-unprotected
1421 (compiler-values (sub-form)
1422 :type value-type
))))