;;; Ikarus Scheme -- A compiler for R6RS Scheme. ;;; Copyright (C) 2006,2007,2008 Abdulaziz Ghuloum ;;; ;;; This program is free software: you can redistribute it and/or modify ;;; it under the terms of the GNU General Public License version 3 as ;;; published by the Free Software Foundation. ;;; ;;; This program is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . ;(module primops (primop? cogen-primop) ; (define (primop? x) #f) ; (define cogen-primop (lambda args (error 'cogen-primop "not yet")))) ; ;#!eof ;(define-syntax export-all-module ; (syntax-rules (define) ; [(_ M (define name* v*) ...) ; (module M (name* ...) ; (define name* v*) ...)])) ; ;(export-all-module object-representation ; (define fixnum-scale 4) ; (define fixnum-shift 2) ; (define fixnum-tag 0) ; (define fixnum-mask 3)) (module primops (primop? get-primop set-primop!) (define cookie (gensym)) (define (primop? x) (and (getprop x cookie) #t)) (define (get-primop x) (or (getprop x cookie) (error 'getprimop "not a primitive" x))) (define (set-primop! x v) (putprop x cookie v)) ) (module (specify-representation) (import primops) (define-struct PH (interruptable? p-handler p-handled? v-handler v-handled? e-handler e-handled?)) (define interrupt-handler (make-parameter (lambda () (error 'interrupt-handler "uninitialized")))) (define (interrupt) ((interrupt-handler)) (prm 'interrupt)) (define (with-interrupt-handler p x ctxt args make-interrupt-call make-no-interrupt-call k) (cond [(not (PH-interruptable? p)) (parameterize ([interrupt-handler (lambda () (error 'cogen "uninterruptable" x args ctxt))]) (k))] [else (let ([interrupted? #f]) (let ([body (parameterize ([interrupt-handler (lambda () (set! interrupted? #t))]) (k))]) (cond [(not interrupted?) body] [(eq? ctxt 'V) (let ([h (make-interrupt-call x args)]) (if (struct-case body [(primcall op) (eq? op 'interrupt)] [else #f]) (make-no-interrupt-call x args) (make-shortcut body h)))] [(eq? ctxt 'E) (let ([h (make-interrupt-call x args)]) (if (struct-case body [(primcall op) (eq? op 'interrupt)] [else #f]) (make-no-interrupt-call x args) (make-shortcut body h)))] [(eq? ctxt 'P) (let ([h (prm '!= (make-interrupt-call x args) (K bool-f))]) (if (struct-case body [(primcall op) (eq? op 'interrupt)] [else #f]) (prm '!= (make-no-interrupt-call x args) (K bool-f)) (make-shortcut body h)))] [else (error 'with-interrupt-handler "invalid context" ctxt)])))])) (define (copy-tag orig new) (struct-case orig [(known _ t) (make-known new t)] [else new])) (define (remove-tag x) (struct-case x [(known expr t) expr] [else x])) (define-syntax with-tmp (lambda (x) (syntax-case x () [(_ ([lhs* rhs*] ...) b b* ...) (with-syntax ([(n* ...) (generate-temporaries #'(lhs* ...))]) #'(let ([lhs* rhs*] ...) (let ([n* (unique-var 'lhs*)] ...) (make-bind (list n* ...) (list lhs* ...) (let ([lhs* (copy-tag lhs* n*)] ...) (seq* b b* ...))))))]))) ;;; if ctxt is V: ;;; if cogen-value, then V ;;; if cogen-pred, then (if P #f #t) ;;; if cogen-effect, then (seq E (void)) ;;; ;;; if ctxt is P: ;;; if cogen-pred, then P ;;; if cogen-value, then (!= V #f) ;;; if cogen-effect, then (seq E #t) ;;; ;;; if ctxt is E: ;;; if cogen-effect, then E ;;; if cogen-value, then (let ([tmp V]) (nop)) ;;; if cogen-pred, then (if P (nop) (nop)) (define (simplify* args k) (define (S* ls) (cond [(null? ls) (values '() '() '())] [else (let-values ([(lhs* rhs* arg*) (S* (cdr ls))]) (let ([a (car ls)]) (struct-case a [(known expr type) (struct-case expr [(constant i) ;;; erase known tag (values lhs* rhs* (cons expr arg*))] [else ;(printf "known ~s ~s\n" type expr) (let ([tmp (unique-var 'tmp)]) (values (cons tmp lhs*) (cons (V expr) rhs*) (cons (make-known tmp type) arg*)))])] [(constant i) (values lhs* rhs* (cons a arg*))] [else (let ([t (unique-var 'tmp)]) (values (cons t lhs*) (cons (V a) rhs*) (cons t arg*)))])))])) (let-values ([(lhs* rhs* args) (S* args)]) (cond [(null? lhs*) (k args)] [else (make-bind lhs* rhs* (k args))]))) ;;; (define (make-cogen-handler make-interrupt-call make-no-interrupt-call) (define (cogen-primop x ctxt args) (define (interrupt? x) (struct-case x [(primcall x) (eq? x 'interrupt)] [else #f])) (let ([p (get-primop x)]) (simplify* args (lambda (args) (with-interrupt-handler p x ctxt (map T args) make-interrupt-call make-no-interrupt-call (lambda () (case ctxt [(P) (cond [(PH-p-handled? p) (apply (PH-p-handler p) args)] [(PH-v-handled? p) (let ([e (apply (PH-v-handler p) args)]) (if (interrupt? e) e (prm '!= e (K bool-f))))] [(PH-e-handled? p) (let ([e (apply (PH-e-handler p) args)]) (if (interrupt? e) e (make-seq e (K #t))))] [else (error 'cogen-primop "not handled" x)])] [(V) (cond [(PH-v-handled? p) (apply (PH-v-handler p) args)] [(PH-p-handled? p) (let ([e (apply (PH-p-handler p) args)]) (if (interrupt? e) e (make-conditional e (K bool-t) (K bool-f))))] [(PH-e-handled? p) (let ([e (apply (PH-e-handler p) args)]) (if (interrupt? e) e (make-seq e (K void-object))))] [else (error 'cogen-primop "not handled" x)])] [(E) (cond [(PH-e-handled? p) (apply (PH-e-handler p) args)] [(PH-p-handled? p) (let ([e (apply (PH-p-handler p) args)]) (if (interrupt? e) e (make-conditional e (prm 'nop) (prm 'nop))))] [(PH-v-handled? p) (let ([e (apply (PH-v-handler p) args)]) (if (interrupt? e) e (with-tmp ([t e]) (prm 'nop))))] [else (error 'cogen-primop "not handled" x)])] [else (error 'cogen-primop "invalid context" ctxt)]))))))) cogen-primop) (module (cogen-primop cogen-debug-primop) (define (primop-interrupt-handler x) (case x [(fx+) 'error@fx+] [(fx-) 'error@fx-] [(fx*) 'error@fx*] [(add1) 'error@add1] [(sub1) 'error@sub1] [(fxadd1) 'error@fxadd1] [(fxsub1) 'error@fxsub1] [(fxarithmetic-shift-left) 'error@fxarithmetic-shift-left] [(fxarithmetic-shift-right) 'error@fxarithmetic-shift-right] [else x])) (define (make-interrupt-call op args) (make-funcall (V (make-primref (primop-interrupt-handler op))) args)) (define (make-no-interrupt-call op args) (make-funcall (V (make-primref op)) args)) (define cogen-primop (make-cogen-handler make-interrupt-call make-no-interrupt-call)) (define (cogen-debug-primop op src/loc ctxt args) (define (make-call op args) (make-funcall (V (make-primref 'debug-call)) (cons* (V src/loc) (V (make-primref op)) args))) ((make-cogen-handler make-call make-call) op ctxt args))) (define-syntax define-primop (lambda (x) (define (cogen-name stx name suffix) (datum->syntax stx (string->symbol (format "cogen-~a-~a" suffix (syntax->datum name))))) (define (generate-handler name ctxt case*) (define (filter-cases case*) (syntax-case case* () [() '()] [([(c . arg*) b b* ...] . rest) (free-identifier=? #'c ctxt) (cons #'[arg* b b* ...] (filter-cases #'rest))] [(c . rest) (filter-cases #'rest)])) (let ([case* (filter-cases case*)]) (with-syntax ([ctxt ctxt] [name name] [(case* ...) case*] [handled? (not (null? case*))]) #'[(case-lambda case* ... [args (interrupt)]) handled?]))) (syntax-case x () [(stx name int? case* ...) (with-syntax ([cogen-p (cogen-name #'stx #'name "pred")] [cogen-e (cogen-name #'stx #'name "effect")] [cogen-v (cogen-name #'stx #'name "value")] [interruptable? (syntax-case #'int? (safe unsafe) [safe #t] [unsafe #f])] [(p-handler phandled?) (generate-handler #'name #'P #'(case* ...))] [(v-handler vhandled?) (generate-handler #'name #'V #'(case* ...))] [(e-handler ehandled?) (generate-handler #'name #'E #'(case* ...))]) #'(begin (define cogen-p p-handler) (define cogen-v v-handler) (define cogen-e e-handler) (module () (set-primop! 'name (make-PH interruptable? cogen-p phandled? cogen-v vhandled? cogen-e ehandled?)))))]))) (define (handle-fix lhs* rhs* body) (define (closure-size x) (struct-case x [(closure code free*) (if (null? free*) 0 (align (+ disp-closure-data (* (length free*) wordsize))))])) (define (partition p? lhs* rhs*) (cond [(null? lhs*) (values '() '() '() '())] [else (let-values ([(a* b* c* d*) (partition p? (cdr lhs*) (cdr rhs*))] [(x y) (values (car lhs*) (car rhs*))]) (cond [(p? x y) (values (cons x a*) (cons y b*) c* d*)] [else (values a* b* (cons x c*) (cons y d*))]))])) (define (combinator? lhs rhs) (struct-case rhs [(closure code free*) (null? free*)])) (define (sum n* n) (cond [(null? n*) n] [else (sum (cdr n*) (+ n (car n*)))])) (define (adders lhs n n*) (cond [(null? n*) '()] [else (cons (prm 'int+ lhs (K n)) (adders lhs (+ n (car n*)) (cdr n*)))])) (define (build-closures lhs* rhs* body) (let ([lhs (car lhs*)] [rhs (car rhs*)] [lhs* (cdr lhs*)] [rhs* (cdr rhs*)]) (let ([n (closure-size rhs)] [n* (map closure-size rhs*)]) (make-bind (list lhs) (list (prm 'alloc (K (sum n* n)) (K closure-tag))) (make-bind lhs* (adders lhs n n*) body))))) (define (build-setters lhs* rhs* body) (define (build-setter lhs rhs body) (struct-case rhs [(closure code free*) (make-seq (prm 'mset lhs (K (- disp-closure-code closure-tag)) (V code)) (let f ([ls free*] [i (- disp-closure-data closure-tag)]) (cond [(null? ls) body] [else (make-seq (prm 'mset lhs (K i) (V (car ls))) (f (cdr ls) (+ i wordsize)))])))])) (cond [(null? lhs*) body] [else (build-setter (car lhs*) (car rhs*) (build-setters (cdr lhs*) (cdr rhs*) body))])) (let-values ([(flhs* frhs* clhs* crhs*) (partition combinator? lhs* rhs*)]) (cond [(null? clhs*) (make-bind flhs* (map V frhs*) body)] [(null? flhs*) (build-closures clhs* crhs* (build-setters clhs* crhs* body))] [else (make-bind flhs* (map V frhs*) (build-closures clhs* crhs* (build-setters clhs* crhs* body)))]))) (define (constant-rep x) (let ([c (constant-value x)]) (cond [(fx? c) (make-constant (* c fx-scale))] [(boolean? c) (make-constant (if c bool-t bool-f))] [(eq? c (void)) (make-constant void-object)] [(bwp-object? c) (make-constant bwp-object)] [(char? c) (make-constant (fxlogor char-tag (fxsll (char->integer c) char-shift)))] [(null? c) (make-constant nil)] [(eof-object? c) (make-constant eof)] [(object? c) (error 'constant-rep "double-wrap")] [else (make-constant (make-object c))]))) (define (V x) ;;; erase known values (struct-case x [(known x t) (unknown-V x)] [else (unknown-V x)])) (define (unknown-V x) (struct-case x [(constant) (constant-rep x)] [(var) x] [(primref name) (prm 'mref (K (make-object (primref->symbol name))) (K (- disp-symbol-record-value symbol-ptag)))] [(code-loc) (make-constant x)] [(closure) (make-constant x)] [(bind lhs* rhs* body) (make-bind lhs* (map V rhs*) (V body))] [(fix lhs* rhs* body) (handle-fix lhs* rhs* (V body))] [(conditional e0 e1 e2) (make-conditional (P e0) (V e1) (V e2))] [(seq e0 e1) (make-seq (E e0) (V e1))] [(primcall op arg*) (case op [(debug-call) (cogen-debug-call op 'V arg* V)] [else (cogen-primop op 'V arg*)])] [(forcall op arg*) (make-forcall op (map V arg*))] [(funcall rator arg*) (make-funcall (Function rator) (map V arg*))] [(jmpcall label rator arg*) (make-jmpcall label (V rator) (map V arg*))] [else (error 'cogen-V "invalid value expr" x)])) (define (cogen-debug-call op ctxt arg* k) (define (fail) (k (make-funcall (make-primref 'debug-call) arg*))) (assert (>= (length arg*) 2)) (let ([src/expr (car arg*)] [op (cadr arg*)] [args (cddr arg*)]) (struct-case (remove-tag op) [(primref name) (if (primop? name) (cogen-debug-primop name src/expr ctxt args) (fail))] [else (fail)]))) (define (P x) (struct-case x [(constant c) (if c (K #t) (K #f))] [(primref) (K #t)] [(code-loc) (K #t)] [(closure) (K #t)] [(bind lhs* rhs* body) (make-bind lhs* (map V rhs*) (P body))] [(conditional e0 e1 e2) (make-conditional (P e0) (P e1) (P e2))] [(seq e0 e1) (make-seq (E e0) (P e1))] [(fix lhs* rhs* body) (handle-fix lhs* rhs* (P body))] [(primcall op arg*) (case op [(debug-call) (cogen-debug-call op 'P arg* P)] [else (cogen-primop op 'P arg*)])] [(var) (prm '!= (V x) (V (K #f)))] [(funcall) (prm '!= (V x) (V (K #f)))] [(jmpcall) (prm '!= (V x) (V (K #f)))] [(forcall) (prm '!= (V x) (V (K #f)))] [(known expr type) ;;; FIXME: suboptimal (P expr)] [else (error 'cogen-P "invalid pred expr" x)])) (define (E x) (struct-case x [(constant) (nop)] [(var) (nop)] [(primref) (nop)] [(code-loc) (nop)] [(closure) (nop)] [(bind lhs* rhs* body) (make-bind lhs* (map V rhs*) (E body))] [(conditional e0 e1 e2) (make-conditional (P e0) (E e1) (E e2))] [(seq e0 e1) (make-seq (E e0) (E e1))] [(fix lhs* rhs* body) (handle-fix lhs* rhs* (E body))] [(primcall op arg*) (case op [(debug-call) (cogen-debug-call op 'E arg* E)] [else (cogen-primop op 'E arg*)])] [(forcall op arg*) (make-forcall op (map V arg*))] [(funcall rator arg*) (make-funcall (Function rator) (map V arg*))] [(jmpcall label rator arg*) (make-jmpcall label (V rator) (map V arg*))] [(known expr type) ;;; FIXME: suboptimal (E expr)] [else (error 'cogen-E "invalid effect expr" x)])) (define (Function x) (define (Function x check?) (define (nonproc x check?) (cond [check? (with-tmp ([x (V x)]) (make-shortcut (make-seq (make-conditional (tag-test x closure-mask closure-tag) (prm 'nop) (prm 'interrupt)) x) (V (make-funcall (make-primref 'error) (list (K 'apply) (K "not a procedure") x)))))] [else (V x)])) (struct-case x [(primcall op args) (cond [(and (eq? op 'top-level-value) (= (length args) 1) (let f ([x (car args)]) (struct-case x [(constant x) (and (symbol? x) x)] [(known x t) (f x)] [else #f]))) => (lambda (sym) (reset-symbol-proc! sym) (prm 'mref (T (K sym)) (K (- disp-symbol-record-proc symbol-ptag))))] [else (nonproc x check?)])] [(primref op) (V x)] [(known x t) (cond [(eq? (T:procedure? t) 'yes) ;(record-optimization 'procedure x) (Function x #f)] [else (Function x check?)])] [else (nonproc x check?)])) (Function x #t)) (define record-optimization^ (let ([h (make-eq-hashtable)]) (lambda (what expr) (let ([n (hashtable-ref h what 0)]) (hashtable-set! h what (+ n 1)) (printf "optimize ~a[~s]: ~s\n" what n (unparse expr)))))) (define-syntax record-optimization (syntax-rules () [(_ what expr) (void)])) ;;;======================================================================== ;;; (define (interrupt-unless x) (make-conditional x (prm 'nop) (interrupt))) (define (interrupt-when x) (make-conditional x (interrupt) (prm 'nop))) (define (interrupt-unless-fixnum x) (interrupt-unless (tag-test x fx-mask fx-tag))) (define (T x) (struct-case x [(var) x] [(constant i) (constant-rep x)] [(known expr type) (make-known (T expr) type)] [else (error 'cogen-T "invalid" (unparse x))])) (define (ClambdaCase x) (struct-case x [(clambda-case info body) (make-clambda-case info (V body))] [else (error 'specify-rep "invalid clambda-case" x)])) ;;; (define (Clambda x) (struct-case x [(clambda label case* cp free* name) (make-clambda label (map ClambdaCase case*) cp free* name)] [else (error 'specify-rep "invalid clambda" x)])) ;;; (define (Program x) (struct-case x [(codes code* body) (let ([code* (map Clambda code*)] [body (V body)]) (make-codes code* body))] [else (error 'specify-rep "invalid program" x)])) (define (specify-representation x) (let ([x (Program x)]) x)) (include "pass-specify-rep-primops.ss"))