1 ;;; open-coding primitive procedures
3 ;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
5 ;;;; This library is free software; you can redistribute it and/or
6 ;;;; modify it under the terms of the GNU Lesser General Public
7 ;;;; License as published by the Free Software Foundation; either
8 ;;;; version 3 of the License, or (at your option) any later version.
10 ;;;; This library is distributed in the hope that it will be useful,
11 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ;;;; Lesser General Public License for more details.
15 ;;;; You should have received a copy of the GNU Lesser General Public
16 ;;;; License along with this library; if not, write to the Free Software
17 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 (define-module (language tree-il primitives)
22 #:use-module (system base pmatch)
23 #:use-module (rnrs bytevectors)
24 #:use-module (system base syntax)
25 #:use-module (language tree-il)
26 #:use-module (srfi srfi-4)
27 #:use-module (srfi srfi-16)
28 #:export (resolve-primitives! add-interesting-primitive!
30 effect-free-primitive? effect+exception-free-primitive?
31 constructor-primitive? accessor-primitive?
32 singly-valued-primitive?))
34 (define *interesting-primitive-names*
36 call-with-values @call-with-values
37 call-with-current-continuation @call-with-current-continuation
45 + * - / 1- 1+ quotient remainder modulo
46 ash logand logior logxor
48 pair? null? list? symbol? vector? string? struct?
58 caaar caadr cadar caddr cdaar cdadr cddar cdddr
60 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
61 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
63 vector-length vector-ref vector-set!
64 variable-ref variable-set!
69 @prompt call-with-prompt @abort abort-to-prompt
72 string-length string-ref string-set!
74 struct-vtable make-struct struct-ref struct-set!
76 bytevector-u8-ref bytevector-u8-set!
77 bytevector-s8-ref bytevector-s8-set!
78 u8vector-ref u8vector-set! s8vector-ref s8vector-set!
80 bytevector-u16-ref bytevector-u16-set!
81 bytevector-u16-native-ref bytevector-u16-native-set!
82 bytevector-s16-ref bytevector-s16-set!
83 bytevector-s16-native-ref bytevector-s16-native-set!
84 u16vector-ref u16vector-set! s16vector-ref s16vector-set!
86 bytevector-u32-ref bytevector-u32-set!
87 bytevector-u32-native-ref bytevector-u32-native-set!
88 bytevector-s32-ref bytevector-s32-set!
89 bytevector-s32-native-ref bytevector-s32-native-set!
90 u32vector-ref u32vector-set! s32vector-ref s32vector-set!
92 bytevector-u64-ref bytevector-u64-set!
93 bytevector-u64-native-ref bytevector-u64-native-set!
94 bytevector-s64-ref bytevector-s64-set!
95 bytevector-s64-native-ref bytevector-s64-native-set!
96 u64vector-ref u64vector-set! s64vector-ref s64vector-set!
98 bytevector-ieee-single-ref bytevector-ieee-single-set!
99 bytevector-ieee-single-native-ref bytevector-ieee-single-native-set!
100 bytevector-ieee-double-ref bytevector-ieee-double-set!
101 bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!
102 f32vector-ref f32vector-set! f64vector-ref f64vector-set!))
104 (define (add-interesting-primitive! name)
105 (hashq-set! *interesting-primitive-vars*
106 (or (module-variable (current-module) name)
107 (error "unbound interesting primitive" name))
110 (define *interesting-primitive-vars* (make-hash-table))
112 (for-each add-interesting-primitive! *interesting-primitive-names*)
114 (define *primitive-constructors*
115 ;; Primitives that return a fresh object.
116 '(acons cons cons* list vector make-struct make-struct/no-tail
119 (define *primitive-accessors*
120 ;; Primitives that are pure, but whose result depends on the mutable
121 ;; memory pointed to by their operands.
125 struct-vtable struct-ref
127 bytevector-u8-ref bytevector-s8-ref
128 bytevector-u16-ref bytevector-u16-native-ref
129 bytevector-s16-ref bytevector-s16-native-ref
130 bytevector-u32-ref bytevector-u32-native-ref
131 bytevector-s32-ref bytevector-s32-native-ref
132 bytevector-u64-ref bytevector-u64-native-ref
133 bytevector-s64-ref bytevector-s64-native-ref
134 bytevector-ieee-single-ref bytevector-ieee-single-native-ref
135 bytevector-ieee-double-ref bytevector-ieee-double-native-ref))
137 (define *effect-free-primitives*
141 + * - / 1- 1+ quotient remainder modulo
143 pair? null? list? symbol? vector? struct? string?
144 string-length vector-length
145 ;; These all should get expanded out by expand-primitives!.
147 caaar caadr cadar caddr cdaar cdadr cddar cdddr
148 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
149 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
150 ,@*primitive-constructors*
151 ,@*primitive-accessors*))
153 ;; Like *effect-free-primitives* above, but further restricted in that they
154 ;; cannot raise exceptions.
155 (define *effect+exception-free-primitives*
159 pair? null? list? symbol? vector? struct? string?
160 acons cons cons* list vector))
162 ;; Primitives that only return one value.
163 (define *singly-valued-primitives*
167 + * - / 1- 1+ quotient remainder modulo
168 ash logand logior logxor
170 pair? null? list? symbol? vector? acons cons cons*
175 caaar caadr cadar caddr cdaar cdadr cddar cdddr
176 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
177 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
178 vector-ref vector-set!
179 variable-ref variable-set!
183 struct? struct-vtable make-struct struct-ref struct-set!
184 string-length string-ref string-set!
185 bytevector-u8-ref bytevector-u8-set!
186 bytevector-s8-ref bytevector-s8-set!
187 u8vector-ref u8vector-set! s8vector-ref s8vector-set!
188 bytevector-u16-ref bytevector-u16-set!
189 bytevector-u16-native-ref bytevector-u16-native-set!
190 bytevector-s16-ref bytevector-s16-set!
191 bytevector-s16-native-ref bytevector-s16-native-set!
192 u16vector-ref u16vector-set! s16vector-ref s16vector-set!
193 bytevector-u32-ref bytevector-u32-set!
194 bytevector-u32-native-ref bytevector-u32-native-set!
195 bytevector-s32-ref bytevector-s32-set!
196 bytevector-s32-native-ref bytevector-s32-native-set!
197 u32vector-ref u32vector-set! s32vector-ref s32vector-set!
198 bytevector-u64-ref bytevector-u64-set!
199 bytevector-u64-native-ref bytevector-u64-native-set!
200 bytevector-s64-ref bytevector-s64-set!
201 bytevector-s64-native-ref bytevector-s64-native-set!
202 u64vector-ref u64vector-set! s64vector-ref s64vector-set!
203 bytevector-ieee-single-ref bytevector-ieee-single-set!
204 bytevector-ieee-single-native-ref bytevector-ieee-single-native-set!
205 bytevector-ieee-double-ref bytevector-ieee-double-set!
206 bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!
207 f32vector-ref f32vector-set! f64vector-ref f64vector-set!))
209 (define *effect-free-primitive-table* (make-hash-table))
210 (define *effect+exceptions-free-primitive-table* (make-hash-table))
211 (define *singly-valued-primitive-table* (make-hash-table))
213 (for-each (lambda (x)
214 (hashq-set! *effect-free-primitive-table* x #t))
215 *effect-free-primitives*)
216 (for-each (lambda (x)
217 (hashq-set! *effect+exceptions-free-primitive-table* x #t))
218 *effect+exception-free-primitives*)
219 (for-each (lambda (x)
220 (hashq-set! *singly-valued-primitive-table* x #t))
221 *singly-valued-primitives*)
223 (define (constructor-primitive? prim)
224 (memq prim *primitive-constructors*))
225 (define (accessor-primitive? prim)
226 (memq prim *primitive-accessors*))
227 (define (effect-free-primitive? prim)
228 (hashq-ref *effect-free-primitive-table* prim))
229 (define (effect+exception-free-primitive? prim)
230 (hashq-ref *effect+exceptions-free-primitive-table* prim))
231 (define (singly-valued-primitive? prim)
232 (hashq-ref *singly-valued-primitive-table* prim))
234 (define (resolve-primitives! x mod)
235 (define local-definitions
238 (let collect-local-definitions ((x x))
240 ((<toplevel-define> name)
241 (hashq-set! local-definitions name #t))
243 (collect-local-definitions head)
244 (collect-local-definitions tail))
250 ((<toplevel-ref> src name)
251 (and=> (and (not (hashq-ref local-definitions name))
252 (hashq-ref *interesting-primitive-vars*
253 (module-variable mod name)))
254 (lambda (name) (make-primitive-ref src name))))
255 ((<module-ref> src mod name public?)
256 ;; for the moment, we're disabling primitive resolution for
257 ;; public refs because resolve-interface can raise errors.
258 (let ((m (and (not public?) (resolve-module mod))))
260 (and=> (hashq-ref *interesting-primitive-vars*
261 (module-variable m name))
262 (lambda (name) (make-primitive-ref src name))))))
263 ((<call> src proc args)
264 (and (primitive-ref? proc)
265 (make-primcall src (primitive-ref-name proc) args)))
271 (define *primitive-expand-table* (make-hash-table))
273 (define (expand-primitives! x)
277 ((<primcall> src name args)
278 (let ((expand (hashq-ref *primitive-expand-table* name)))
279 (and expand (apply expand src args))))
283 ;;; I actually did spend about 10 minutes trying to redo this with
284 ;;; syntax-rules. Patches appreciated.
286 (define-macro (define-primitive-expander sym . clauses)
287 (define (inline-args args)
288 (let lp ((in args) (out '()))
289 (cond ((null? in) `(list ,@(reverse out)))
290 ((symbol? in) `(cons* ,@(reverse out) ,in))
293 (cons (if (eq? (caar in) 'quote)
294 `(make-const src ,@(cdar in))
295 `(make-primcall src ',(caar in)
296 ,(inline-args (cdar in))))
299 ;; assume it's locally bound
300 (lp (cdr in) (cons (car in) out)))
301 ((self-evaluating? (car in))
302 (lp (cdr in) (cons `(make-const src ,(car in)) out)))
304 (error "what what" (car in))))))
305 (define (consequent exp)
309 ((if ,test ,then ,else)
314 `(make-primcall src ',(car exp)
315 ,(inline-args (cdr exp))))))
317 ;; assume locally bound
320 `(make-const src ,exp))
324 (else (error "bad consequent yall" exp))))
325 `(hashq-set! *primitive-expand-table*
328 ,@(let lp ((in clauses) (out '()))
330 (reverse (cons '(else #f) out))
332 (cons `((src . ,(car in))
333 ,(consequent (cadr in))) out)))))))
335 (define-primitive-expander zero? (x)
338 ;; FIXME: All the code that uses `const?' is redundant with `peval'.
340 (define-primitive-expander +
343 (x y) (if (and (const? y)
344 (let ((y (const-exp y)))
345 (and (number? y) (exact? y) (= y 1))))
348 (let ((y (const-exp y)))
349 (and (number? y) (exact? y) (= y -1))))
352 (let ((x (const-exp x)))
353 (and (number? x) (exact? x) (= x 1))))
356 (x y z . rest) (+ x (+ y z . rest)))
358 (define-primitive-expander *
361 (x y z . rest) (* x (* y z . rest)))
363 (define-primitive-expander -
365 (x y) (if (and (const? y)
366 (let ((y (const-exp y)))
367 (and (number? y) (exact? y) (= y 1))))
370 (x y z . rest) (- x (+ y z . rest)))
372 (define-primitive-expander /
374 (x y z . rest) (/ x (* y z . rest)))
376 (define-primitive-expander caar (x) (car (car x)))
377 (define-primitive-expander cadr (x) (car (cdr x)))
378 (define-primitive-expander cdar (x) (cdr (car x)))
379 (define-primitive-expander cddr (x) (cdr (cdr x)))
380 (define-primitive-expander caaar (x) (car (car (car x))))
381 (define-primitive-expander caadr (x) (car (car (cdr x))))
382 (define-primitive-expander cadar (x) (car (cdr (car x))))
383 (define-primitive-expander caddr (x) (car (cdr (cdr x))))
384 (define-primitive-expander cdaar (x) (cdr (car (car x))))
385 (define-primitive-expander cdadr (x) (cdr (car (cdr x))))
386 (define-primitive-expander cddar (x) (cdr (cdr (car x))))
387 (define-primitive-expander cdddr (x) (cdr (cdr (cdr x))))
388 (define-primitive-expander caaaar (x) (car (car (car (car x)))))
389 (define-primitive-expander caaadr (x) (car (car (car (cdr x)))))
390 (define-primitive-expander caadar (x) (car (car (cdr (car x)))))
391 (define-primitive-expander caaddr (x) (car (car (cdr (cdr x)))))
392 (define-primitive-expander cadaar (x) (car (cdr (car (car x)))))
393 (define-primitive-expander cadadr (x) (car (cdr (car (cdr x)))))
394 (define-primitive-expander caddar (x) (car (cdr (cdr (car x)))))
395 (define-primitive-expander cadddr (x) (car (cdr (cdr (cdr x)))))
396 (define-primitive-expander cdaaar (x) (cdr (car (car (car x)))))
397 (define-primitive-expander cdaadr (x) (cdr (car (car (cdr x)))))
398 (define-primitive-expander cdadar (x) (cdr (car (cdr (car x)))))
399 (define-primitive-expander cdaddr (x) (cdr (car (cdr (cdr x)))))
400 (define-primitive-expander cddaar (x) (cdr (cdr (car (car x)))))
401 (define-primitive-expander cddadr (x) (cdr (cdr (car (cdr x)))))
402 (define-primitive-expander cdddar (x) (cdr (cdr (cdr (car x)))))
403 (define-primitive-expander cddddr (x) (cdr (cdr (cdr (cdr x)))))
405 (define-primitive-expander cons*
408 (x y . rest) (cons x (cons* y . rest)))
410 (define-primitive-expander acons (x y z)
413 (define-primitive-expander apply (f a0 . args)
414 (@apply f a0 . args))
416 (define-primitive-expander call-with-values (producer consumer)
417 (@call-with-values producer consumer))
419 (define-primitive-expander call-with-current-continuation (proc)
420 (@call-with-current-continuation proc))
422 (define-primitive-expander call/cc (proc)
423 (@call-with-current-continuation proc))
425 (define-primitive-expander make-struct (vtable tail-size . args)
426 (if (and (const? tail-size)
427 (let ((n (const-exp tail-size)))
428 (and (number? n) (exact? n) (zero? n))))
429 (make-struct/no-tail vtable . args)
432 (define-primitive-expander u8vector-ref (vec i)
433 (bytevector-u8-ref vec i))
434 (define-primitive-expander u8vector-set! (vec i x)
435 (bytevector-u8-set! vec i x))
436 (define-primitive-expander s8vector-ref (vec i)
437 (bytevector-s8-ref vec i))
438 (define-primitive-expander s8vector-set! (vec i x)
439 (bytevector-s8-set! vec i x))
441 (define-primitive-expander u16vector-ref (vec i)
442 (bytevector-u16-native-ref vec (* i 2)))
443 (define-primitive-expander u16vector-set! (vec i x)
444 (bytevector-u16-native-set! vec (* i 2) x))
445 (define-primitive-expander s16vector-ref (vec i)
446 (bytevector-s16-native-ref vec (* i 2)))
447 (define-primitive-expander s16vector-set! (vec i x)
448 (bytevector-s16-native-set! vec (* i 2) x))
450 (define-primitive-expander u32vector-ref (vec i)
451 (bytevector-u32-native-ref vec (* i 4)))
452 (define-primitive-expander u32vector-set! (vec i x)
453 (bytevector-u32-native-set! vec (* i 4) x))
454 (define-primitive-expander s32vector-ref (vec i)
455 (bytevector-s32-native-ref vec (* i 4)))
456 (define-primitive-expander s32vector-set! (vec i x)
457 (bytevector-s32-native-set! vec (* i 4) x))
459 (define-primitive-expander u64vector-ref (vec i)
460 (bytevector-u64-native-ref vec (* i 8)))
461 (define-primitive-expander u64vector-set! (vec i x)
462 (bytevector-u64-native-set! vec (* i 8) x))
463 (define-primitive-expander s64vector-ref (vec i)
464 (bytevector-s64-native-ref vec (* i 8)))
465 (define-primitive-expander s64vector-set! (vec i x)
466 (bytevector-s64-native-set! vec (* i 8) x))
468 (define-primitive-expander f32vector-ref (vec i)
469 (bytevector-ieee-single-native-ref vec (* i 4)))
470 (define-primitive-expander f32vector-set! (vec i x)
471 (bytevector-ieee-single-native-set! vec (* i 4) x))
472 (define-primitive-expander f32vector-ref (vec i)
473 (bytevector-ieee-single-native-ref vec (* i 4)))
474 (define-primitive-expander f32vector-set! (vec i x)
475 (bytevector-ieee-single-native-set! vec (* i 4) x))
477 (define-primitive-expander f64vector-ref (vec i)
478 (bytevector-ieee-double-native-ref vec (* i 8)))
479 (define-primitive-expander f64vector-set! (vec i x)
480 (bytevector-ieee-double-native-set! vec (* i 8) x))
481 (define-primitive-expander f64vector-ref (vec i)
482 (bytevector-ieee-double-native-ref vec (* i 8)))
483 (define-primitive-expander f64vector-set! (vec i x)
484 (bytevector-ieee-double-native-set! vec (* i 8) x))
486 (hashq-set! *primitive-expand-table*
490 (let ((PRE (gensym " pre"))
491 (POST (gensym " post")))
499 (make-lexical-ref #f 'pre PRE)
500 (make-call #f (make-lexical-ref #f 'pre PRE) '())
502 (make-call #f (make-lexical-ref #f 'post POST) '())
503 (make-lexical-ref #f 'post POST)))))))
505 (hashq-set! *primitive-expand-table*
508 ((src fluid) (make-dynref src fluid))
511 (hashq-set! *primitive-expand-table*
514 ((src fluid exp) (make-dynset src fluid exp))
517 (hashq-set! *primitive-expand-table*
520 ((src tag exp handler)
521 (let ((args-sym (gensym)))
524 ;; If handler itself is a lambda, the inliner can do some
527 (tree-il-src handler) '() #f 'args #f '() (list args-sym)
528 (make-primcall #f 'apply
530 (make-lexical-ref #f 'args args-sym)))
534 (hashq-set! *primitive-expand-table*
537 ((src tag thunk handler)
538 ;; Sigh. Until the inliner does its job, manually inline
539 ;; (let ((h (lambda ...))) (prompt k x h))
542 (let ((args-sym (gensym)))
544 src tag (make-call #f thunk '())
545 ;; If handler itself is a lambda, the inliner can do some
548 (tree-il-src handler) '() #f 'args #f '() (list args-sym)
549 (make-primcall #f 'apply
551 (make-lexical-ref #f 'args args-sym)))
556 (hashq-set! *primitive-expand-table*
560 (make-abort src tag '() tail-args))
562 (hashq-set! *primitive-expand-table*
566 (make-abort src tag args (make-const #f '())))