Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
;;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: C -*-
;;;;
;;;; Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
;;;; Copyright (c) 1990, Giuseppe Attardi.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; See file '../../Copyright' for full details.
;;;; CMPVAR Variables.
(in-package "COMPILER")
(defun make-var (&rest args)
(let ((var (apply #'%make-var args)))
(unless (member (var-kind var) '(SPECIAL GLOBAL))
(when *current-function*
(push var (fun-local-vars *current-function*))))
var))
(defun var-referenced-in-form-list (var form-list)
(dolist (f form-list nil)
(when (var-referenced-in-form var f)
(return t))))
(defun var-changed-in-form-list (var form-list)
(dolist (f form-list nil)
(when (var-changed-in-form var f)
(return t))))
;;; FIXME! VAR-REFERENCED-IN-FORM and VAR-CHANGED-IN-FORM are too
;;; pessimistic. One should check whether the functions reading/setting the
;;; variable are actually called from the given node. The problem arises when
;;; we create a closure of a function, as in
;;;
;;; (let* ((a 1) (b #'(lambda () (incf a)))) ...)
;;;
;;; To know whether A is changed or read, we would have to track where B is
;;; actually used.
(defun var-referenced-in-form (var form)
(declare (type var var))
(if (eq (var-kind var) 'REPLACED)
(let ((loc (var-loc var)))
(when (var-p loc)
(var-referenced-in-forms loc form)))
(or (find-node-in-list form (var-read-nodes var))
(var-functions-reading var))))
(defun var-changed-in-form (var form)
(declare (type var var))
(let ((kind (var-kind var)))
(if (eq (var-kind var) 'REPLACED)
(let ((loc (var-loc var)))
(when (var-p loc)
(var-changed-in-form loc form)))
(or (find-node-in-list form (var-set-nodes var))
(if (or (eq kind 'SPECIAL) (eq kind 'GLOBAL))
(c1form-sp-change form)
(var-functions-setting var))))))
(defun add-to-read-nodes (var form)
(push form (var-read-nodes var))
(when *current-function*
(unless (eq *current-function* (var-function var))
(pushnew *current-function* (var-functions-reading var))
(pushnew var (fun-referred-vars *current-function*))))
form)
(defun add-to-set-nodes (var form)
(push form (var-set-nodes var))
(when *current-function*
(unless (eq *current-function* (var-function var))
(pushnew *current-function* (var-functions-setting var))
(pushnew var (fun-referred-vars *current-function*))))
form)
(defun add-to-set-nodes-of-var-list (var-list form)
(dolist (v var-list)
(add-to-set-nodes v form))
form)
;;; A special binding creates a var object with the kind field SPECIAL,
;;; whereas a special declaration without binding creates a var object with
;;; the kind field GLOBAL. Thus a reference to GLOBAL may need to make sure
;;; that the variable has a value.
;;; Bootstrap problem: proclaim needs this function:
(defun sch-global (name)
(dolist (var *undefined-vars* nil)
(declare (type (or null var) var))
(when (eq (var-name var) name)
(return-from sch-global var))))
;;;
;;; Check if a variable has been declared as a special variable with a global
;;; value.
(defun check-global (name)
(member name *global-vars* :test #'eq :key #'var-name))
;;;
;;; Check if the symbol has a symbol macro
;;;
(defun chk-symbol-macrolet (form)
(loop
(when (not (symbolp form))
(return form))
(let ((new-form (macroexpand-1 form *cmp-env*)))
(when (eq new-form form)
(return form))
(setf form new-form))))
(defun c1make-var (name specials ignores types ignorables dynamics)
(cmpck (not (symbolp name)) "The variable ~s is not a symbol." name)
(cmpck (constantp name) "The constant ~s is being bound." name)
(let (type)
(if (setq type (assoc name types))
(setq type (si::type-filter (cdr type)))
(setq type 'T))
(cond ((or (member name specials)
(sys:specialp name)
(check-global name))
(when (member name ignores)
(cmpwarn-style "Variable ~s declared special while explicitly ignored." name))
(setf type (or (get-sysprop name 'TYPE) 'T)))
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
(c1make-global-variable name :kind 'SPECIAL :type type))
(t
(make-var :name name :type type :loc 'OBJECT
:kind 'LEXICAL ; we rely on check-vref to fix it
:ref (if (member name ignores) -1 0)
:ignorable (if (member name ignorables) t nil)
:extent (if (member name dynamics) 'DYNAMIC nil))))))
(defun check-vref (var)
(when (eq (var-kind var) 'LEXICAL)
(when (zerop (var-ref var)) ;;; This field may be -1 (IGNORE). Beppe
(unless (var-ignorable var)
(cmpwarn-style "The variable ~s is not used." (var-name var))))
(when (not (var-ref-clb var))
;; if the variable can be stored locally, set it var-kind to its type
(setf (var-kind var)
(if (plusp (var-ref var))
(lisp-type->rep-type (var-type var))
:OBJECT)))))
(defun c1var (name)
(let ((vref (c1vref name)))
(unless (var-p vref)
;; This might be the case if there is a symbol macrolet
(return-from c1var vref))
(let ((output (make-c1form* 'VAR :type (var-type vref)
:args vref)))
(add-to-read-nodes vref output)
output)
#+nil
(add-to-read-nodes vref (make-c1form* 'VAR :type (var-type vref)
:args vref))))
(defun make-lcl-var (&key rep-type (type 'T))
(unless rep-type
(setq rep-type (if type (lisp-type->rep-type type) :object)))
(unless type
(setq type 'T))
(make-var :kind rep-type :type type :loc `(LCL ,(incf *lcl*))))
(defun make-temp-var (&optional (type 'T))
(make-var :kind :object :type type :loc `(TEMP ,(next-temp))))
;;; A variable reference (vref for short) is a list: pair
;;; ( var-object ) Beppe(ccb) ccb-reference )
(defun c1vref (name)
(multiple-value-bind (var ccb clb unw)
(cmp-env-search-var name)
(declare (ignore unw))
(cond ((null var)
(c1make-global-variable name :warn t
:type (or (get-sysprop name 'TYPE) t)))
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
((not (var-p var))
;; symbol-macrolet
(baboon))
(t
(when (minusp (var-ref var)) ; IGNORE.
(cmpwarn-style "The ignored variable ~s is used." name)
(setf (var-ref var) 0))
(when (eq (var-kind var) 'LEXICAL)
(cond (ccb (setf (var-ref-clb var) nil ; replace a previous 'CLB
(var-ref-ccb var) t
(var-kind var) 'CLOSURE
(var-loc var) 'OBJECT))
(clb (setf (var-ref-clb var) t
(var-loc var) 'OBJECT))))
(incf (var-ref var))
var))))
(defun push-vars (v)
(setf (var-index v) (length (cmp-env-variables)))
(cmp-env-register-var v))
(defun unboxed (var)
(not (eq (var-rep-type var) :object)))
(defun local (var)
(and (not (member (var-kind var) '(LEXICAL CLOSURE SPECIAL GLOBAL REPLACED)))
(var-kind var)))
(defun c2var (vref) (unwind-exit vref))
(defun c2location (loc) (unwind-exit loc))
(defun wt-var (var &aux (var-loc (var-loc var))) ; ccb
(declare (type var var))
(case (var-kind var)
(CLOSURE
(let* ((cloc (var-cloc var))
(level (car cloc))
(index (cdr cloc))
(var-fun (var-function var)))
(if var-fun
(if (eq *written-function* var-fun)
(progn
(let ((local-level (- level (fun-closure-depth var-fun))))
(wt "cenv" (1- local-level) "->lblock.var[" (1- index) "]")
)
)
(progn
(wt "closure_display->display.level[" (1- level) "]->lblock.var[" (1- index) "]")
)
)
(if *written-function*
(progn
(wt "closure_display->display.level[" (1- level) "]->lblock.var[" (1- index) "]")
)
(progn
(wt "cenv" (1- level) "->lblock.var[" (1- index) "]")
)
)
)
)
)
(LEXICAL (wt-lex var-loc))
(REPLACED (wt var-loc))
((SPECIAL GLOBAL)
(if (safe-compile)
(wt "mkcl_symbol_value(env, " var-loc ")")
(wt "MKCL_SYM_VAL(env," var-loc ")")))
(t (wt var-loc))
))
(defun var-rep-type (var)
(case (var-kind var)
((LEXICAL CLOSURE SPECIAL GLOBAL) :object)
(REPLACED (loc-representation-type (var-loc var)))
(t (var-kind var))))
(defun set-var (loc var &aux (var-loc (var-loc var))) ; ccb
(if (var-p var)
(case (var-kind var)
(CLOSURE
(wt-nl)(wt-var var)(wt "= ")
(wt-coerce-loc (var-rep-type var) loc)
(wt #\;))
(LEXICAL
(wt-nl)(wt-lex var-loc)(wt "= ")
(wt-coerce-loc (var-rep-type var) loc)
(wt #\;))
((SPECIAL GLOBAL)
;; (if (safe-compile)
;; (wt-nl "mk_cl_set(env, " var-loc ",")
(wt-nl "MKCL_SETQ(env," var-loc ",") ;; I believe this is always safe now. JCB
;; )
(wt-coerce-loc (var-rep-type var) loc)
(wt ");"))
(t
(wt-nl var-loc "= ")
(wt-coerce-loc (var-rep-type var) loc)
(wt #\;))
)
(baboon)))
(defun wt-lex (lex)
(if (consp lex)
(wt "lex" (car lex) "[" (cdr lex) "]")
(wt-lcl lex)))
;;; ----------------------------------------------------------------------
(defun c1make-global-variable (name &key (type t) (kind 'GLOBAL) (warn nil))
(let ((var (find name *global-var-objects* :key #'var-name)))
(unless var
(setf var (make-var :name name :kind kind :type type :loc (add-symbol name))))
(push var *global-var-objects*)
(when warn
(unless (or (sys:specialp name) (constantp name) (check-global name))
(undefined-variable name)
(push var *undefined-vars*)))
var))
(defun c1declare-specials (globals)
(mapc #'cmp-env-declare-special globals))
(defun register-global (name)
(unless (check-global name)
(push (c1make-global-variable name :kind 'GLOBAL
:type (or (get-sysprop name 'TYPE) 'T))
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
*global-vars*))
(values))
(defun c1setq (args)
(let ((l (length args)))
(declare (fixnum l))
(cmpck (oddp l) "SETQ requires an even number of arguments.")
(cond ((zerop l) (c1nil))
((= l 2) (c1setq1 (first args) (second args)))
(t
(do ((pairs args (cddr pairs))
(forms nil))
((endp pairs)
(make-c1form* 'PROGN
:type (c1form-type (first forms))
:args (nreverse forms)))
(push (c1setq1 (first pairs) (second pairs)) forms)
)))))
(defun c1setq1 (name form)
(cmpck (not (symbolp name)) "The variable ~s is not a symbol." name)
(cmpck (constantp name) "The constant ~s is being assigned a value." name)
(setq name (chk-symbol-macrolet name))
(unless (symbolp name)
(return-from c1setq1 (c1expr `(setf ,name ,form))))
(let* ((name1 (c1vref name))
(form1 (c1expr form))
(type (type-and (var-type name1) (c1form-primary-type form1))) ;; This type check is too weak! JCB
)
(unless type
(cmpwarn "Type mismatch between ~s and ~s." name form)
(setq type T) ;; And what is this supposed to accomplish, destroy further type-checking? JCB
)
;; Is this justified????
(add-to-set-nodes name1 (make-c1form* 'SETQ :type type :args name1 form1))))
(defun c2setq (vref form)
(let ((*destination* vref)) (c2expr* form))
(if (eq (c1form-name form) 'LOCATION)
(c2location (c1form-arg 0 form))
(unwind-exit vref))
)
(defun c1progv (args)
(check-args-number 'PROGV args 2)
(let ((symbols (c1expr (first args)))
(values (c1expr (second args)))
(forms (c1progn (cddr args))))
(make-c1form* 'PROGV :type (c1form-type forms)
:args symbols values forms)))
(defun c2progv (symbols values body
&aux (*unwind-exit* *unwind-exit*))
(let* ((*lcl* *lcl*)
(lcl (next-lcl))
(sym-loc (make-lcl-var))
(val-loc (make-lcl-var)))
(wt-nl "{mkcl_object " sym-loc "," val-loc ";")
(wt-nl "mkcl_index " lcl " = env->bds_top - env->bds_org;")
(push lcl *unwind-exit*)
(let ((*destination* sym-loc)) (c2expr* symbols))
(let ((*destination* val-loc)) (c2expr* values))
(wt-nl "while(!mkcl_endp(env, " sym-loc ")) {")
(when (safe-compile)
(wt-nl "if(mkcl_type_of(MKCL_CAR(" sym-loc "))!=mkcl_t_symbol)")
(wt-nl "mkcl_FEinvalid_variable(env, \"progv asked to bind ~s, which is not a symbol.\",MKCL_CAR(" sym-loc "));"))
(wt-nl "if(mkcl_endp(env, " val-loc "))mkcl_bds_bind(env,MKCL_CAR(" sym-loc "),MKCL_OBJNULL);")
(wt-nl "else{mkcl_bds_bind(env,MKCL_CAR(" sym-loc "),MKCL_CAR(" val-loc "));")
(wt-nl val-loc "=MKCL_CDR(" val-loc ");}")
(wt-nl sym-loc "=MKCL_CDR(" sym-loc ");}")
(c2expr body)
(wt "}")
)
)
(defun c1psetq (old-args &aux (args nil) (use-psetf nil))
(do (var (l old-args (cddr l)))
((endp l))
(declare (object l))
(setq var (car l))
(cmpck (not (symbolp var))
"The variable ~s is not a symbol." var)
(cmpck (endp (cdr l))
"No form was given for the value of ~s." var)
(setq var (chk-symbol-macrolet var))
(setq args (nconc args (list var (second l))))
(if (symbolp var)
(cmpck (constantp var)
"The constant ~s is being assigned a value." var)
(setq use-psetf t)))
(when use-psetf
(return-from c1psetq (c1expr `(psetf ,@args))))
(do ((l args (cddr l))
(vrefs '())
(forms '()))
((endp l)
(add-to-set-nodes-of-var-list
vrefs (make-c1form* 'PSETQ :type '(MEMBER NIL)
:args (reverse vrefs) (nreverse forms))))
(let* ((vref (c1vref (first l)))
(form (c1expr (second l)))
(type (type-and (var-type vref) (c1form-primary-type form)))) ;; This type check is too weak! JCB
(unless type
(cmpwarn "Type mismatch between ~s and ~s." (var-name vref) form)
(setq type T))
;; Is this justified????
#+nil(setf (c1form-type form) type)
(push vref vrefs)
(push form forms))))
(defun c2psetq (vrefs forms &aux (*lcl* *lcl*) (saves nil) (blocks 0))
;; similar to inline-args
(do ((vrefs vrefs (cdr vrefs))
(forms forms (cdr forms))
(var) (form))
((null vrefs))
(setq var (first vrefs)
form (car forms))
(if (or (var-changed-in-form-list var (rest forms))
(var-referenced-in-form-list var (rest forms)))
(case (c1form-name form)
(LOCATION (push (cons var (c1form-arg 0 form)) saves))
(otherwise
(if (local var)
(let* ((rep-type (var-rep-type var))
(rep-type-name (rep-type-name rep-type))
(temp (make-lcl-var :rep-type rep-type)))
(wt-nl "{" *volatile* rep-type-name " " temp ";")
(incf blocks)
(let ((*destination* temp)) (c2expr* form))
(push (cons var temp) saves))
(let ((*destination* (make-temp-var)))
(c2expr* form)
(push (cons var *destination*) saves)))))
(let ((*destination* var)) (c2expr* form))))
(dolist (save saves) (set-var (cdr save) (car save)))
(dotimes (i blocks) (wt "}"))
(unwind-exit nil)
)
;;; ----------------------------------------------------------------------
(put-sysprop 'VAR 'C2 'c2var)
(put-sysprop 'LOCATION 'C2 'c2location)
(put-sysprop 'SETQ 'c1special 'c1setq)
(put-sysprop 'SETQ 'C2 'c2setq)
(put-sysprop 'PROGV 'c1special 'c1progv)
(put-sysprop 'PROGV 'C2 'c2progv)
(put-sysprop 'PSETQ 'c1 'c1psetq)
(put-sysprop 'PSETQ 'C2 'c2psetq)