1 ;;; open-coding primitive procedures
3 ;; Copyright (C) 2009, 2010, 2011, 2012, 2013, 2014, 2015 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 (ice-9 match)
24 #:use-module (rnrs bytevectors)
25 #:use-module (system base syntax)
26 #:use-module (language tree-il)
27 #:use-module (srfi srfi-4)
28 #:use-module (srfi srfi-16)
29 #:export (resolve-primitives add-interesting-primitive!
31 effect-free-primitive? effect+exception-free-primitive?
32 constructor-primitive?
33 singly-valued-primitive? equality-primitive?
37 ;; When adding to this, be sure to update *multiply-valued-primitives*
39 (define *interesting-primitive-names*
42 call-with-current-continuation
48 = < > <= >= zero? positive? negative?
49 + * - / 1- 1+ quotient remainder modulo
50 ash logand logior logxor lognot logtest logbit?
53 pair? null? list? symbol? vector? string? struct? number? char? nil?
54 bytevector? keyword? bitvector?
58 complex? real? rational? inf? nan? integer? exact? inexact? even? odd?
60 char<? char<=? char>=? char>?
62 integer->char char->integer number->string string->number
73 caaar caadr cadar caddr cdaar cdadr cddar cdddr
75 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
76 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
80 make-vector vector-length vector-ref vector-set!
81 variable? variable-ref variable-set!
84 current-module define!
86 fluid-ref fluid-set! with-fluid*
89 abort-to-prompt* abort-to-prompt
94 string-length string-ref string-set!
96 allocate-struct struct-vtable make-struct struct-ref struct-set!
100 bytevector-u8-ref bytevector-u8-set!
101 bytevector-s8-ref bytevector-s8-set!
102 u8vector-ref u8vector-set! s8vector-ref s8vector-set!
104 bytevector-u16-ref bytevector-u16-set!
105 bytevector-u16-native-ref bytevector-u16-native-set!
106 bytevector-s16-ref bytevector-s16-set!
107 bytevector-s16-native-ref bytevector-s16-native-set!
108 u16vector-ref u16vector-set! s16vector-ref s16vector-set!
110 bytevector-u32-ref bytevector-u32-set!
111 bytevector-u32-native-ref bytevector-u32-native-set!
112 bytevector-s32-ref bytevector-s32-set!
113 bytevector-s32-native-ref bytevector-s32-native-set!
114 u32vector-ref u32vector-set! s32vector-ref s32vector-set!
116 bytevector-u64-ref bytevector-u64-set!
117 bytevector-u64-native-ref bytevector-u64-native-set!
118 bytevector-s64-ref bytevector-s64-set!
119 bytevector-s64-native-ref bytevector-s64-native-set!
120 u64vector-ref u64vector-set! s64vector-ref s64vector-set!
122 bytevector-ieee-single-ref bytevector-ieee-single-set!
123 bytevector-ieee-single-native-ref bytevector-ieee-single-native-set!
124 bytevector-ieee-double-ref bytevector-ieee-double-set!
125 bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!
126 f32vector-ref f32vector-set! f64vector-ref f64vector-set!))
128 (define (add-interesting-primitive! name)
129 (hashq-set! *interesting-primitive-vars*
130 (or (module-variable (current-module) name)
131 (error "unbound interesting primitive" name))
134 (define *interesting-primitive-vars* (make-hash-table))
136 (for-each add-interesting-primitive! *interesting-primitive-names*)
138 (define *primitive-constructors*
139 ;; Primitives that return a fresh object.
140 '(acons cons cons* list vector make-vector
141 allocate-struct make-struct make-struct/no-tail
144 (define *primitive-accessors*
145 ;; Primitives that are pure, but whose result depends on the mutable
146 ;; memory pointed to by their operands.
148 ;; Note: if you add an accessor here, be sure to add a corresponding
149 ;; case in (language tree-il effects)!
155 bytevector-u8-ref bytevector-s8-ref
156 bytevector-u16-ref bytevector-u16-native-ref
157 bytevector-s16-ref bytevector-s16-native-ref
158 bytevector-u32-ref bytevector-u32-native-ref
159 bytevector-s32-ref bytevector-s32-native-ref
160 bytevector-u64-ref bytevector-u64-native-ref
161 bytevector-s64-ref bytevector-s64-native-ref
162 bytevector-ieee-single-ref bytevector-ieee-single-native-ref
163 bytevector-ieee-double-ref bytevector-ieee-double-native-ref))
165 (define *effect-free-primitives*
168 = < > <= >= zero? positive? negative?
169 ash logand logior logxor lognot logtest logbit?
170 + * - / 1- 1+ sqrt abs quotient remainder modulo
172 pair? null? nil? list?
173 symbol? variable? vector? struct? string? number? char?
174 bytevector? keyword? bitvector?
175 complex? real? rational? inf? nan? integer? exact? inexact? even? odd?
176 char<? char<=? char>=? char>?
177 integer->char char->integer number->string string->number
179 length string-length vector-length bytevector-length
180 ;; These all should get expanded out by expand-primitives.
182 caaar caadr cadar caddr cdaar cdadr cddar cdddr
183 caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
184 cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
185 ,@*primitive-constructors*
186 ,@*primitive-accessors*))
188 ;; Like *effect-free-primitives* above, but further restricted in that they
189 ;; cannot raise exceptions.
190 (define *effect+exception-free-primitives*
194 pair? null? nil? list?
195 symbol? variable? vector? struct? string? number? char?
196 bytevector? keyword? bitvector?
198 acons cons cons* list vector))
200 ;; Primitives that don't always return one value.
201 (define *multiply-valued-primitives*
204 call-with-current-continuation
209 @abort abort-to-prompt))
211 ;; Procedures that cause a nonlocal, non-resumable abort.
212 (define *bailout-primitives*
213 '(throw error scm-error))
215 ;; Negatable predicates.
216 (define *negatable-primitives*
219 ;; (< <= > >=) are not negatable because of NaNs.
223 (define *equality-primitives*
226 (define *effect-free-primitive-table* (make-hash-table))
227 (define *effect+exceptions-free-primitive-table* (make-hash-table))
228 (define *equality-primitive-table* (make-hash-table))
229 (define *multiply-valued-primitive-table* (make-hash-table))
230 (define *bailout-primitive-table* (make-hash-table))
231 (define *negatable-primitive-table* (make-hash-table))
233 (for-each (lambda (x)
234 (hashq-set! *effect-free-primitive-table* x #t))
235 *effect-free-primitives*)
236 (for-each (lambda (x)
237 (hashq-set! *effect+exceptions-free-primitive-table* x #t))
238 *effect+exception-free-primitives*)
239 (for-each (lambda (x)
240 (hashq-set! *equality-primitive-table* x #t))
241 *equality-primitives*)
242 (for-each (lambda (x)
243 (hashq-set! *multiply-valued-primitive-table* x #t))
244 *multiply-valued-primitives*)
245 (for-each (lambda (x)
246 (hashq-set! *bailout-primitive-table* x #t))
247 *bailout-primitives*)
248 (for-each (lambda (x)
249 (hashq-set! *negatable-primitive-table* (car x) (cdr x))
250 (hashq-set! *negatable-primitive-table* (cdr x) (car x)))
251 *negatable-primitives*)
253 (define (constructor-primitive? prim)
254 (memq prim *primitive-constructors*))
255 (define (effect-free-primitive? prim)
256 (hashq-ref *effect-free-primitive-table* prim))
257 (define (effect+exception-free-primitive? prim)
258 (hashq-ref *effect+exceptions-free-primitive-table* prim))
259 (define (equality-primitive? prim)
260 (hashq-ref *equality-primitive-table* prim))
261 (define (singly-valued-primitive? prim)
262 (not (hashq-ref *multiply-valued-primitive-table* prim)))
263 (define (bailout-primitive? prim)
264 (hashq-ref *bailout-primitive-table* prim))
265 (define (negate-primitive prim)
266 (hashq-ref *negatable-primitive-table* prim))
268 (define (resolve-primitives x mod)
269 (define local-definitions
272 ;; Assume that any definitions with primitive names in the root module
273 ;; have the same semantics as the primitives.
274 (unless (eq? mod the-root-module)
275 (let collect-local-definitions ((x x))
277 ((<toplevel-define> name)
278 (hashq-set! local-definitions name #t))
280 (collect-local-definitions head)
281 (collect-local-definitions tail))
288 ((<toplevel-ref> src name)
289 (and=> (and (not (hashq-ref local-definitions name))
290 (hashq-ref *interesting-primitive-vars*
291 (module-variable mod name)))
292 (lambda (name) (make-primitive-ref src name))))
293 ((<module-ref> src mod name public?)
294 ;; for the moment, we're disabling primitive resolution for
295 ;; public refs because resolve-interface can raise errors.
296 (and=> (and=> (resolve-module mod)
298 module-public-interface
301 (and=> (hashq-ref *interesting-primitive-vars*
302 (module-variable m name))
304 (make-primitive-ref src name))))))
305 ((<call> src proc args)
306 (and (primitive-ref? proc)
307 (make-primcall src (primitive-ref-name proc) args)))
314 (define *primitive-expand-table* (make-hash-table))
316 (define (expand-primitives x)
320 ((<primcall> src name args)
321 (let ((expand (hashq-ref *primitive-expand-table* name)))
322 (or (and expand (apply expand src args))
327 ;;; I actually did spend about 10 minutes trying to redo this with
328 ;;; syntax-rules. Patches appreciated.
330 (define-macro (define-primitive-expander sym . clauses)
331 (define (inline-args args)
332 (let lp ((in args) (out '()))
333 (cond ((null? in) `(list ,@(reverse out)))
334 ((symbol? in) `(cons* ,@(reverse out) ,in))
337 (cons (if (eq? (caar in) 'quote)
338 `(make-const src ,@(cdar in))
339 `(make-primcall src ',(caar in)
340 ,(inline-args (cdar in))))
343 ;; assume it's locally bound
344 (lp (cdr in) (cons (car in) out)))
345 ((self-evaluating? (car in))
346 (lp (cdr in) (cons `(make-const src ,(car in)) out)))
348 (error "what what" (car in))))))
349 (define (consequent exp)
353 ((if ,test ,then ,else)
358 `(make-primcall src ',(car exp)
359 ,(inline-args (cdr exp))))))
361 ;; assume locally bound
364 `(make-const src ,exp))
368 (else (error "bad consequent yall" exp))))
369 `(hashq-set! *primitive-expand-table*
372 ,@(let lp ((in clauses) (out '()))
374 (reverse (cons '(_ #f) out))
376 (cons `((src . ,(car in))
377 ,(consequent (cadr in)))
380 (define-primitive-expander zero? (x)
383 (define-primitive-expander positive? (x)
386 (define-primitive-expander negative? (x)
389 ;; FIXME: All the code that uses `const?' is redundant with `peval'.
391 (define-primitive-expander +
394 (x y) (if (and (const? y) (eqv? (const-exp y) 1))
396 (if (and (const? y) (eqv? (const-exp y) -1))
398 (if (and (const? x) (eqv? (const-exp x) 1))
400 (if (and (const? x) (eqv? (const-exp x) -1))
403 (x y z ... last) (+ (+ x y . z) last))
405 (define-primitive-expander *
408 (x y z ... last) (* (* x y . z) last))
410 (define-primitive-expander -
412 (x y) (if (and (const? y) (eqv? (const-exp y) 1))
415 (x y z ... last) (- (- x y . z) last))
417 (define-primitive-expander /
419 (x y z ... last) (/ (/ x y . z) last))
421 (define-primitive-expander logior
425 (x y z ... last) (logior (logior x y . z) last))
427 (define-primitive-expander logand
431 (x y z ... last) (logand (logand x y . z) last))
433 (define-primitive-expander caar (x) (car (car x)))
434 (define-primitive-expander cadr (x) (car (cdr x)))
435 (define-primitive-expander cdar (x) (cdr (car x)))
436 (define-primitive-expander cddr (x) (cdr (cdr x)))
437 (define-primitive-expander caaar (x) (car (car (car x))))
438 (define-primitive-expander caadr (x) (car (car (cdr x))))
439 (define-primitive-expander cadar (x) (car (cdr (car x))))
440 (define-primitive-expander caddr (x) (car (cdr (cdr x))))
441 (define-primitive-expander cdaar (x) (cdr (car (car x))))
442 (define-primitive-expander cdadr (x) (cdr (car (cdr x))))
443 (define-primitive-expander cddar (x) (cdr (cdr (car x))))
444 (define-primitive-expander cdddr (x) (cdr (cdr (cdr x))))
445 (define-primitive-expander caaaar (x) (car (car (car (car x)))))
446 (define-primitive-expander caaadr (x) (car (car (car (cdr x)))))
447 (define-primitive-expander caadar (x) (car (car (cdr (car x)))))
448 (define-primitive-expander caaddr (x) (car (car (cdr (cdr x)))))
449 (define-primitive-expander cadaar (x) (car (cdr (car (car x)))))
450 (define-primitive-expander cadadr (x) (car (cdr (car (cdr x)))))
451 (define-primitive-expander caddar (x) (car (cdr (cdr (car x)))))
452 (define-primitive-expander cadddr (x) (car (cdr (cdr (cdr x)))))
453 (define-primitive-expander cdaaar (x) (cdr (car (car (car x)))))
454 (define-primitive-expander cdaadr (x) (cdr (car (car (cdr x)))))
455 (define-primitive-expander cdadar (x) (cdr (car (cdr (car x)))))
456 (define-primitive-expander cdaddr (x) (cdr (car (cdr (cdr x)))))
457 (define-primitive-expander cddaar (x) (cdr (cdr (car (car x)))))
458 (define-primitive-expander cddadr (x) (cdr (cdr (car (cdr x)))))
459 (define-primitive-expander cdddar (x) (cdr (cdr (cdr (car x)))))
460 (define-primitive-expander cddddr (x) (cdr (cdr (cdr (cdr x)))))
462 (define-primitive-expander cons*
465 (x y . rest) (cons x (cons* y . rest)))
467 (define-primitive-expander acons (x y z)
470 (define-primitive-expander call/cc (proc)
471 (call-with-current-continuation proc))
473 (define-primitive-expander make-struct (vtable tail-size . args)
474 (if (and (const? tail-size)
475 (let ((n (const-exp tail-size)))
476 (and (number? n) (exact? n) (zero? n))))
477 (make-struct/no-tail vtable . args)
480 (define-primitive-expander u8vector-ref (vec i)
481 (bytevector-u8-ref vec i))
482 (define-primitive-expander u8vector-set! (vec i x)
483 (bytevector-u8-set! vec i x))
484 (define-primitive-expander s8vector-ref (vec i)
485 (bytevector-s8-ref vec i))
486 (define-primitive-expander s8vector-set! (vec i x)
487 (bytevector-s8-set! vec i x))
489 (define-primitive-expander u16vector-ref (vec i)
490 (bytevector-u16-native-ref vec (* i 2)))
491 (define-primitive-expander u16vector-set! (vec i x)
492 (bytevector-u16-native-set! vec (* i 2) x))
493 (define-primitive-expander s16vector-ref (vec i)
494 (bytevector-s16-native-ref vec (* i 2)))
495 (define-primitive-expander s16vector-set! (vec i x)
496 (bytevector-s16-native-set! vec (* i 2) x))
498 (define-primitive-expander u32vector-ref (vec i)
499 (bytevector-u32-native-ref vec (* i 4)))
500 (define-primitive-expander u32vector-set! (vec i x)
501 (bytevector-u32-native-set! vec (* i 4) x))
502 (define-primitive-expander s32vector-ref (vec i)
503 (bytevector-s32-native-ref vec (* i 4)))
504 (define-primitive-expander s32vector-set! (vec i x)
505 (bytevector-s32-native-set! vec (* i 4) x))
507 (define-primitive-expander u64vector-ref (vec i)
508 (bytevector-u64-native-ref vec (* i 8)))
509 (define-primitive-expander u64vector-set! (vec i x)
510 (bytevector-u64-native-set! vec (* i 8) x))
511 (define-primitive-expander s64vector-ref (vec i)
512 (bytevector-s64-native-ref vec (* i 8)))
513 (define-primitive-expander s64vector-set! (vec i x)
514 (bytevector-s64-native-set! vec (* i 8) x))
516 (define-primitive-expander f32vector-ref (vec i)
517 (bytevector-ieee-single-native-ref vec (* i 4)))
518 (define-primitive-expander f32vector-set! (vec i x)
519 (bytevector-ieee-single-native-set! vec (* i 4) x))
520 (define-primitive-expander f32vector-ref (vec i)
521 (bytevector-ieee-single-native-ref vec (* i 4)))
522 (define-primitive-expander f32vector-set! (vec i x)
523 (bytevector-ieee-single-native-set! vec (* i 4) x))
525 (define-primitive-expander f64vector-ref (vec i)
526 (bytevector-ieee-double-native-ref vec (* i 8)))
527 (define-primitive-expander f64vector-set! (vec i x)
528 (bytevector-ieee-double-native-set! vec (* i 8) x))
529 (define-primitive-expander f64vector-ref (vec i)
530 (bytevector-ieee-double-native-ref vec (* i 8)))
531 (define-primitive-expander f64vector-set! (vec i x)
532 (bytevector-ieee-double-native-set! vec (* i 8) x))
534 (define (chained-comparison-expander prim-name)
536 ((src) (make-const src #t))
540 (let* ((b-sym (gensym "b"))
541 (b* (make-lexical-ref src 'b b-sym)))
546 (make-conditional src
547 (make-primcall src prim-name (list a b*))
548 (make-primcall src prim-name (cons b* rest))
549 (make-const src #f)))))))
551 (for-each (lambda (prim-name)
552 (hashq-set! *primitive-expand-table* prim-name
553 (chained-comparison-expander prim-name)))
556 ;; Appropriate for use with either 'eqv?' or 'equal?'.
557 (define (maybe-simplify-to-eq prim)
559 ((src) (make-const src #t))
560 ((src a) (make-const src #t))
562 ;; Simplify cases where either A or B is constant.
563 (define (maybe-simplify a b)
565 (let ((v (const-exp a)))
566 (and (or (memq v '(#f #t () #nil))
570 (<= v most-positive-fixnum)
571 (>= v most-negative-fixnum)))
572 (make-primcall src 'eq? (list a b))))))
573 (or (maybe-simplify a b) (maybe-simplify b a)))
575 (make-conditional src (make-primcall src prim (list a b))
576 (make-primcall src prim (cons b rest))
577 (make-const src #f)))
580 (hashq-set! *primitive-expand-table* 'eqv? (maybe-simplify-to-eq 'eqv?))
581 (hashq-set! *primitive-expand-table* 'equal? (maybe-simplify-to-eq 'equal?))
583 (define (expand-chained-comparisons prim)
585 ((src) (make-const src #t))
586 ((src a) (make-const src #t))
589 (make-conditional src (make-primcall src prim (list a b))
590 (make-primcall src prim (cons b rest))
591 (make-const src #f)))
594 (for-each (lambda (prim)
595 (hashq-set! *primitive-expand-table* prim
596 (expand-chained-comparisons prim)))
599 (hashq-set! *primitive-expand-table*
602 ((src tag thunk handler)
603 (make-prompt src #f tag thunk handler))
606 (hashq-set! *primitive-expand-table*
610 (make-abort src tag '() tail-args))
612 (hashq-set! *primitive-expand-table*
616 (make-abort src tag args (make-const #f '())))