1
;;;; Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
2
;;;; Copyright (c) 1990, Giuseppe Attardi.
4
;;;; This program is free software; you can redistribute it and/or
5
;;;; modify it under the terms of the GNU Library General Public
6
;;;; License as published by the Free Software Foundation; either
7
;;;; version 2 of the License, or (at your option) any later version.
9
;;;; See file '../Copyright' for full details.
11
;;;; CMPEXIT Exit manager.
13
(in-package "COMPILER")
15
(defun unwind-bds (bds-lcl bds-bind stack-pop)
16
(declare (fixnum bds-bind))
18
(wt-nl "cl_stack_pop_n(" (car stack-pop))
19
(dolist (f (cdr stack-pop))
22
(when bds-lcl (wt-nl "bds_unwind(" bds-lcl ");"))
24
(dotimes (n bds-bind) (declare (fixnum n)) (wt-nl "bds_unwind1();"))
25
(wt-nl "bds_unwind_n(" bds-bind ");")))
27
(defun unwind-exit (loc &optional (jump-p nil)
28
&aux (bds-lcl nil) (bds-bind 0) (stack-pop nil))
29
(declare (fixnum bds-bind))
30
(when (consp *destination*)
31
(case (car *destination*)
33
(set-jump-true loc (second *destination*))
34
(when (eq loc t) (return-from unwind-exit)))
36
(set-jump-false loc (second *destination*))
37
(when (eq loc nil) (return-from unwind-exit)))))
38
(dolist (ue *unwind-exit* (baboon))
39
;; perform all unwind-exit's which precede *exit*
41
((consp ue) ; ( label# . ref-flag )| (STACK n) |(LCL n)
42
(cond ((eq (car ue) 'STACK)
43
(push (second ue) stack-pop))
45
(setq bds-lcl ue bds-bind 0))
47
;; all body forms except the last (returning) are dealt here
48
(cond ((and (consp *destination*)
49
(or (eq (car *destination*) 'JUMP-TRUE)
50
(eq (car *destination*) 'JUMP-FALSE)))
51
(unwind-bds bds-lcl bds-bind stack-pop))
52
((not (or bds-lcl (plusp bds-bind) stack-pop))
54
;; Save the value if LOC may possibly refer
55
;; to special binding.
56
((or (loc-refers-to-special loc)
57
(loc-refers-to-special *destination*))
58
(let* ((*temp* *temp*)
59
(temp (make-temp-var)))
60
(let ((*destination* temp))
61
(set-loc loc)) ; temp <- loc
62
(unwind-bds bds-lcl bds-bind stack-pop)
63
(set-loc temp))) ; *destination* <- temp
66
(unwind-bds bds-lcl bds-bind stack-pop)))
67
(when jump-p (wt-nl) (wt-go *exit*))
70
((numberp ue) (baboon)
71
(setq bds-lcl ue bds-bind 0))
73
(BDS-BIND (incf bds-bind))
75
(unless (eq *exit* 'RETURN) (baboon))
76
;; *destination* must be either RETURN or TRASH.
77
(cond ((eq loc 'VALUES)
78
;; from multiple-value-prog1 or values
79
(unwind-bds bds-lcl bds-bind stack-pop)
80
(wt-nl "return VALUES(0);"))
82
;; from multiple-value-prog1 or values
83
(unwind-bds bds-lcl bds-bind stack-pop)
84
(wt-nl "return value0;"))
86
(let* ((*destination* 'RETURN))
88
(unwind-bds bds-lcl bds-bind stack-pop)
89
(wt-nl "return value0;")))
91
((RETURN-FIXNUM RETURN-CHARACTER RETURN-LONG-FLOAT
92
RETURN-SHORT-FLOAT RETURN-OBJECT)
94
;; *destination* must be RETURN-FIXNUM
95
(setq loc (list 'COERCE-LOC
96
(getf '(RETURN-FIXNUM :fixnum
97
RETURN-CHARACTER :char
98
RETURN-LONG-FLOAT :float
99
RETURN-DOUBLE-FLOAT :double
100
RETURN-OBJECT :object)
103
(if (or bds-lcl (plusp bds-bind))
104
(let ((lcl (make-lcl-var :type (second loc))))
105
(wt-nl "{cl_fixnum " lcl "= " loc ";")
106
(unwind-bds bds-lcl bds-bind stack-pop)
107
(wt-nl "return(" lcl ");}"))
109
(wt-nl "return(" loc ");")))
112
(let ((*destination* (tmp-destination loc)))
114
(setq loc *destination*))
115
(wt-nl "frs_pop();"))
116
(TAIL-RECURSION-MARK)
117
(JUMP (setq jump-p t))
122
(defun unwind-no-exit (exit &aux (bds-lcl nil) (bds-bind 0) (stack-pop nil))
123
(declare (fixnum bds-bind))
124
(dolist (ue *unwind-exit* (baboon))
128
(unwind-bds bds-lcl bds-bind stack-pop)
130
((eq (first ue) 'STACK)
131
(push (second ue) stack-pop))))
132
((numberp ue) (setq bds-lcl ue bds-bind 0))
133
((eq ue 'BDS-BIND) (incf bds-bind))
134
((member ue '(RETURN RETURN-OBJECT RETURN-FIXNUM RETURN-CHARACTER
135
RETURN-LONG-FLOAT RETURN-SHORT-FLOAT))
137
(progn (unwind-bds bds-lcl bds-bind stack-pop)
142
((eq ue 'FRAME) (wt-nl "frs_pop();"))
143
((eq ue 'TAIL-RECURSION-MARK)
144
(if (eq exit 'TAIL-RECURSION-MARK)
145
(progn (unwind-bds bds-lcl bds-bind stack-pop)
156
;;; Tail-recursion optimization for a function F is possible only if
157
;;; 1. F receives only required parameters, and
158
;;; 2. no required parameter of F is enclosed in a closure.
160
;;; A recursive call (F e1 ... en) may be replaced by a loop only if
161
;;; 1. F is not declared as NOTINLINE,
162
;;; 2. n is equal to the number of required parameters of F,
163
;;; 3. the form is a normal function call (i.e. args are not ARGS-PUSHED),
164
;;; 4. (F e1 ... en) is not surrounded by a form that causes dynamic
165
;;; binding (such as LET, LET*, PROGV),
166
;;; 5. (F e1 ... en) is not surrounded by a form that that pushes a frame
167
;;; onto the frame-stack (such as BLOCK and TAGBODY whose tags are
168
;;; enclosed in a closure, and CATCH),
170
(defun tail-recursion-possible ()
171
(dolist (ue *unwind-exit* (baboon))
172
(cond ((eq ue 'TAIL-RECURSION-MARK) (return t))
173
((or (numberp ue) (eq ue 'BDS-BIND) (eq ue 'FRAME))
175
((or (consp ue) (eq ue 'JUMP)))
178
(defun c2try-tail-recursive-call (fun args)
179
(when (and (listp args) ;; ARGS can be also 'ARGS-PUSHED
180
*tail-recursion-info*
181
(eq fun (first *tail-recursion-info*))
183
(tail-recursion-possible)
184
(inline-possible (fun-name fun))
185
(= (length args) (length (rest *tail-recursion-info*))))
186
(let* ((*destination* 'TRASH)
187
(*exit* (next-label))
188
(*unwind-exit* (cons *exit* *unwind-exit*)))
189
(c2psetq (cdr *tail-recursion-info*) args)
191
(unwind-no-exit 'TAIL-RECURSION-MARK)
193
(cmpnote "Tail-recursive call of ~s was replaced by iteration."