diff --git a/src/ikarus.boot b/src/ikarus.boot index e5ad2f8..b25c3ed 100644 Binary files a/src/ikarus.boot and b/src/ikarus.boot differ diff --git a/src/libcogen1.ss b/src/libcogen1.ss index f131232..37519ec 100644 --- a/src/libcogen1.ss +++ b/src/libcogen1.ss @@ -172,6 +172,7 @@ [(jmpcall label rator arg*) (make-jmpcall label (Expr rator) (map Expr arg*))] [(appcall rator arg*) + (error 'new-cogen "appcall not supported yet") (make-appcall (Expr rator) (map Expr arg*))] [(mvcall rator k) (make-mvcall (Expr rator) (Clambda k))] @@ -197,336 +198,214 @@ ;;; (Program x)) -;;; -;;; So, what do we want to do here? -;;; 1. we eliminate all variables: -;;; bind should become a sequence of (setfv i ) statements -;;; variable refs should befome (fv i) where i is the index of -;;; the var on the stack. -;;; 2. we need to keep track of the maximum stack size used; and -;;; whether we made a procedure call so that we can insert a -;;; stack overflow check with an appropriate size check. -;;; 3. as we generate code, we need to keep track of which stack -;;; locations contain pointers so that procedure calls can -;;; set an appropriate mask. -;;; 4. primitives that allocate, as well as closures and fixes -;;; should insert an appropriate alloc-check marks as well as -;;; keep the live masks for the later generation of trap handlers -;;; 5. primcalls should also keep track of liveness information -;;; and frame size just in case the primitive needs to make a -;;; procedure call. -(define-record move (src dst)) -(define-record alloc-check (n si live)) -(define-record fvar (idx)) -(define acr '%acr) -(define-record cpvar (idx)) -(define-record cmp (op v0 v1)) -(define false-object 'false-object) - -(define (new-cogen-pass1 x) +(define (eliminate-fix x) ;;; - (define who 'new-cogen-pass-1) + (define who 'eliminate-fix) ;;; - (define (fxeven? x) - (if (fixnum? x) - ($fxzero? ($fxlogand x 1)) - (error 'fxeven? "~s is not a fixnum" x))) - ;;; - (define (sum ls) - (let f ([ls ls] [n 0]) - (cond - [(null? ls) n] - [else (f (cdr ls) (fx+ (car ls) n))]))) - ;;; - (define fxmax - (case-lambda - [(x y) (if (fx> x y) x y)] - [(x y z) (fxmax x (fxmax y z))] - [_ (error 'fxmax "unhandled")])) - ;;; - (define (do-seq e0 si live env e1 k) - (let-values ([(e0 msi0 call0?) - (Effect e0 si live env)]) - (let-values ([(e1 msi1 call1?) - (k e1 si live env)]) - (values (make-seq e0 e1) - (fxmax msi0 msi1) - (or call0? call1?))))) - ;;; - (define (do-cond e0 si live env e1 e2 k) - (let-values ([(e0 msi0 call0?) - (Pred e0 si live env)]) - (let-values ([(e1 msi1 call1?) - (k e1 si live env)] - [(e2 msi2 call2?) - (k e2 si live env)]) - (values (make-conditional e0 e1 e2) - (fxmax msi0 msi1 msi2) - (or call0? call1? call2?))))) - ;;; - (define (do-move-to-mem loc expr si live env) - (record-case expr - [(constant) - (values (make-move expr loc) 0 #f)] - [else - (let-values ([(x msi call?) - (Value expr si live env)]) - (values (make-seq x (make-move acr loc)) msi call?))])) - ;;; - (define (do-bind lhs* rhs* si live env0 env body k) - (cond - [(null? lhs*) - (k body si live env)] - [else - (let ([fv (make-fvar si)]) - (let-values ([(e0 msi0 call0?) - (do-move-to-mem fv (car rhs*) si live env0)]) - (let-values ([(e1 msi1 call1?) - (do-bind (cdr lhs*) (cdr rhs*) - (fxadd1 si) - (cons si live) - env0 - (cons (cons (car lhs*) fv) env) - body - k)]) - (values (make-seq e0 e1) - (fxmax msi0 msi1) - (or call0? call1?)))))])) - ;;; - (define (align n) - (cond - [(fxeven? n) n] - [else (fxadd1 n)])) - ;;; - (define (extend-env* lhs* si live env) - (let f ([lhs* lhs*] [si si] [live live] [env env] [nlhs* '()]) - (cond - [(null? lhs*) - (values nlhs* si live env)] - [else - (let ([fv (make-fvar si)]) - (f (cdr lhs*) (fxadd1 si) (cons si live) - (cons (cons (car lhs*) fv) env) - (cons fv nlhs*)))]))) - ;;; - (define (insert-const-alloc-check n si live rest) - (cond - [(fxzero? n) rest] - [else - (make-seq - (make-alloc-check n si live) - rest)])) - ;;; - (define (construct-closures n* lhs* nlhs* rhs* body) - (cond - [(null? lhs*) body] - [else - (make-seq 'FIXME:construct-closures body)])) - ;;; - (define (do-fix lhs* rhs* si live env body k) - (define (compute-closure-size x) - (record-case x - [(closure label free*) - (align (fxadd1 (length free*)))])) - (let ([n* (map compute-closure-size rhs*)]) - (let ([n (sum n*)]) - (let-values ([(nlhs* si live env) - (extend-env* lhs* si live env)]) - (let-values ([(x msi call?) - (k body si live env)]) - (values (insert-const-alloc-check n si live - (construct-closures n* lhs* nlhs* rhs* x)) - msi call?)))))) - ;;; - (define (constant-rep x) - 'FIXME:constant-rep) - ;;; - (define (do-closure label free* si live env) - 'FIXME:do-closure) - ;;; - (define (do-forcall x si live env) - (values 'FIXME:do-forcall si #f)) - ;;; - (define (do-tail-funcall x si live env) - (values 'FIXME:do-tail-funcall si #f)) - ;;; - (define (do-tail-appcall x si live env) - (values 'FIXME:do-tail-appcall si #f)) - ;;; - (define (do-tail-jmpcall x si live env) - (values 'FIXME:do-tail-jmpcall si #f)) - ;;; - (define (do-effect-funcall x si live env) - (values 'FIXME:do-effect-funcall si #f)) - ;;; - (define (do-effect-appcall x si live env) - (values 'FIXME:do-effect-appcall si #f)) - ;;; - (define (do-effect-jmpcall x si live env) - (values 'FIXME:do-effect-jmpcall si #f)) - ;;; - (define (do-value-funcall x si live env) - (values 'FIXME:do-value-funcall si #f)) - ;;; - (define (do-value-appcall x si live env) - (values 'FIXME:do-value-appcall si #f)) - ;;; - (define (do-value-jmpcall x si live env) - (values 'FIXME:do-value-jmpcall si #f)) - ;;; - (define (do-mvcall x si live env k) - (values 'FIXME:do-mvcall si #t)) - ;;; - (define (Var x env) - (cond - [(assq x env) => cdr] - [else (error who "unbound var ~s" x)])) - ;;; - (define (Primref x) - 'FIXME:primref) - ;;; - (define (Value x si live env) + (define (make-closure x) (record-case x - [(constant t) - (values (make-move (constant-rep t) acr) 0 #f)] - [(var) - (values (make-move (Var x env) acr) 0 #f)] - [(primref) - (values (make-move (Primref x) acr) 0 #f)] - [(bind lhs* rhs* body) - (do-bind lhs* rhs* si live env env body Value)] - [(fix lhs* rhs* body) - (do-fix lhs* rhs* si live env body Value)] - [(conditional e0 e1 e2) - (do-cond e0 si live env e1 e2 Value)] - [(seq e0 e1) (do-seq e0 si live env e1 Value)] - [(closure label free*) - (values (do-closure label free* si live env) 0 #f)] - [(forcall) (do-forcall x si live env)] - [(funcall) (do-value-funcall x si live env)] - [(jmpcall) (do-value-jmpcall x si live env)] - [(appcall) (do-value-appcall x si live env)] - [(mvcall) (do-mvcall x si live env Value)] - [else (error who "invalid value expr ~s" x)])) + [(closure code free*) + (cond + [(null? free*) x] + [else + (make-prim 'make-closure + (list code (make-constant (length free*))))])])) ;;; - (define (Pred x si live env) - (record-case x - [(constant t) - (values (if t #t #f) 0 #f)] - [(var) (values (make-cmp 'neq (Var x env) false-object) 0 #f)] - [(primref) (values #t 0 #f)] - [(bind lhs* rhs* body) - (do-bind lhs* rhs* si live env env body Pred)] - [(fix lhs* rhs* body) - (do-fix lhs* rhs* si live env body Pred)] - [(conditional e0 e1 e2) - (do-cond e0 si live env e1 e2 Pred)] - [(seq e0 e1) (do-seq e0 si live env e1 Pred)] - [(closure label free*) (values #t 0 #f)] - [(forcall) - (let-values ([(x msi call?) (Value x si live env)]) - (values (make-seq x (make-cmp 'neq acr false-object)) msi call?))] - [(funcall) - (let-values ([(x msi call?) (Value x si live env)]) - (values (make-seq x (make-cmp 'neq acr false-object)) msi call?))] - [(jmpcall) - (let-values ([(x msi call?) (Value x si live env)]) - (values (make-seq x (make-cmp 'neq acr false-object)) msi call?))] - [(appcall) - (let-values ([(x msi call?) (Value x si live env)]) - (values (make-seq x (make-cmp 'neq acr false-object)) msi call?))] - [(mvcall) (do-mvcall x si live env Pred)] - [else (error who "invalid pred expr ~s" x)])) + (define (closure-sets var x) + (record-case x + [(closure code free*) + (let f ([i 0] [free* free*]) + (cond + [(null? free*) (make-primcall 'void '())] + [else + (make-seq + (make-primcall 'closure-set! + (list var (make-constant i) (car free*))) + (f (fxadd1 i) (cdr free*)))]))])) ;;; - (define (Effect x si live env) - (record-case x - [(constant) (values 'nop 0 #f)] - [(var) (values 'nop 0 #f)] - [(primref) (values 'nop 0 #f)] - [(bind lhs* rhs* body) - (do-bind lhs* rhs* si live env env body Effect)] - [(fix lhs* rhs* body) - (do-fix lhs* rhs* si live env body Effect)] - [(conditional e0 e1 e2) - (do-cond e0 si live env e1 e2 Effect)] - [(seq e0 e1) (do-seq e0 si live env e1 Effect)] - [(closure label free*) (values 'nop 0 #f)] - [(forcall) (do-forcall x si live env)] - [(funcall) (do-effect-funcall x si live env)] - [(jmpcall) (do-effect-jmpcall x si live env)] - [(appcall) (do-effect-appcall x si live env)] - [(mvcall) (do-mvcall x si live env Tail)] - [else (error who "invalid effect expr ~s" x)])) - ;;; - (define (Tail x si live env) - (record-case x - [(constant) (values x si #f)] - [(var) (values (Var x env) si #f)] - [(primref) (values x si #f)] - [(bind lhs* rhs* body) - (do-bind lhs* rhs* si live env env body Tail)] - [(fix lhs* rhs* body) - (do-fix lhs* rhs* si live env body Tail)] - [(conditional e0 e1 e2) - (do-cond e0 si live env e1 e2 Tail)] - [(seq e0 e1) (do-seq e0 si live env e1 Tail)] - [(closure label free*) - (values (do-closure label free* si live env) si #f)] - [(forcall) - (let-values ([(x msi call?) (do-forcall x si live env)]) - (values x msi call?))] - [(funcall) (do-tail-funcall x si live env)] - [(jmpcall) (do-tail-jmpcall x si live env)] - [(appcall) (do-tail-appcall x si live env)] - [(mvcall) (do-mvcall x si live env Tail)] - [else (error who "invalid tail expr ~s" x)])) - ;;; - (define (MainTail x si live env) - (let-values ([(x msi call?) - (Tail x si live env)]) - (if call? - (make-seq 'FIXME:stack-overflow-check x) - x))) - (define (ClambdaCase free*) - (define (bind-free ls) - (let f ([ls ls] [i 0] [env '()]) + (define (do-fix lhs* rhs* body) + (make-bind lhs* + (map make-closure rhs*) + (let f ([lhs* lhs*] [rhs* rhs*]) (cond - [(null? ls) env] + [(null? lhs*) body] [else - (f (cdr ls) (fxadd1 i) - (cons (cons (car ls) (make-cpvar i)) env))]))) - (define (do-info x env) - (record-case x - [(case-info label args proper) - (let f ([ls args] [env env] [si 0] [live '()]) - (cond - [(null? ls) (values env si live)] - [else - (let ([fv (make-fvar si)]) - (f (cdr ls) - (cons (cons (car ls) fv) env) - (fxadd1 si) - (cons si live)))]))])) - (let ([env (bind-free free*)]) - (lambda (x) - (record-case x - [(clambda-case info body) - (let-values ([(env si live) (do-info info env)]) - (make-clambda-case info (MainTail body si live env)))] - [else (error who "invalid clambda-case ~s" x)])))) + (make-seq + (closure-sets (car lhs*) (car rhs*)) + (f (cdr lhs*) (cdr rhs*)))])))) + ;;; + (define (Expr x) + (record-case x + [(constant) x] + [(var) x] + [(primref) x] + [(bind lhs* rhs* body) + (make-bind lhs* (map Expr rhs*) (Expr body))] + [(fix lhs* rhs* body) + (do-fix lhs* rhs* (Expr body))] + [(conditional e0 e1 e2) + (make-conditional (Expr e0) (Expr e1) (Expr e2))] + [(seq e0 e1) + (make-seq (Expr e0) (Expr e1))] + [(closure) + (let ([t (unique-var 'tmp)]) + (Expr (make-fix (list t) (list x) t)))] + [(primcall op arg*) + (make-appcall (make-primref op) (map Expr arg*))] + [(forcall op arg*) + (make-forcall op (map Expr arg*))] + [(funcall rator arg*) + (make-funcall (Expr rator) (map Expr arg*))] + [(jmpcall label rator arg*) + (make-jmpcall label (Expr rator) (map Expr arg*))] + [(appcall rator arg*) + (error who "appcall not supported yet") + (make-appcall (Expr rator) (map Expr arg*))] + [(mvcall rator k) + (make-mvcall (Expr rator) (Clambda k))] + [else (error who "invalid expr ~s" x)])) + ;;; + (define (ClambdaCase x) + (record-case x + [(clambda-case info body) + (make-clambda-case info (Expr body))] + [else (error who "invalid clambda-case ~s" x)])) ;;; (define (Clambda x) (record-case x [(clambda label case* free*) - (make-clambda label (map (ClambdaCase free*) case*) free*)] + (make-clambda label (map ClambdaCase case*) free*)] [else (error who "invalid clambda ~s" x)])) ;;; (define (Program x) (record-case x [(codes code* body) - (make-codes (map Clambda code*) (MainTail body 0 '() '()))] + (make-codes (map Clambda code*) (Expr body))] + [else (error who "invalid program ~s" x)])) + ;;; + (Program x)) + + +(define (specify-representation x) + (define who 'specify-representation) + ;;; + (define nop (make-primcall 'nop '())) + ;;; + (define (constant-rep x) + (let ([c (constant-value x)]) + (cond + [(fixnum? c) (* c fixnum-scale)] + [(boolean? c) (if c bool-t bool-f)] + [(void? c) void-object] + [(bwp? c) bwp-object] + [(char? c) (fxlogor (fxsll (char->integer c) char-shift) + char-tag)] + [(null? c) nil] + [else x]))) + ;;; + (define (Effect x) + (record-case x + [(constant c) nop] + [(var) nop] + [(primref) nop] + [(closure code free*) nop] + [(bind lhs* rhs* body) + (make-bind lhs* (map Value rhs*) (Effect body))] + [(conditional e0 e1 e2) + (make-conditional (Pred e0) (Effect e1) (Effect e2))] + [(seq e0 e1) + (make-seq (Effect e0) (Effect e1))] + [(primcall op arg*) + (error who "effect prim ~a not supported" op)] + [(forcall op arg*) + (error who "effect forcall not supported" op)] + [(funcall rator arg*) + (make-funcall (Value rator) (map Value arg*))] + [(jmpcall label rator arg*) + (make-jmpcall label (Value rator) (map Value arg*))] + [(appcall rator arg*) + (error who "appcall not supported yet")] + [(mvcall rator x) + (make-mvcall (Value rator) (Clambda x Effect))] + [else (error who "invalid pred expr ~s" x)])) + ;;; + (define (Pred x) + (record-case x + [(constant c) (if c #t #f)] + [(var) (mkprm '!= (list x bool-f))] + [(primref) #t] + [(closure code free*) #t] + [(bind lhs* rhs* body) + (make-bind lhs* (map Value rhs*) (Pred body))] + [(conditional e0 e1 e2) + (make-conditional (Pred e0) (Pred e1) (Pred e2))] + [(seq e0 e1) + (make-seq (Effect e0) (Pred e1))] + [(primcall op arg*) + (error who "pred prim ~a not supported" op)] + [(forcall op arg*) + (error who "pred forcall not supported" op)] + [(funcall rator arg*) + (mkprm '!= + (list (make-funcall (Value rator) (map Value arg*)) + bool-f))] + [(jmpcall label rator arg*) + (mkprm '!= + (list (make-jmpcall label (Value rator) (map Value arg*)) + bool-f))] + [(appcall rator arg*) + (error who "appcall not supported yet")] + [(mvcall rator x) + (make-mvcall (Value rator) (Clambda x Pred))] + [else (error who "invalid pred expr ~s" x)])) + ;;; + (define (Value x) + (record-case x + [(constant) (constant-rep x)] + [(var) x] + [(primref) x] + [(bind lhs* rhs* body) + (make-bind lhs* (map Value rhs*) (Value body))] + [(conditional e0 e1 e2) + (make-conditional (Pred e0) (Value e1) (Value e2))] + [(seq e0 e1) + (make-seq (Effect e0) (Value e1))] + [(primcall op arg*) + (error who "value prim ~a not supported" op)] + [(forcall op arg*) + (error who "value forcall not supported" op)] + [(funcall rator arg*) + (make-funcall (Value rator) (map Value arg*))] + [(jmpcall label rator arg*) + (make-jmpcall label (Value rator) (map Value arg*))] + [(appcall rator arg*) + (error who "appcall not supported yet")] + [(mvcall rator x) + (make-mvcall (Value rator) (Clambda x Value))] + [else (error who "invalid value expr ~s" x)])) + ;;; + (define (ClambdaCase x k) + (record-case x + [(clambda-case info body) + (make-clambda-case info (k body))] + [else (error who "invalid clambda-case ~s" x)])) + ;;; + (define (Clambda x k) + (record-case x + [(clambda label case* free*) + (make-clambda label + (map (lambda (x) (ClambdaCase x k)) case*) + free*)] + [else (error who "invalid clambda ~s" x)])) + ;;; + (define (Program x) + (record-case x + [(codes code* body) + (make-codes + (map (lambda (x) (Clambda x Value)) code*) + (Value body))] [else (error who "invalid program ~s" x)])) ;;; (Program x)) @@ -534,11 +413,12 @@ - (define (new-cogen x) (verify-new-cogen-input x) - (let ([x (remove-primcalls x)]) - (new-cogen-pass1 x))) + (let* ([x (remove-primcalls x)] + [x (eliminate-fix x)] + [x (specify-representation x)]) + x)) diff --git a/src/libintelasm.ss b/src/libintelasm.ss index 83e101d..6327c95 100644 --- a/src/libintelasm.ss +++ b/src/libintelasm.ss @@ -263,7 +263,7 @@ (define label-name (lambda (x) (cadr x))) -(define int? fixnum?) +(define int? integer?) (define obj? (lambda (x) diff --git a/src/racompiler.ss b/src/racompiler.ss new file mode 100755 index 0000000..57b6ae2 --- /dev/null +++ b/src/racompiler.ss @@ -0,0 +1,153 @@ +#!/usr/bin/env ikarus --script +(define (racompile x) + ;;; + (define-syntax record-case + (lambda (x) + (define (enumerate fld* i) + (syntax-case fld* () + [() #'()] + [(x . x*) + (with-syntax ([i i] [i* (enumerate #'x* (fx+ i 1))]) + #'(i . i*))])) + (define (generate-body ctxt cls*) + (syntax-case cls* (else) + [() (with-syntax ([x x]) #'(error #f "unmatched ~s in ~s" v #'x))] + [([else b b* ...]) #'(begin b b* ...)] + [([(rec-name rec-field* ...) b b* ...] . rest) (identifier? #'rec-name) + (with-syntax ([altern (generate-body ctxt #'rest)] + [(id* ...) (enumerate #'(rec-field* ...) 0)] + [rtd #'(type-descriptor rec-name)]) + #'(if (#%$record/rtd? v rtd) + (let ([rec-field* (#%$record-ref v id*)] ...) + b b* ...) + altern))])) + (syntax-case x () + [(_ expr cls* ...) + (with-syntax ([body (generate-body #'_ #'(cls* ...))]) + #'(let ([v expr]) body))]))) + ;;; + (define-record constant (val)) + (define (mkconst v) (make-constant v)) + (define-record int (val)) + (define (mkint v) (make-int v)) + (define-record set (lhs rhs)) + (define (mkset x v) (make-set x v)) + (define-record reg (name)) + (define (mkreg x) (make-reg x)) + (define-record primcall (op rand*)) + (define (mkprm op . rand*) (make-primcall op rand*)) + (define-record seq (e0 e1)) + (define (mkseq e0 e1) (make-seq e0 e1)) + ;;; + (define (recordize x) + (define who 'recordize) + ;;; + (define (E x r) + (cond + [(pair? x) + (case (car x) + [(quote) (mkconst (cadr x))] + [else (error who "invalid expression ~s" x)])] + [else (error who "invalid expression ~s" x)])) + ;;; + (E x '())) + ;;; + (define (specify-representation x) + (define who 'specify-representation) + ;;; + (define fixnum-scale 4) + ;;; + (define (immediate? c) + (or (fixnum? c))) + ;;; + (define (immediate-rep c) + (cond + [(fixnum? c) (mkint (* c fixnum-scale))] + [else (error 'immediate-rep "invalid ~s" c)])) + ;;; + (define (Tail x) + (record-case x + [(constant c) + (if (immediate? c) + (immediate-rep c) + x)] + [else (error who "invalid tail ~s" x)])) + ;;; + (Tail x)) + ;;; + (define (impose-calling-convention x) + (define who 'impose-calling-convention) + ;;; + (define rv-register (mkreg '%eax)) + ;;; + (define (Tail x) + (record-case x + [(constant c) + (mkseq (mkset rv-register x) + (mkprm 'return rv-register))] + [else (error who "invalid tail ~s" x)])) + ;;; + (Tail x)) + ;;; + (define (linearize x) + (define who 'linearize) + ;;; + (define (op x) + (record-case x + [(register r) r] + [(constant c) `(obj ,c)] + [(int i) `(int ,i)] + ;;; + (define (Effect x ac) + (record-case x + [(seq e0 e1) + (Effect e0 (Effect e1 ac))] + [(set targ v) + (cons `(movl ,(op v) ,(op targ)) ac)] + [else (error who "invalid effect ~s" x)])) + ;;; + (define (Tail x ac) + (record-case x + [(seq e0 e1) + (Effect e0 (Tail e1 ac))] + [(primcall op rands) + (case op + [(return) + (cons '(ret) ac)] + [else (error who "invalid tail prim ~s" op)])] + [else (error who "invalid tail ~s" x)])) + ;;; + (list (Tail x '()))) + ;;; + (define (compile x) + (let* ([x (expand x)] + [x (recordize x)] + [x (specify-representation x)] + [x (impose-calling-convention x)] + [x* (linearize x)] + [code (car (#%list*->code* + (lambda (x) #f) + x*))]) + ((#%$code->closure code)))) + (compile x)) + + + +(define-syntax add-tests-with-string-output + (syntax-rules (=>) + [(_ name [expr* => str*] ...) + (begin + (printf "SECTION ~a ...\n" 'name) + (let ([str str*] + [expr 'expr*]) + (printf "testing ~s\n" expr) + (let ([r (with-output-to-string + (lambda () + (write (racompile expr)) + (newline)))]) + (unless (string=? r str) + (error #f "expected ~s, got ~s\n" str r)))) + ...)])) + +(load "tests/tests-1.1-req.scm") +