ikarus/src/libaltcogen.ss

2976 lines
98 KiB
Scheme

(module (alt-cogen)
;;; input to cogen is <Program>:
;;; <Expr> ::= (constant x)
;;; | (var)
;;; | (primref name)
;;; | (bind var* <Expr>* <Expr>)
;;; | (fix var* <FixRhs>* <Expr>)
;;; | (conditional <Expr> <Expr> <Expr>)
;;; | (seq <Expr> <Expr>)
;;; | (closure <codeloc> <var>*) ; thunk special case
;;; | (primcall op <Expr>*)
;;; | (forcall "name" <Expr>*)
;;; | (funcall <Expr> <Expr>*)
;;; | (jmpcall <label> <Expr> <Expr>*)
;;; | (mvcall <Expr> <clambda>)
;;; <codeloc> ::= (code-loc <label>)
;;; <clambda> ::= (clambda <label> <case>* <free var>*)
;;; <case> ::= (clambda-case <info> <body>)
;;; <info> ::= (clambda-info label <arg var>* proper)
;;; <Program> ::= (codes <clambda>* <Expr>)
(define (verify-new-cogen-input x)
;;;
(define who 'verify-new-cogen-input)
;;;
(define (check-gensym x)
(unless (gensym? x)
(error who "invalid gensym ~s" x)))
;;;
(define (check-label x)
(record-case x
[(code-loc label)
(check-gensym label)]
[else (error who "invalid label ~s" x)]))
;;;
(define (check-var x)
(record-case x
[(var) (void)]
[else (error who "invalid var ~s" x)]))
;;;
(define (check-closure x)
(record-case x
[(closure label free*)
(check-label label)
(for-each check-var free*)]
[else (error who "invalid closure ~s" x)]))
;;;
(define (check-jmp-target x)
(unless (or (gensym? x)
(and (pair? x)
(eq? (car x) 'symbol-code)
(symbol? (cdr x))))
(error who "invalid jmp target")))
;;;
(define (Expr x)
(record-case x
[(constant) (void)]
[(var) (void)]
[(primref) (void)]
[(bind lhs* rhs* body)
(for-each check-var lhs*)
(for-each Expr rhs*)
(Expr body)]
[(fix lhs* rhs* body)
(for-each check-var lhs*)
(for-each check-closure rhs*)
(Expr body)]
[(conditional e0 e1 e2)
(Expr e0) (Expr e1) (Expr e2)]
[(seq e0 e1)
(Expr e0) (Expr e1)]
[(closure) (check-closure x)]
[(primcall op arg*)
(for-each Expr arg*)]
[(forcall op arg*)
(for-each Expr arg*)]
[(funcall rator arg*)
(Expr rator)
(for-each Expr arg*)]
[(jmpcall label rator arg*)
(check-jmp-target label)
(Expr rator)
(for-each Expr arg*)]
[(mvcall rator k)
(Expr rator)
(Clambda k)]
[else (error who "invalid expr ~s" x)]))
;;;
(define (check-info x)
(record-case x
[(case-info label args proper)
(check-gensym label)
(for-each check-var args)]
[else (error who "invalid case-info ~s" x)]))
;;;
(define (ClambdaCase x)
(record-case x
[(clambda-case info body)
(check-info info)
(Expr body)]
[else (error who "invalid clambda-case ~s" x)]))
;;;
(define (Clambda x)
(record-case x
[(clambda label case* free*)
(for-each check-var free*)
(for-each ClambdaCase case*)
(check-gensym label)]
[else (error who "invalid clambda ~s" x)]))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(for-each Clambda code*)
(Expr body)]
[else (error who "invalid program ~s" x)]))
;;;
(Program x))
(module (must-open-code? prim-context)
(define core-prims
;;;ctxt: p=predicate v=value vt=true-value e=effect
'([pair? p]
[vector? p]
[null? p]
[bwp-object? p]
[eof-object? p]
[eof-object vt]
[$unbound-object? p]
[procedure? p]
[symbol? p]
[boolean? p]
[string? p]
[char? p]
[fixnum? p]
[string? p]
[immediate? p]
[char? p]
[eq? p]
[not pv]
[void vt]
[$fx+ vt]
[$fx- vt]
[$fx* vt]
[$fxadd1 vt]
[$fxsub1 vt]
[$fxsll vt]
[$fxsra vt]
[$fxlogand vt]
[$fxlogor vt]
[$fxlogxor vt]
[$fxlognot vt]
[$fxmodulo vt]
[$fxquotient vt]
[$fxzero? p]
[$fx> p]
[$fx>= p]
[$fx< p]
[$fx<= p]
[$fx= p]
[- v]
[+ v]
[= p]
[< p]
[<= p]
[> p]
[>= p]
[zero? p]
[$char= p]
[$char< p]
[$char<= p]
[$char> p]
[$char>= p]
[$char->fixnum vt]
[$fixnum->char vt]
[cons vt]
[list vt]
[list* pv]
[car v]
[cdr v]
[$car v]
[$cdr v]
[set-car! e]
[set-cdr! e]
[$set-car! e]
[$set-cdr! e]
[vector vt]
[$make-vector vt]
[$vector-length vt]
[vector-length vt]
[$vector-ref v]
[vector-ref v]
[vector-set! e]
[$vector-set! e]
[$make-string vt]
[$string-length vt]
[$string-ref vt]
[string-ref vt]
[$string-set! e]
[$make-symbol vt]
[$set-symbol-value! e]
[$symbol-string v]
[$symbol-unique-string v]
[$set-symbol-unique-string! e]
[$symbol-plist vt]
[$set-symbol-plist! e]
[$set-symbol-string! e]
[top-level-value v]
[$symbol-value v]
[$memq pv]
[$procedure-check v]
[$record vt]
[$record/rtd? p]
[$record-ref v]
[$record-set! e]
[$record? p]
[$record-rtd vt]
[$make-record vt]
;;; ports
[output-port? p]
[input-port? p]
[port? p]
[$make-port/input vt]
[$make-port/output vt]
[$make-port/both vt]
[$port-handler vt]
[$port-input-buffer vt]
[$port-input-index vt]
[$port-input-size vt]
[$port-output-buffer vt]
[$port-output-index vt]
[$port-output-size vt]
[$set-port-input-index! e]
[$set-port-input-size! e]
[$set-port-output-index! e]
[$set-port-output-size! e]
[$code? p]
[$code-size vt]
[$code-reloc-vector vt]
[$code-freevars vt]
[$code-ref vt]
[$code-set! e]
[$code->closure vt]
[$closure-code vt]
[$make-tcbucket vt]
[$tcbucket-key v]
[$tcbucket-val v]
[$tcbucket-next vt]
[$set-tcbucket-tconc! e]
[$set-tcbucket-val! e]
[$set-tcbucket-next! e]
[$cpref v]
[primitive-set! e]
[primitive-ref v]
[pointer-value vt]
[$fp-at-base p]
[$current-frame vt]
[$seal-frame-and-call tail]
[$frame->continuation vt]
[$forward-ptr? p]
[$make-call-with-values-procedure vt]
[$make-values-procedure vt]
[$arg-list vt]
[$interrupted? p]
[$unset-interrupted! e]
))
(define (must-open-code? x)
(and (assq x core-prims) #t))
(define (prim-context x)
(cond
[(assq x core-prims) => cadr]
[else (error 'prim-context "~s is not a core prim" x)])))
;;; the program so far includes both primcalls and funcalls to
;;; primrefs. This pass removes all primcalls. Once everything
;;; works, we need to fix all previous passes to eliminate this
;;; whole primcall business.
(define (remove-primcalls x)
;;;
(define who 'remove-primcalls)
;;;
(define (check-gensym x)
(unless (gensym? x)
(error who "invalid gensym ~s" x)))
;;;
(define (check-label x)
(record-case x
[(code-loc label)
(check-gensym label)]
[else (error who "invalid label ~s" x)]))
;;;
(define (check-var x)
(record-case x
[(var) (void)]
[else (error who "invalid var ~s" x)]))
;;;
(define (check-closure x)
(record-case x
[(closure label free*)
(check-label label)
(for-each check-var free*)]
[else (error who "invalid closure ~s" x)]))
;;;
(define (mkfuncall op arg*)
(import primops)
(record-case op
[(primref name)
(cond
[(primop? name)
(make-primcall name arg*)]
[(open-codeable? name)
(error 'chaitin-compiler "primitive ~s is not supported"
name)]
[else (make-funcall op arg*)])]
[else (make-funcall op arg*)]))
;;;
(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)
(make-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) x]
[(primcall op arg*)
(mkfuncall (make-primref op) (map Expr arg*))]
[(forcall op arg*)
(make-forcall op (map Expr arg*))]
[(funcall rator arg*)
(mkfuncall (Expr rator) (map Expr arg*))]
[(jmpcall label rator arg*)
(make-jmpcall label (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 case*) free*)]
[else (error who "invalid clambda ~s" x)]))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(make-codes (map Clambda code*) (Expr body))]
[else (error who "invalid program ~s" x)]))
;;;
(Program x))
(define (eliminate-fix x)
;;;
(define who 'eliminate-fix)
;;;
(define (Expr cpvar free*)
;;;
(define (Var x)
(let f ([free* free*] [i 0])
(cond
[(null? free*) x]
[(eq? x (car free*))
(make-primcall '$cpref (list cpvar (make-constant i)))]
[else (f (cdr free*) (fxadd1 i))])))
(define (do-fix lhs* rhs* body)
(define (handle-closure x)
(record-case x
[(closure code free*)
(make-closure code (map Var free*))]))
(make-fix lhs* (map handle-closure rhs*) body))
(define (Expr x)
(record-case x
[(constant) x]
[(var) (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-primcall 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*))]
[(mvcall rator k)
(make-mvcall (Expr rator) (Clambda k))]
[else (error who "invalid expr ~s" x)]))
Expr)
;;;
(define (ClambdaCase free*)
(lambda (x)
(record-case x
[(clambda-case info body)
(record-case info
[(case-info label args proper)
(let ([cp (unique-var 'cp)])
(make-clambda-case
(make-case-info label (cons cp args) proper)
((Expr cp free*) 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*)]
[else (error who "invalid clambda ~s" x)]))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(make-codes (map Clambda code*) ((Expr #f '()) body))]
[else (error who "invalid program ~s" x)]))
;;;
(Program x))
(define (normalize-context x)
(define who 'normalize-context)
;;;
(define nop (make-primcall 'nop '()))
;;;
(define (Predicafy x)
(make-primcall 'neq?
(list (V x) (make-constant #f))))
(define (Unpred x)
(make-conditional (P x)
(make-constant #t)
(make-constant #f)))
(define (mkif e0 e1 e2)
(record-case e0
[(constant c) (if c e1 e2)]
[(seq p0 p1)
(make-seq p0 (mkif p1 e1 e2))]
[else
(make-conditional e0 e1 e2)]))
(define (mkbind lhs* rhs* body)
(if (null? lhs*)
body
(make-bind lhs* rhs* body)))
(define (mkseq e0 e1)
(if (eq? e0 nop)
e1
(make-seq e0 e1)))
;;;
(define (P x)
(record-case x
[(constant v) (make-constant (not (not v)))]
[(primref) (make-constant #t)]
[(closure) (make-constant #t)]
[(code-loc) (make-constant #t)]
[(seq e0 e1)
(mkseq (E e0) (P e1))]
[(conditional e0 e1 e2)
(mkif (P e0) (P e1) (P e2))]
[(bind lhs* rhs* body)
(mkbind lhs* (map V rhs*) (P body))]
[(var) (Predicafy x)]
[(funcall) (Predicafy x)]
[(jmpcall) (Predicafy x)]
[(forcall) (Predicafy x)]
[(fix lhs* rhs* body)
(make-fix lhs* rhs* (P body))]
[(primcall op rands)
(case (prim-context op)
[(v) (Predicafy x)]
[(p) (make-primcall op (map V rands))]
[(vt e) (make-seq (E x) (make-constant #t))]
[(pv)
(case op
[(list*)
(case (length rands)
[(1) (P (car rands))]
[else (make-seq (E x) (make-constant #t))])]
[($memq)
(record-case (cadr rands)
[(constant ls)
(unless (list? ls) (error who "invalid call to $memq"))
(cond
[(null? ls)
(make-seq (E (car rands)) (make-constant #f))]
[else
(let ([t (unique-var 'tmp)])
(make-bind (list t) (list (V (car rands)))
(let f ([ls ls])
(cond
[(null? (cdr ls))
(make-primcall 'eq? (list t (make-constant (car ls))))]
[else
(make-conditional
(make-primcall 'eq? (list t (make-constant (car ls))))
(make-constant #t)
(f (cdr ls)))]))))])]
[else (Predicafy x)])]
[(not)
(make-conditional
(P (car rands))
(make-constant #f)
(make-constant #t))]
[else (error who "unhandled pv prim ~s" op)])]
[else (error who "invalid context for ~s" op)])]
[else (error who "invalid pred ~s" x)]))
;;;
(define (E x)
(record-case x
[(constant) nop]
[(primref) nop]
[(var) nop]
[(closure) nop]
[(code-loc) nop]
[(seq e0 e1)
(mkseq (E e0) (E e1))]
[(bind lhs* rhs* body)
(mkbind lhs* (map V rhs*) (E body))]
[(fix lhs* rhs* body)
(make-fix lhs* rhs* (E body))]
[(conditional e0 e1 e2)
(let ([e1 (E e1)] [e2 (E e2)])
(cond
[(and (eq? e1 nop) (eq? e2 nop))
(E e0)]
[else
(mkif (P e0) e1 e2)]))]
[(funcall rator rand*)
(make-funcall (V rator) (map V rand*))]
[(jmpcall label rator rand*)
(make-jmpcall label (V rator) (map V rand*))]
[(forcall op rands) (make-forcall op (map V rands))]
[(primcall op rands)
(case (prim-context op)
[(p v pv vt)
(let f ([rands rands])
(cond
[(null? rands) nop]
[else
(mkseq (f (cdr rands)) (E (car rands)))]))]
[(e) (make-primcall op (map V rands))]
[else (error who "invalid context for ~s" op)])]
[else (error who "invalid effect ~s" x)]))
;;;
(define (V x)
(record-case x
[(constant) x]
[(primref) x]
[(var) x]
[(closure) x]
[(code-loc) x]
[(seq e0 e1)
(mkseq (E e0) (V e1))]
[(conditional e0 e1 e2)
(mkif (P e0) (V e1) (V e2))]
[(bind lhs* rhs* body)
(mkbind lhs* (map V rhs*) (V body))]
[(fix lhs* rhs* body)
(make-fix lhs* rhs* (V body))]
[(funcall rator rand*)
(make-funcall (V rator) (map V rand*))]
[(jmpcall label rator rand*)
(make-jmpcall label (V rator) (map V rand*))]
[(forcall op rands) (make-forcall op (map V rands))]
[(primcall op rands)
(case (prim-context op)
[(v vt tail) (make-primcall op (map V rands))]
[(p) (Unpred x)]
[(e) (make-seq (E x) (make-constant (void)))]
[(pv)
(case op
[($memq)
(record-case (cadr rands)
[(constant ls)
(unless (list? ls) (error who "invalid call to $memq"))
(cond
[(null? ls)
(make-seq (E (car rands)) (make-constant #f))]
[else
(let ([t (unique-var 'tmp)])
(make-bind (list t) (list (V (car rands)))
(let f ([ls ls])
(cond
[(null? ls)
(make-constant #f)]
[else
(make-conditional
(make-primcall 'eq? (list t (make-constant (car ls))))
(make-constant ls)
(f (cdr ls)))]))))])]
[else (make-funcall (make-primref '$memq) (map V rands))])]
[(list*)
(case (length rands)
[(0) (make-funcall (make-primref 'list*) '())]
[(1) (V (car rands))]
[else (make-primcall 'list* (map V rands))])]
[(not)
(make-conditional
(P (car rands))
(make-constant #f)
(make-constant #t))]
[else (error who "unhandled pv ~s" op)])]
[else (error who "invalid context for ~s" op)])]
[else (error who "invalid value ~s" x)]))
;;;
(define (ClambdaCase x)
(record-case x
[(clambda-case info body)
(make-clambda-case info (V body))]
[else (error who "invalid clambda-case ~s" x)]))
;;;
(define (Clambda x)
(record-case x
[(clambda label 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*)
(V body))]
[else (error who "invalid program ~s" x)]))
;;;
(Program x))
(define (remove-complex-operands x)
(define who 'remove-complex-operands)
(define (mkbind lhs* rhs* body)
(if (null? lhs*) body (make-bind lhs* rhs* body)))
(define (simplify* arg* op)
(define (partition arg*)
(if (null? arg*)
(values '() '() '())
(let ([a (car arg*)])
(let-values ([(lhs* rhs* arg*) (partition (cdr arg*))])
(record-case a
[(constant) (values lhs* rhs* (cons a arg*))]
[(var) (values lhs* rhs* (cons a arg*))]
[(code-loc) (values lhs* rhs* (cons a arg*))]
[(closure) (values lhs* rhs* (cons a arg*))]
[else
(let ([t (unique-var 'tmp)])
(values (cons t lhs*)
(cons a rhs*)
(cons t arg*)))])))))
(let ([arg* (map V arg*)])
(let-values ([(lhs* rhs* arg*) (partition arg*)])
(mkbind lhs* rhs* (make-primcall op arg*)))))
(define (E x)
(record-case x
[(bind lhs* rhs* body)
(mkbind lhs* (map V rhs*) (E body))]
[(fix lhs* rhs* body)
(make-fix lhs* rhs* (E body))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (E e1) (E e2))]
[(seq e0 e1)
(make-seq (E e0) (E e1))]
[(primcall op arg*) (simplify* arg* op)]
[(forcall op arg*)
(make-forcall op (map V arg*))]
[(funcall rator arg*)
(make-funcall (V rator) (map V arg*))]
[(jmpcall label rator arg*)
(make-jmpcall label (V rator) (map V arg*))]
[else (error who "invalid effect expr ~s" x)]))
(define (P x)
(record-case x
[(constant) x]
[(bind lhs* rhs* body)
(mkbind lhs* (map V rhs*) (P body))]
[(fix lhs* rhs* body)
(make-fix lhs* rhs* (P body))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (P e1) (P e2))]
[(seq e0 e1)
(make-seq (E e0) (P e1))]
[(primcall op arg*) (simplify* arg* op)]
[else (error who "invalid pred expr ~s" x)]))
(define (V x)
(record-case x
[(constant) x]
[(var) x]
[(primref name) x]
[(code-loc) x]
[(closure) x]
[(bind lhs* rhs* body)
(mkbind lhs* (map V rhs*) (V body))]
[(fix lhs* rhs* body)
(make-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*) (simplify* arg* op)]
[(forcall op arg*)
(make-forcall op (map V arg*))]
[(funcall rator arg*)
(make-funcall (V rator) (map V arg*))]
[(jmpcall label rator arg*)
(make-jmpcall label (V rator) (map V arg*))]
[else (error who "invalid value expr ~s" x)]))
(define (ClambdaCase x)
(record-case x
[(clambda-case info body)
(make-clambda-case info (V body))]
[else (error who "invalid clambda-case ~s" x)]))
;;;
(define (Clambda x)
(record-case x
[(clambda label 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*)
(V body))]
[else (error who "invalid program ~s" x)]))
(Program x))
(define-syntax seq*
(syntax-rules ()
[(_ e) e]
[(_ e* ... e)
(make-seq (seq* e* ...) e)]))
(include "pass-specify-rep.ss")
(define parameter-registers '(%edi))
(define return-value-register '%eax)
(define cp-register '%edi)
(define all-registers '(%eax %edi %ebx %edx))
(define argc-register '%eax)
(define non-8bit-registers '(%edi))
(define (impose-calling-convention/evaluation-order x)
(define who 'impose-calling-convention/evaluation-order)
;;;
(define-syntax car
(syntax-rules ()
[(_ x)
(let ([t x])
(if (pair? t)
(#%car t)
(error 'car "not a pair ~s in ~s" t '(car x))))]))
;;;
(define (S* x* k)
(cond
[(null? x*) (k '())]
[else
(S (car x*)
(lambda (a)
(S* (cdr x*)
(lambda (d)
(k (cons a d))))))]))
;;;
(define (S x k)
(record-case x
[(bind lhs* rhs* body)
(do-bind lhs* rhs* (S body k))]
[(seq e0 e1)
(make-seq (E e0) (S e1 k))]
[else
(cond
[(or (constant? x) (var? x) (symbol? x)) (k x)]
[(or (funcall? x) (primcall? x) (jmpcall? x)
(forcall? x) (shortcut? x)
(conditional? x))
(let ([t (unique-var 'tmp)])
(do-bind (list t) (list x)
(k t)))]
[else (error who "invalid S ~s" x)])]))
;;;
(define (do-bind lhs* rhs* body)
(cond
[(null? lhs*) body]
[else
(set! locals (cons (car lhs*) locals))
(make-seq
(V (car lhs*) (car rhs*))
(do-bind (cdr lhs*) (cdr rhs*) body))]))
;;;
(define (nontail-locations args)
(let f ([regs parameter-registers] [args args])
(cond
[(null? args) (values '() '() '())]
[(null? regs) (values '() '() args)]
[else
(let-values ([(r* rl* f*) (f (cdr regs) (cdr args))])
(values (cons (car regs) r*)
(cons (car args) rl*)
f*))])))
(define (make-set lhs rhs)
(make-asm-instr 'move lhs rhs))
(define (do-bind-frmt* nf* v* ac)
(cond
[(null? nf*) ac]
[else
(make-seq
(V (car nf*) (car v*))
(do-bind-frmt* (cdr nf*) (cdr v*) ac))]))
;;;
(define (handle-nontail-call rator rands value-dest call-targ)
(let-values ([(reg-locs reg-args frm-args)
(nontail-locations (cons rator rands))])
(let ([regt* (map (lambda (x) (unique-var 'rt)) reg-args)]
[frmt* (map (lambda (x) (make-nfv 'unset-conflicts #f #f #f #f))
frm-args)])
(let* ([call
(make-ntcall call-targ value-dest
(list* argc-register
pcr esp apr
(append reg-locs frmt*))
#f #f)]
[body
(make-nframe frmt* #f
(do-bind-frmt* frmt* frm-args
(do-bind (cdr regt*) (cdr reg-args)
;;; evaluate cpt last
(do-bind (list (car regt*)) (list (car reg-args))
(assign* reg-locs regt*
(make-seq
(make-set argc-register
(make-constant
(argc-convention (length rands))))
call))))))])
(if value-dest
(make-seq body (make-set value-dest return-value-register))
body)))))
(define (alloc-check size)
(E (make-conditional ;;; PCB ALLOC-REDLINE
(make-primcall '<=
(list (make-primcall 'int+ (list apr size))
(make-primcall 'mref (list pcr (make-constant 4)))))
(make-primcall 'nop '())
(make-funcall
(make-primcall 'mref
(list (make-constant (make-object 'do-overflow))
(make-constant (- disp-symbol-system-value
symbol-tag))))
(list size)))))
;;; impose value
(define (V d x)
(record-case x
[(constant) (make-set d x)]
[(var) (make-set d x)]
[(bind lhs* rhs* e)
(do-bind lhs* rhs* (V d e))]
[(seq e0 e1)
(make-seq (E e0) (V d e1))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (V d e1) (V d e2))]
[(primcall op rands)
(case op
[(alloc)
(unless (pair? rands) (error 'car "h1"))
(S (car rands)
(lambda (size)
(make-seq
(alloc-check size)
(S (cadr rands)
(lambda (tag)
(make-seq
(make-seq
(make-set d apr)
(make-asm-instr 'logor d tag))
(make-asm-instr 'int+ apr size)))))))]
[(mref)
(S* rands
(lambda (rands)
(unless (pair? rands) (error 'car "h2"))
(make-set d (make-disp (car rands) (cadr rands)))))]
[(logand logxor logor int+ int- int*
int-/overflow int+/overflow int*/overflow)
(unless (pair? rands) (error 'car "h3"))
(make-seq
(V d (car rands))
(S (cadr rands)
(lambda (s)
(make-asm-instr op d s))))]
[(remainder)
(S* rands
(lambda (rands)
(unless (pair? rands) (error 'car "h4"))
(seq*
(make-set eax (car rands))
(make-asm-instr 'cltd edx eax)
(make-asm-instr 'idiv eax (cadr rands))
(make-set d eax))))]
[(quotient)
(S* rands
(lambda (rands)
(unless (pair? rands) (error 'car "h5"))
(seq*
(make-set eax (car rands))
(make-asm-instr 'cltd edx eax)
(make-asm-instr 'idiv edx (cadr rands))
(make-set d edx))))]
[(sll sra srl)
(unless (pair? rands) (error 'car "h6 ~s" x))
(let ([a (car rands)] [b (cadr rands)])
(cond
[(constant? b)
(make-seq
(V d a)
(make-asm-instr op d b))]
[else
(S b
(lambda (b)
(seq*
(V d a)
(make-set ecx b)
(make-asm-instr op d ecx))))]))]
[else (error who "invalid value op ~s" op)])]
[(funcall rator rands)
(handle-nontail-call rator rands d #f)]
[(jmpcall label rator rands)
(handle-nontail-call rator rands d label)]
[(forcall op rands)
(handle-nontail-call
(make-constant (make-foreign-label op))
rands d op)]
[(shortcut body handler)
(make-shortcut
(V d body)
(V d handler))]
[else
(if (symbol? x)
(make-set d x)
(error who "invalid value ~s" (unparse x)))]))
;;;
(define (assign* lhs* rhs* ac)
(cond
[(null? lhs*) ac]
[else
(make-seq
(make-set (car lhs*) (car rhs*))
(assign* (cdr lhs*) (cdr rhs*) ac))]))
;;;
(define (VT x)
(S x
(lambda (x)
(make-seq
(make-set return-value-register x)
(make-primcall 'return (list return-value-register))))))
;;; impose effect
(define (E x)
(record-case x
[(seq e0 e1) (make-seq (E e0) (E e1))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (E e1) (E e2))]
[(bind lhs* rhs* e)
(do-bind lhs* rhs* (E e))]
[(primcall op rands)
(case op
[(mset bset/c bset/h)
(S* rands
(lambda (s*)
(make-asm-instr op
(make-disp (car s*) (cadr s*))
(caddr s*))))]
[(nop interrupt) x]
[else (error 'impose-effect "invalid instr ~s" x)])]
[(funcall rator rands)
(handle-nontail-call rator rands #f #f)]
[(jmpcall label rator rands)
(handle-nontail-call rator rands #f label)]
[(forcall op rands)
(handle-nontail-call
(make-constant (make-foreign-label op))
rands #f op)]
[(shortcut body handler)
(make-shortcut (E body) (E handler))]
[else (error who "invalid effect ~s" x)]))
;;; impose pred
(define (P x)
(record-case x
[(constant) x]
[(seq e0 e1) (make-seq (E e0) (P e1))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (P e1) (P e2))]
[(bind lhs* rhs* e)
(do-bind lhs* rhs* (P e))]
[(primcall op rands)
(unless (pair? rands) (error 'car "ha ~s" x))
(let ([a (car rands)] [b (cadr rands)])
(cond
[(and (constant? a) (constant? b))
(let ([t (unique-var 'tmp)])
(P (make-bind (list t) (list a)
(make-primcall op (list t b)))))]
[else
(S* rands
(lambda (rands)
(let ([a (car rands)] [b (cadr rands)])
(make-asm-instr op a b))))]))]
[(shortcut body handler)
(make-shortcut (P body) (P handler))]
[else (error who "invalid pred ~s" x)]))
;;;
(define (Tail env)
(define (handle-tail-call target rator rands)
(let* ([args (cons rator rands)]
[locs (formals-locations args)]
[rest
(make-seq
(make-set argc-register
(make-constant
(argc-convention (length rands))))
(cond
[target
(make-primcall 'direct-jump
(cons target
(list* argc-register
pcr esp apr
locs)))]
[else
(make-primcall 'indirect-jump
(list* argc-register
pcr esp apr
locs))]))])
(let f ([args (reverse args)]
[locs (reverse locs)]
[targs '()]
[tlocs '()])
(cond
[(null? args) (assign* tlocs targs rest)]
[(constant? (car args))
(f (cdr args) (cdr locs)
(cons (car args) targs)
(cons (car locs) tlocs))]
[(and (fvar? (car locs))
(cond
[(and (var? (car args)) (assq (car args) env))
=> (lambda (p) (eq? (cdr p) (car locs)))]
[else #f]))
(f (cdr args) (cdr locs) targs tlocs)]
[else
(let ([t (unique-var 'tmp)])
(set! locals (cons t locals))
(make-seq
(V t (car args))
(f (cdr args) (cdr locs)
(cons t targs) (cons (car locs) tlocs))))]))))
(define (Tail x)
(record-case x
[(constant) (VT x)]
[(var) (VT x)]
[(primcall op rands)
(case op
[($call-with-underflow-handler)
(unless (pair? rands) (error 'car "h6"))
(let ([handler (car rands)]
[proc (cadr rands)]
[k (caddr rands)])
(seq*
(make-set (mkfvar 1) handler)
(make-set (mkfvar 2) k)
(make-set cpr proc)
(make-set argc-register (make-constant (argc-convention 1)))
(make-asm-instr 'int- fpr (make-constant wordsize))
(make-primcall 'indirect-jump
(list argc-register cpr pcr esp apr
(mkfvar 1) (mkfvar 2)))))]
[else (VT x)])]
[(bind lhs* rhs* e)
(do-bind lhs* rhs* (Tail e))]
[(seq e0 e1)
(make-seq (E e0) (Tail e1))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (Tail e1) (Tail e2))]
[(funcall rator rands)
(handle-tail-call #f rator rands)]
[(jmpcall label rator rands)
(handle-tail-call (make-code-loc label) rator rands)]
[(forcall) (VT x)]
[(shortcut body handler)
(make-shortcut (Tail body) (Tail handler))]
[else (error who "invalid tail ~s" x)]))
Tail)
;;;
(define (formals-locations args)
(let f ([regs parameter-registers] [args args])
(cond
[(null? args) '()]
[(null? regs)
(let f ([i 1] [args args])
(cond
[(null? args) '()]
[else
(cons (mkfvar i)
(f (fxadd1 i) (cdr args)))]))]
[else
(cons (car regs) (f (cdr regs) (cdr args)))])))
;;;
(define locals '())
;;;
(define (ClambdaCase x)
(record-case x
[(clambda-case info body)
(record-case info
[(case-info label args proper)
(set! locals args)
(let* ([locs (formals-locations args)]
[env (map cons args locs)]
[body (let f ([args args] [locs locs])
(cond
[(null? args) ((Tail env) body)]
[else
(make-seq
(make-set (car args) (car locs))
(f (cdr args) (cdr locs)))]))])
(make-clambda-case
(make-case-info label locs proper)
(make-locals locals body)))])]))
;;;
(define (Clambda x)
(record-case x
[(clambda label case* free*)
(make-clambda label (map ClambdaCase case*) free*)]))
;;;
(define (Main x)
(set! locals '())
(let ([x ((Tail '()) x)])
(make-locals locals x)))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(make-codes (map Clambda code*) (Main body))]))
;;;
; (print-code x)
(Program x))
(module ListyGraphs
(empty-graph add-edge! empty-graph? print-graph node-neighbors
delete-node!)
;;;
(define-record graph (ls))
;;;
(define (empty-graph) (make-graph '()))
;;;
(define (empty-graph? g)
(andmap (lambda (x) (null? (cdr x))) (graph-ls g)))
;;;
(define (add-edge! g x y)
(let ([ls (graph-ls g)])
(cond
[(assq x ls) =>
(lambda (p0)
(unless (memq y (cdr p0))
(set-cdr! p0 (cons y (cdr p0)))
(cond
[(assq y ls) =>
(lambda (p1)
(set-cdr! p1 (cons x (cdr p1))))]
[else
(set-graph-ls! g
(cons (list y x) ls))])))]
[(assq y ls) =>
(lambda (p1)
(set-cdr! p1 (cons x (cdr p1)))
(set-graph-ls! g (cons (list x y) ls)))]
[else
(set-graph-ls! g
(list* (list x y)
(list y x)
ls))])))
(define (print-graph g)
(printf "G={\n")
(parameterize ([print-gensym 'pretty])
(for-each (lambda (x)
(let ([lhs (car x)] [rhs* (cdr x)])
(printf " ~s => ~s\n"
(unparse lhs)
(map unparse rhs*))))
(graph-ls g)))
(printf "}\n"))
(define (node-neighbors x g)
(cond
[(assq x (graph-ls g)) => cdr]
[else '()]))
(define (delete-node! x g)
(let ([ls (graph-ls g)])
(cond
[(assq x ls) =>
(lambda (p)
(for-each (lambda (y)
(let ([p (assq y ls)])
(set-cdr! p (set-rem x (cdr p)))))
(cdr p))
(set-cdr! p '()))]
[else (void)])))
;;;
#|ListyGraphs|#)
(begin
(define empty-set '())
(define (set-member? x s) (memq x s))
(define (set-add x s)
(cond
[(memq x s) s]
[else (cons x s)]))
(define (set-rem x s)
(cond
[(null? s) '()]
[(eq? x (car s)) (cdr s)]
[else (cons (car s) (set-rem x (cdr s)))]))
(define (set-difference s1 s2)
(cond
[(null? s2) s1]
[else (set-difference (set-rem (car s2) s1) (cdr s2))]))
(define (set-union s1 s2)
(cond
[(null? s1) s2]
[(memq (car s1) s2) (set-union (cdr s1) s2)]
[else (cons (car s1) (set-union (cdr s1) s2))])))
(module (assign-frame-sizes)
;;; assign-frame-sizes module
(define (has-nontail-call? x)
(define who 'has-nontail-call?)
(define (E x)
(record-case x
[(seq e0 e1) (or (E e0) (E e1))]
[(conditional e0 e1 e2)
(or (P e0) (E e1) (E e2))]
[(nframe) #t]
[(asm-instr) #f]
[(primcall op args)
(case op
[(interrupt nop) #f]
[else (error who "invalid effect ~s" (unparse x))])]
[(shortcut body handler)
(or (E body) (E handler))]
[else (error who "invalid effect ~s" x)]))
(define (P x)
(record-case x
[(seq e0 e1) (or (E e0) (P e1))]
[(conditional e0 e1 e2)
(or (P e0) (P e1) (P e2))]
[(asm-instr) #f]
[(constant) #f]
[(shortcut body handler)
(or (P body) (P handler))]
[else (error who "invalid pred ~s" x)]))
(define (T x)
(record-case x
[(seq e0 e1)
(or (E e0) (T e1))]
[(conditional e0 e1 e2)
(or (P e0) (T e1) (T e2))]
[(primcall) #f]
[(shortcut body handler)
(or (T body) (T handler))]
[else (error who "invalid tail ~s" x)]))
(T x))
;;;
(begin
(define (init-var! x)
(set-var-var-move! x (empty-var-set))
(set-var-reg-move! x (empty-reg-set))
(set-var-frm-move! x (empty-frm-set))
(set-var-var-conf! x (empty-var-set))
(set-var-reg-conf! x (empty-reg-set))
(set-var-frm-conf! x (empty-frm-set)))
(define (init-nfv! x)
(set-nfv-frm-conf! x (empty-frm-set))
(set-nfv-nfv-conf! x (empty-nfv-set))
(set-nfv-var-conf! x (empty-var-set)))
(define (reg? x) (symbol? x))
(define (empty-frm-set) empty-set)
(define (empty-nfv-set) empty-set)
(define (empty-var-set) empty-set)
(define (add-var x s) (set-add x s))
(define (mem-var? x s) (set-member? x s))
(define (rem-var x s) (set-rem x s))
(define (union-vars s1 s2) (union s1 s2))
(define (empty-reg-set) empty-set)
(define (add-reg x s) (set-add x s))
(define (rem-reg x s) (set-rem x s))
(define (mem-reg? x s) (set-member? x s))
(define (union-regs s1 s2) (union s1 s2))
(define (add-frm x s) (set-add x s))
(define (mem-frm? x s) (set-member? x s))
(define (rem-frm x s) (set-rem x s))
(define (union-frms s1 s2) (union s1 s2))
(define (for-each-var s f) (for-each f s))
(define (add-nfv x s) (set-add x s))
(define (rem-nfv x s) (set-rem x s))
(define (mem-nfv? x s) (set-member? x s))
(define (union-nfvs s1 s2) (union s1 s2))
(define (for-each-nfv s f) (for-each f s)))
;;;
(define (uncover-frame-conflicts x)
(define who 'uncover-frame-conflicts)
(define spill-set '())
(define-syntax assert
(syntax-rules ()
[(_ p0 p1 v0 v1)
(unless (and (p0 v0)
(andmap p1 v1))
(error 'assert "failed in ~s" '(assert p0 p1 v0 v1)))]))
(define (mark-reg/vars-conf! r vs)
(assert reg? var? r vs)
(for-each-var vs
(lambda (v)
(set-var-reg-conf! v
(add-reg r (var-reg-conf v))))))
(define (mark-frm/vars-conf! f vs)
(assert fvar? var? f vs)
(for-each-var vs
(lambda (v)
(set-var-frm-conf! v
(add-frm f (var-frm-conf v))))))
(define (mark-frm/nfvs-conf! f ns)
(assert fvar? nfv? f ns)
(for-each-nfv ns
(lambda (n)
(set-nfv-frm-conf! n
(add-frm f (nfv-frm-conf n))))))
(define (mark-var/vars-conf! v vs)
(assert var? var? v vs)
(for-each-var vs
(lambda (w)
(set-var-var-conf! w
(add-var v (var-var-conf w)))))
(set-var-var-conf! v
(union-vars vs (var-var-conf v))))
(define (mark-var/frms-conf! v fs)
(assert var? fvar? v fs)
(set-var-frm-conf! v
(union-frms fs (var-frm-conf v))))
(define (mark-var/regs-conf! v rs)
(assert var? reg? v rs)
(set-var-reg-conf! v
(union-regs rs (var-reg-conf v))))
(define (mark-var/nfvs-conf! v ns)
(assert var? nfv? v ns)
(for-each-nfv ns
(lambda (n)
(set-nfv-var-conf! n
(add-var v (nfv-var-conf n))))))
(define (mark-nfv/vars-conf! n vs)
(assert nfv? var? n vs)
(set-nfv-var-conf! n
(union-vars vs (nfv-var-conf n))))
(define (mark-nfv/frms-conf! n fs)
(assert nfv? fvar? n fs)
(set-nfv-frm-conf! n
(union-frms fs (nfv-frm-conf n))))
(define (mark-nfv/nfvs-conf! n ns)
(assert nfv? nfv? n ns)
(set-nfv-nfv-conf! n
(union-nfvs ns (nfv-nfv-conf n)))
(for-each-nfv ns
(lambda (m)
(set-nfv-nfv-conf! m
(add-nfv n (nfv-nfv-conf m))))))
(define (mark-var/var-move! x y)
(set-var-var-move! x
(add-var y (var-var-move x)))
(set-var-var-move! y
(add-var x (var-var-move y))))
(define (mark-var/frm-move! x y)
(set-var-frm-move! x
(add-frm y (var-frm-move x))))
(define (mark-var/reg-move! x y)
(set-var-reg-move! x
(add-reg y (var-reg-move x))))
(define (const? x)
(or (constant? x)
(code-loc? x)))
(define (R x vs rs fs ns)
(cond
[(const? x) (values vs rs fs ns)]
[(reg? x)
(values vs (add-reg x rs) fs ns)]
[(fvar? x)
(values vs rs (add-frm x fs) ns)]
[(var? x)
(values (add-var x vs) rs fs ns)]
[(nfv? x)
(values vs rs fs (add-nfv x ns))]
[(disp? x)
(let-values ([(vs rs fs ns) (R (disp-s0 x) vs rs fs ns)])
(R (disp-s1 x) vs rs fs ns))]
[else (error who "invalid R ~s" x)]))
(define (R* ls vs rs fs ns)
(cond
[(null? ls) (values vs rs fs ns)]
[else
(let-values ([(vs rs fs ns) (R (car ls) vs rs fs ns)])
(R* (cdr ls) vs rs fs ns))]))
(define (E x vs rs fs ns)
(record-case x
[(seq e0 e1)
(let-values ([(vs rs fs ns) (E e1 vs rs fs ns)])
(E e0 vs rs fs ns))]
[(conditional e0 e1 e2)
(let-values ([(vs1 rs1 fs1 ns1) (E e1 vs rs fs ns)]
[(vs2 rs2 fs2 ns2) (E e2 vs rs fs ns)])
(P e0
vs1 rs1 fs1 ns1
vs2 rs2 fs2 ns2
(union-vars vs1 vs2)
(union-regs rs1 rs2)
(union-frms fs1 fs2)
(union-nfvs ns1 ns2)))]
[(asm-instr op d s)
(case op
[(move)
(cond
[(reg? d)
(cond
[(not (mem-reg? d rs))
(set-asm-instr-op! x 'nop)
(values vs rs fs ns)]
[(or (const? s) (disp? s) (reg? s))
(let ([rs (rem-reg d rs)])
(mark-reg/vars-conf! d vs)
(R s vs rs fs ns))]
[(var? s)
(let ([rs (rem-reg d rs)]
[vs (rem-var s vs)])
(mark-var/reg-move! s d)
(mark-reg/vars-conf! d vs)
(values (add-var s vs) rs fs ns))]
[else (error who "invalid rs ~s" (unparse x))])]
[(fvar? d)
(cond
[(not (mem-frm? d fs))
(set-asm-instr-op! x 'nop)
(values vs rs fs ns)]
[(or (const? s) (disp? s) (reg? s))
(let ([fs (rem-frm d fs)])
(mark-frm/vars-conf! d vs)
(mark-frm/nfvs-conf! d ns)
(R s vs rs fs ns))]
[(var? s)
(let ([fs (rem-frm d fs)]
[vs (rem-var s vs)])
(mark-var/frm-move! s d)
(mark-frm/vars-conf! d vs)
(mark-frm/nfvs-conf! d ns)
(values (add-var s vs) rs fs ns))]
[else (error who "invalid fs ~s" s)])]
[(var? d)
(cond
[(not (mem-var? d vs))
(set-asm-instr-op! x 'nop)
(values vs rs fs ns)]
[(or (disp? s) (constant? s))
(let ([vs (rem-var d vs)])
(mark-var/vars-conf! d vs)
(mark-var/frms-conf! d fs)
(mark-var/regs-conf! d rs)
(mark-var/nfvs-conf! d ns)
(R s vs rs fs ns))]
[(reg? s)
(let ([vs (rem-var d vs)]
[rs (rem-reg s rs)])
(mark-var/reg-move! d s)
(mark-var/vars-conf! d vs)
(mark-var/frms-conf! d fs)
(mark-var/regs-conf! d rs)
(mark-var/nfvs-conf! d ns)
(values vs (add-reg s rs) fs ns))]
[(var? s)
(let ([vs (rem-var d (rem-var s vs))])
(mark-var/var-move! d s)
(mark-var/vars-conf! d vs)
(mark-var/frms-conf! d fs)
(mark-var/regs-conf! d rs)
(mark-var/nfvs-conf! d ns)
(values (add-var s vs) rs fs ns))]
[(fvar? s)
(let ([vs (rem-var d vs)]
[fs (rem-frm s fs)])
(mark-var/frm-move! d s)
(mark-var/vars-conf! d vs)
(mark-var/frms-conf! d fs)
(mark-var/regs-conf! d rs)
(mark-var/nfvs-conf! d ns)
(values vs rs (add-var s fs) ns))]
[else (error who "invalid vs ~s" s)])]
[(nfv? d)
(cond
[(not (mem-nfv? d ns)) (error who "dead nfv")]
[(or (disp? s) (constant? s) (reg? s))
(let ([ns (rem-nfv d ns)])
(mark-nfv/vars-conf! d vs)
(mark-nfv/frms-conf! d fs)
(R s vs rs fs ns))]
[(var? s)
(let ([ns (rem-nfv d ns)]
[vs (rem-var s vs)])
(mark-nfv/vars-conf! d vs)
(mark-nfv/frms-conf! d fs)
(values (add-var s vs) rs fs ns))]
[else (error who "invalid ns ~s" s)])]
[else (error who "invalid d ~s" d)])]
[(int-/overflow int+/overflow int*/overflow)
(let ([v (exception-live-set)])
(unless (vector? v)
(error who "unbound exception"))
(let ([vs (union-vars vs (vector-ref v 0))]
[rs (union-regs rs (vector-ref v 1))]
[fs (union-frms fs (vector-ref v 2))]
[ns (union-nfvs ns (vector-ref v 3))])
(cond
[(var? d)
(cond
[(not (mem-var? d vs))
(set-asm-instr-op! x 'nop)
(values vs rs fs ns)]
[else
(let ([vs (rem-var d vs)])
(mark-var/vars-conf! d vs)
(mark-var/frms-conf! d fs)
(mark-var/nfvs-conf! d ns)
(mark-var/regs-conf! d rs)
(R s (set-add d vs) rs fs ns))])]
[(reg? d)
(cond
[(not (mem-reg? d rs))
(values vs rs fs ns)]
[else
(let ([rs (rem-reg d rs)])
(mark-reg/vars-conf! d vs)
(R s vs (set-add d rs) fs ns))])]
[(nfv? d)
(cond
[(not (mem-nfv? d ns)) (error who "dead nfv")]
[else
(let ([ns (rem-nfv d ns)])
(mark-nfv/vars-conf! d vs)
(mark-nfv/frms-conf! d fs)
(R s vs rs fs (add-nfv d ns)))])]
[else (error who "invalid op d ~s" (unparse x))])))]
[(logand logor logxor sll sra srl int+ int- int*)
(cond
[(var? d)
(cond
[(not (mem-var? d vs))
(set-asm-instr-op! x 'nop)
(values vs rs fs ns)]
[else
(let ([vs (rem-var d vs)])
(mark-var/vars-conf! d vs)
(mark-var/frms-conf! d fs)
(mark-var/nfvs-conf! d ns)
(mark-var/regs-conf! d rs)
(R s (set-add d vs) rs fs ns))])]
[(reg? d)
(cond
[(not (mem-reg? d rs))
(values vs rs fs ns)]
[else
(let ([rs (rem-reg d rs)])
(mark-reg/vars-conf! d vs)
(R s vs (set-add d rs) fs ns))])]
[(nfv? d)
(cond
[(not (mem-nfv? d ns)) (error who "dead nfv")]
[else
(let ([ns (rem-nfv d ns)])
(mark-nfv/vars-conf! d vs)
(mark-nfv/frms-conf! d fs)
(R s vs rs fs (add-nfv d ns)))])]
[else (error who "invalid op d ~s" (unparse x))])]
[(idiv)
(mark-reg/vars-conf! eax vs)
(mark-reg/vars-conf! edx vs)
(R s vs (add-reg eax (add-reg edx rs)) fs ns)]
[(cltd)
(mark-reg/vars-conf! edx vs)
(R s vs (rem-reg edx rs) fs ns)]
[(mset bset/c bset/h)
(R* (list s d) vs rs fs ns)]
[else (error who "invalid effect op ~s" (unparse x))])]
[(ntcall target value args mask size)
(set! spill-set (union-vars vs spill-set))
(R* args vs (empty-reg-set) fs ns)]
[(nframe nfvs live body)
(for-each init-nfv! nfvs)
(set-nframe-live! x (vector vs fs ns))
(E body vs rs fs ns)]
[(primcall op args)
(case op
[(nop) (values vs rs fs ns)]
[(interrupt)
(let ([v (exception-live-set)])
(unless (vector? v)
(error who "unbound exception"))
(values (vector-ref v 0)
(vector-ref v 1)
(vector-ref v 2)
(vector-ref v 3)))]
[else (error who "invalid effect op ~s" op)])]
[(shortcut body handler)
(let-values ([(vsh rsh fsh nsh) (E handler vs rs fs ns)])
(parameterize ([exception-live-set
(vector vsh rsh fsh nsh)])
(E body vs rs fs ns)))]
[else (error who "invalid effect ~s" (unparse x))]))
(define (P x vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)
(record-case x
[(seq e0 e1)
(let-values ([(vs rs fs ns)
(P e1 vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)])
(E e0 vs rs fs ns))]
[(conditional e0 e1 e2)
(let-values ([(vs1 rs1 fs1 ns1)
(P e1 vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)]
[(vs2 rs2 fs2 ns2)
(P e2 vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)])
(P e0
vs1 rs1 fs1 ns1
vs2 rs2 fs2 ns2
(union-vars vs1 vs2)
(union-regs rs1 rs2)
(union-frms fs1 fs2)
(union-nfvs ns1 ns2)))]
[(constant t)
(if t
(values vst rst fst nst)
(values vsf rsf fsf nsf))]
[(asm-instr op d s)
(R* (list d s) vsu rsu fsu nsu)]
[(shortcut body handler)
(let-values ([(vsh rsh fsh nsh)
(P handler vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)])
(parameterize ([exception-live-set
(vector vsh rsh fsh nsh)])
(P body vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)))]
[else (error who "invalid pred ~s" (unparse x))]))
(define (T x)
(record-case x
[(seq e0 e1)
(let-values ([(vs rs fs ns) (T e1)])
(E e0 vs rs fs ns))]
[(conditional e0 e1 e2)
(let-values ([(vs1 rs1 fs1 ns1) (T e1)]
[(vs2 rs2 fs2 ns2) (T e2)])
(P e0
vs1 rs1 fs1 ns1
vs2 rs2 fs2 ns2
(union-vars vs1 vs2)
(union-regs rs1 rs2)
(union-frms fs1 fs2)
(union-nfvs ns1 ns2)))]
[(primcall op arg*)
(case op
[(return indirect-jump direct-jump)
(R* arg* (empty-var-set)
(empty-reg-set)
(empty-frm-set)
(empty-nfv-set))]
[else (error who "invalid tail op ~s" x)])]
[(shortcut body handler)
(let-values ([(vsh rsh fsh nsh) (T handler)])
(parameterize ([exception-live-set
(vector vsh rsh fsh nsh)])
(T body)))]
[else (error who "invalid tail ~s" x)]))
(define exception-live-set
(make-parameter #f))
(T x)
spill-set)
(define-syntax frm-loc
(syntax-rules ()
[(_ x)
(let ([t x])
(if (fvar? t)
(fvar-idx t)
(error 'frm-loc "in ~s ~s" (unparse t) '(frm-loc x))))]))
(define (frame-conflict? i vs fs)
(define (frm-conf x)
(unless (fvar? x) (error 'here3 "herea"))
(fx= i (frm-loc x)))
(define (var-conf x)
(let ([loc (var-loc x)])
(and (fvar? loc)
(fx= i (frm-loc loc)))))
(unless (andmap fvar? fs) (error 'frame-conflict? "nonfvars"))
(or (ormap frm-conf fs)
(ormap var-conf vs)))
;;;
(define (assign-locations! ls)
(for-each (lambda (x) (set-var-loc! x #t)) ls))
(define (rewrite x)
(define who 'rewrite)
(define (assign x)
(define (assign-any)
(let ([frms (var-frm-conf x)]
[vars (var-var-conf x)])
(let f ([i 1])
(cond
[(frame-conflict? i vars frms) (f (fxadd1 i))]
[else
(let ([fv (mkfvar i)])
(set-var-loc! x fv)
(for-each
(lambda (var)
(set-var-var-conf! var
(rem-var x (var-var-conf var)))
(set-var-frm-conf! var
(add-frm fv (var-frm-conf var))))
vars)
fv)]))))
(define (assign-move x)
(let ([mr (set-difference
(var-frm-move x)
(var-frm-conf x))])
(cond
[(null? mr) #f]
[else
(let ([fv (car mr)])
(set-var-loc! x fv)
(for-each
(lambda (var)
(set-var-var-conf! var
(rem-var x (var-var-conf var)))
(set-var-frm-conf! var
(add-frm fv (var-frm-conf var))))
(var-var-conf x))
(for-each
(lambda (var)
(set-var-var-move! var
(rem-var x (var-var-move var)))
(set-var-frm-move! var
(add-frm fv (var-frm-move var)))
(let ([loc (var-loc var)])
(when (and loc (not (fvar? loc)))
(assign-move var))))
(var-var-move x))
fv)])))
(or (assign-move x)
(assign-any)))
(define (NFE idx mask x)
(record-case x
[(seq e0 e1)
(let ([e0 (E e0)])
(make-seq e0 (NFE idx mask e1)))]
[(ntcall target value args mask^ size)
(make-ntcall target value
(map (lambda (x)
(cond
[(symbol? x) x]
[(nfv? x) (nfv-loc x)]
[else (error who "invalid arg")]))
args)
mask idx)]
[else (error who "invalid NF effect ~s" x)]))
(define (Var x)
(cond
[(var-loc x) =>
(lambda (loc)
(if (fvar? loc)
loc
(assign x)))]
[else x]))
(define (R x)
(cond
[(or (constant? x) (reg? x) (fvar? x)) x]
[(nfv? x)
(or (nfv-loc x)
(error who "unassigned nfv"))]
[(var? x) (Var x)]
[(disp? x)
(make-disp (R (disp-s0 x)) (R (disp-s1 x)))]
[else (error who "invalid R ~s" (unparse x))]))
(define (E x)
(record-case x
[(seq e0 e1)
(let ([e0 (E e0)])
(make-seq e0 (E e1)))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (E e1) (E e2))]
[(asm-instr op d s)
(case op
[(move)
(let ([d (R d)] [s (R s)])
(cond
[(eq? d s)
(make-primcall 'nop '())]
[else
(make-asm-instr 'move d s)]))]
[(logand logor logxor int+ int- int* mset bset/c bset/h
sll sra srl
cltd idiv int-/overflow int+/overflow int*/overflow)
(make-asm-instr op (R d) (R s))]
[(nop) (make-primcall 'nop '())]
[else (error who "invalid op ~s" op)])]
[(nframe vars live body)
(let ([live-frms1 (map Var (vector-ref live 0))]
[live-frms2 (vector-ref live 1)]
[live-nfvs (vector-ref live 2)])
(define (max-frm ls i)
(cond
[(null? ls) i]
[else
(max-frm (cdr ls)
(max i (fvar-idx (car ls))))]))
(define (max-nfv ls i)
(cond
[(null? ls) i]
[else
(let ([loc (nfv-loc (car ls))])
(unless (fvar? loc) (error 'max-nfv "not assigned"))
(max-nfv (cdr ls) (max i (frm-loc loc))))]))
(define (actual-frame-size vars i)
(define (frame-size-ok? i vars)
(or (null? vars)
(and (let ([x (car vars)])
(not (frame-conflict? i
(nfv-var-conf x)
(nfv-frm-conf x))))
(frame-size-ok? (fxadd1 i) (cdr vars)))))
(cond
[(frame-size-ok? i vars) i]
[else (actual-frame-size vars (fxadd1 i))]))
(define (assign-frame-vars! vars i)
(unless (null? vars)
(let ([v (car vars)] [fv (mkfvar i)])
(set-nfv-loc! v fv)
(for-each
(lambda (x)
(when (fx= (frm-loc x) i)
(error who "invalid assignment")))
(nfv-frm-conf v))
(for-each
(lambda (x)
(let ([loc (nfv-loc x)])
(cond
[loc
(when (fx= (frm-loc loc) i)
(error who "invalid assignment"))]
[else
(set-nfv-nfv-conf! x
(rem-nfv v (nfv-nfv-conf x)))
(set-nfv-frm-conf! x
(add-frm fv (nfv-frm-conf x)))])))
(nfv-nfv-conf v))
(for-each
(lambda (x)
(let ([loc (var-loc x)])
(cond
[(fvar? loc)
(when (fx= (frm-loc loc) i)
(error who "invalid assignment"))]
[else
(set-var-frm-conf! x
(add-frm fv (var-frm-conf x)))])))
(nfv-var-conf v)))
(assign-frame-vars! (cdr vars) (fxadd1 i))))
(define (make-mask n)
(let ([v (make-vector (fxsra (fx+ n 7) 3) 0)])
(define (set-bit idx)
(let ([q (fxsra idx 3)]
[r (fxlogand idx 7)])
(vector-set! v q
(fxlogor (vector-ref v q) (fxsll 1 r)))))
(for-each (lambda (x) (set-bit (fvar-idx x))) live-frms1)
(for-each (lambda (x) (set-bit (fvar-idx x))) live-frms2)
(for-each (lambda (x)
(let ([loc (nfv-loc x)])
(when loc
(set-bit (fvar-idx loc)))))
live-nfvs) v))
(let ([i (actual-frame-size vars
(fx+ 2
(max-frm live-frms1
(max-nfv live-nfvs
(max-frm live-frms2 0)))))])
(assign-frame-vars! vars i)
(NFE (fxsub1 i) (make-mask (fxsub1 i)) body)))]
[(primcall op args)
(case op
[(nop interrupt) x]
[else (error who "invalid effect prim ~s" op)])]
[(shortcut body handler)
(make-shortcut (E body) (E handler))]
[else (error who "invalid effect ~s" (unparse x))]))
(define (P x)
(record-case x
[(seq e0 e1)
(let ([e0 (E e0)])
(make-seq e0 (P e1)))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (P e1) (P e2))]
[(asm-instr op d s) (make-asm-instr op (R d) (R s))]
[(constant) x]
[(shortcut body handler)
(make-shortcut (P body) (P handler))]
[else (error who "invalid pred ~s" (unparse x))]))
(define (T x)
(record-case x
[(seq e0 e1)
(let ([e0 (E e0)])
(make-seq e0 (T e1)))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (T e1) (T e2))]
[(primcall op args) x]
[(shortcut body handler)
(make-shortcut (T body) (T handler))]
[else (error who "invalid tail ~s" (unparse x))]))
(T x))
;;;
(define (Main x)
(record-case x
[(locals vars body)
(cond
[(has-nontail-call? body)
(for-each init-var! vars)
(let ([call-live* (uncover-frame-conflicts body)])
(assign-locations! call-live*)
(let ([body (rewrite body)])
(make-locals (set-difference vars call-live*) body)))]
[else x])]
[else (error 'assign-frame-sizes "invalid main ~s" x)]))
;;;
(define (ClambdaCase x)
(record-case x
[(clambda-case info body)
(make-clambda-case info (Main body))]))
;;;
(define (Clambda x)
(record-case x
[(clambda label case* free*)
(make-clambda label (map ClambdaCase case*) free*)]))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(make-codes (map Clambda code*) (Main body))]))
;;;
(define (assign-frame-sizes x)
(Program x)))
(module (color-by-chaitin)
(import ListyGraphs)
;;;
(define (build-graph x reg?)
(define who 'build-graph)
(define g (empty-graph))
(define (R* ls)
(cond
[(null? ls) '()]
[else (union (R (car ls)) (R* (cdr ls)))]))
(define (R x)
(record-case x
[(constant) '()]
[(var) (list x)]
[(disp s0 s1) (union (R s0) (R s1))]
[(nfv) (list x)]
[(fvar) (if (reg? x) (list x) '())]
[(code-loc) '()]
[else
(cond
[(symbol? x) (if (reg? x) (list x) '())]
[else (error who "invalid R ~s" x)])]))
;;; build effect
(define (E x s)
(record-case x
[(asm-instr op d v)
(case op
[(move)
(let ([s (set-rem d s)])
(record-case d
[(nfv c i)
(if (list? c)
(set-nfv-conf! d
(set-union c s))
(set-nfv-conf! d s))
(union (R v) s)]
[else
(for-each (lambda (y) (add-edge! g d y)) s)
(union (R v) s)]))]
[(int-/overflow int+/overflow int*/overflow)
(unless (exception-live-set)
(error who "uninitialized live set"))
(let ([s (set-rem d (set-union s (exception-live-set)))])
(record-case d
[(nfv c i)
(if (list? c)
(set-nfv-conf! d (set-union c s))
(set-nfv-conf! d s))
(union (union (R v) (R d)) s)]
[else
(for-each (lambda (y) (add-edge! g d y)) s)
(union (union (R v) (R d)) s)]))]
[(logand logxor int+ int- int* logor sll sra srl)
(let ([s (set-rem d s)])
(record-case d
[(nfv c i)
(if (list? c)
(set-nfv-conf! d (set-union c s))
(set-nfv-conf! d s))
(union (union (R v) (R d)) s)]
[else
(for-each (lambda (y) (add-edge! g d y)) s)
(union (union (R v) (R d)) s)]))]
[(bset/c)
(union (union (R v) (R d)) s)]
[(bset/h)
(when (register? eax)
(when (var? v)
(for-each (lambda (r) (add-edge! g v r))
non-8bit-registers)))
(union (union (R v) (R d)) s)]
[(cltd)
(let ([s (set-rem edx s)])
(when (register? edx)
(for-each (lambda (y)
(add-edge! g edx y))
s))
(union (R eax) s))]
[(idiv)
(let ([s (set-rem eax (set-rem edx s))])
(when (register? eax)
(for-each (lambda (y)
(add-edge! g eax y)
(add-edge! g edx y))
s))
(union (union (R eax) (R edx))
(union (R v) s)))]
[(mset)
(union (R v) (union (R d) s))]
[else (error who "invalid effect ~s" x)])]
[(seq e0 e1) (E e0 (E e1 s))]
[(conditional e0 e1 e2)
(let ([s1 (E e1 s)] [s2 (E e2 s)])
(P e0 s1 s2 (set-union s1 s2)))]
[(ntcall targ value args mask size)
(union (R* args) s)]
[(primcall op arg*)
(case op
[(nop) s]
[(interrupt)
(or (exception-live-set) (error who "uninitialized exception"))]
[else (error who "invalid effect primcall ~s" op)])]
[(shortcut body handler)
(let ([s2 (E handler s)])
(parameterize ([exception-live-set s2])
(E body s)))]
[else (error who "invalid effect ~s" (unparse x))]))
(define (P x st sf su)
(record-case x
[(constant c) (if c st sf)]
[(seq e0 e1)
(E e0 (P e1 st sf su))]
[(conditional e0 e1 e2)
(let ([s1 (P e1 st sf su)] [s2 (P e2 st sf su)])
(P e0 s1 s2 (set-union s1 s2)))]
[(asm-instr op s0 s1)
(union (union (R s0) (R s1)) su)]
[(shortcut body handler)
(let ([s2 (P handler st sf su)])
(parameterize ([exception-live-set s2])
(P body st sf su)))]
[else (error who "invalid pred ~s" (unparse x))]))
(define (T x)
(record-case x
[(conditional e0 e1 e2)
(let ([s1 (T e1)] [s2 (T e2)])
(P e0 s1 s2 (set-union s1 s2)))]
[(primcall op rands)
(R* rands)]
[(seq e0 e1) (E e0 (T e1))]
[(shortcut body handler)
(let ([s2 (T handler)])
(parameterize ([exception-live-set s2])
(T body)))]
[else (error who "invalid tail ~s" (unparse x))]))
(define exception-live-set (make-parameter #f))
(let ([s (T x)])
;(pretty-print (unparse x))
;(print-graph g)
g))
;;;
(define (color-graph sp* un* g)
(define (find-low-degree ls g)
(cond
[(null? ls) #f]
[(fx< (length (node-neighbors (car ls) g))
(length all-registers))
(car ls)]
[else (find-low-degree (cdr ls) g)]))
(define (find-color/maybe x confs env)
(let ([cr (map (lambda (x)
(cond
[(symbol? x) x]
[(assq x env) => cdr]
[else #f]))
confs)])
(let ([r* (set-difference all-registers cr)])
(if (null? r*)
#f
(car r*)))))
(define (find-color x confs env)
(or (find-color/maybe x confs env)
(error 'find-color "cannot find color for ~s" x)))
(cond
[(and (null? sp*) (null? un*)) (values '() '() '())]
[(find-low-degree un* g) =>
(lambda (un)
(let ([n* (node-neighbors un g)])
(delete-node! un g)
(let-values ([(spills sp* env)
(color-graph sp* (set-rem un un*) g)])
(let ([r (find-color un n* env)])
(values spills sp*
(cons (cons un r) env))))))]
[(find-low-degree sp* g) =>
(lambda (sp)
(let ([n* (node-neighbors sp g)])
(delete-node! sp g)
(let-values ([(spills sp* env)
(color-graph (set-rem sp sp*) un* g)])
(let ([r (find-color sp n* env)])
(values spills (cons sp sp*)
(cons (cons sp r) env))))))]
[(pair? sp*)
(let ([sp (car sp*)])
(let ([n* (node-neighbors sp g)])
(delete-node! sp g)
(let-values ([(spills sp* env)
(color-graph (set-rem sp sp*) un* g)])
(let ([r (find-color/maybe sp n* env)])
(if r
(values spills (cons sp sp*)
(cons (cons sp r) env))
(values (cons sp spills) sp* env))))))]
[else (error 'color-graph "whoaaa")]))
;;;
(define (substitute env x frm-graph)
(define who 'substitute)
(define (Var x)
(cond
[(assq x env) => cdr]
[else x]))
(define (Rhs x)
(record-case x
[(var) (Var x)]
[(primcall op rand*)
(make-primcall op (map Rand rand*))]
[else x]))
(define (Rand x)
(record-case x
[(var) (Var x)]
[else x]))
(define (Lhs x)
(record-case x
[(var) (Var x)]
[(nfv confs loc)
(or loc (error who "LHS not set ~s" x))]
[else x]))
(define (D x)
(record-case x
[(constant) x]
[(var) (Var x)]
[(fvar) x]
[else
(if (symbol? x) x (error who "invalid D ~s" x))]))
(define (R x)
(record-case x
[(constant) x]
[(var) (Var x)]
[(fvar) x]
[(nfv c loc)
(or loc (error who "unset nfv ~s in R" x))]
[(disp s0 s1) (make-disp (D s0) (D s1))]
[else
(if (symbol? x) x (error who "invalid R ~s" x))]))
;;; substitute effect
(define (E x)
(record-case x
[(seq e0 e1) (make-seq (E e0) (E e1))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (E e1) (E e2))]
[(asm-instr op x v)
(make-asm-instr op (R x) (R v))]
[(primcall op rands)
(make-primcall op (map R rands))]
[(ntcall) x]
[(shortcut body handler)
(make-shortcut (E body) (E handler))]
[else (error who "invalid effect ~s" (unparse x))]))
(define (P x)
(record-case x
[(constant) x]
[(asm-instr op x v)
(make-asm-instr op (R x) (R v))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (P e1) (P e2))]
[(seq e0 e1) (make-seq (E e0) (P e1))]
[(shortcut body handler)
(make-shortcut (P body) (P handler))]
[else (error who "invalid pred ~s" (unparse x))]))
(define (T x)
(record-case x
[(primcall op rands) x]
[(conditional e0 e1 e2)
(make-conditional (P e0) (T e1) (T e2))]
[(seq e0 e1) (make-seq (E e0) (T e1))]
[(shortcut body handler)
(make-shortcut (T body) (T handler))]
[else (error who "invalid tail ~s" (unparse x))]))
;(print-code x)
(T x))
;;;
(define (do-spill sp* g)
(define (find/set-loc x)
(let ([ls (node-neighbors x g)])
(define (conflicts? i ls)
(and (pair? ls)
(or (record-case (car ls)
[(fvar j)
(and (fixnum? j) (fx= i j))]
[else #f])
(conflicts? i (cdr ls)))))
(let f ([i 1])
(cond
[(conflicts? i ls) (f (fxadd1 i))]
[else
(let ([fv (mkfvar i)])
(for-each (lambda (y) (add-edge! g y fv)) ls)
(delete-node! x g)
(cons x fv))]))))
(map find/set-loc sp*))
;;;
(define (add-unspillables un* x)
(define who 'add-unspillables)
(define (mku)
(let ([u (unique-var 'u)])
(set! un* (cons u un*))
u))
(define (S x k)
(cond
[(or (constant? x) (var? x) (symbol? x))
(k x)]
[else
(let ([u (mku)])
(make-seq (E (make-asm-instr 'move u x)) (k u)))]))
(define (S* ls k)
(cond
[(null? ls) (k '())]
[else
(S (car ls)
(lambda (a)
(S* (cdr ls)
(lambda (d)
(k (cons a d))))))]))
(define (mem? x)
(or (disp? x) (fvar? x)))
;;; unspillable effect
(define (E x)
(record-case x
[(seq e0 e1) (make-seq (E e0) (E e1))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (E e1) (E e2))]
[(asm-instr op a b)
(case op
[(logor logxor logand int+ int- int* move
int-/overflow int+/overflow int*/overflow)
(cond
[(and (eq? op 'move) (eq? a b))
(make-primcall 'nop '())]
[(and (mem? a) (mem? b))
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u b))
(E (make-asm-instr op a u))))]
[(disp? a)
(let ([s0 (disp-s0 a)] [s1 (disp-s1 a)])
(cond
[(mem? s0)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s0))
(E (make-asm-instr op (make-disp u s1) b))))]
[(mem? s1)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s1))
(E (make-asm-instr op (make-disp s0 u) b))))]
[else x]))]
[(disp? b)
(let ([s0 (disp-s0 b)] [s1 (disp-s1 b)])
(cond
[(mem? s0)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s0))
(E (make-asm-instr op a (make-disp u s1)))))]
[(mem? s1)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s1))
(E (make-asm-instr op a (make-disp s0 u)))))]
[else x]))]
[else x])]
[(cltd)
(unless (and (symbol? a) (symbol? b))
(error who "invalid args to cltd"))
x]
[(idiv)
(unless (symbol? a)
(error who "invalid arg to idiv"))
(cond
[(disp? b)
(error who "invalid arg to idiv ~s" b)]
[else x])]
[(sll sra srl)
(unless (or (constant? b)
(eq? b ecx))
(error who "invalid shift ~s" b))
x]
[(mset bset/c bset/h)
(cond
[(mem? b)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u b))
(E (make-asm-instr op a u))))]
[else
(let ([s1 (disp-s0 a)] [s2 (disp-s1 a)])
(cond
[(and (mem? s1) (mem? s2))
(let ([u (mku)])
(make-seq
(make-seq
(E (make-asm-instr 'move u s1))
(E (make-asm-instr 'int+ u s2)))
(make-asm-instr op
(make-disp u (make-constant 0))
b)))]
[(mem? s1)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s1))
(E (make-asm-instr op (make-disp u s2) b))))]
[(mem? s2)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s2))
(E (make-asm-instr op (make-disp u s1) b))))]
[else x]))])]
[else (error who "invalid effect ~s" op)])]
[(primcall op rands)
(case op
[(nop interrupt) x]
[else (error who "invalid op in ~s" (unparse x))])]
[(ntcall) x]
[(shortcut body handler)
(let ([body (E body)])
(make-shortcut body (E handler)))]
[else (error who "invalid effect ~s" (unparse x))]))
(define (P x)
(record-case x
[(constant) x]
[(primcall op rands)
(let ([a0 (car rands)] [a1 (cadr rands)])
(cond
[(and (fvar? a0) (fvar? a1))
(let ([u (mku)])
(make-seq
(make-asm-instr 'move u a0)
(make-primcall op (list u a1))))]
[else x]))]
[(conditional e0 e1 e2)
(make-conditional (P e0) (P e1) (P e2))]
[(seq e0 e1) (make-seq (E e0) (P e1))]
[(asm-instr op a b)
(cond
[(and (mem? a) (mem? b))
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u b))
(make-asm-instr op a u)))]
[else x])]
[(shortcut body handler)
(let ([body (P body)])
(make-shortcut body (P handler)))]
[else (error who "invalid pred ~s" (unparse x))]))
(define (T x)
(record-case x
[(primcall op rands) x]
[(conditional e0 e1 e2)
(make-conditional (P e0) (T e1) (T e2))]
[(seq e0 e1) (make-seq (E e0) (T e1))]
[(shortcut body handler)
(make-shortcut (T body) (T handler))]
[else (error who "invalid tail ~s" (unparse x))]))
(let ([x (T x)])
(values un* x)))
;;;
(define (color-program x)
(define who 'color-program)
(record-case x
[(locals sp* body)
(let ([frame-g (build-graph body fvar?)])
(let loop ([sp* sp*] [un* '()] [body body])
(let-values ([(un* body) (add-unspillables un* body)])
(let ([g (build-graph body
(lambda (x)
(and (symbol? x)
(memq x all-registers))))])
(let-values ([(spills sp* env) (color-graph sp* un* g)])
(cond
[(null? spills) (substitute env body frame-g)]
[else
(let* ([env (do-spill spills frame-g)]
[body (substitute env body frame-g)])
(loop sp* un* body))]))))))]))
;;;
(define (color-by-chaitin x)
;;;
(define (ClambdaCase x)
(record-case x
[(clambda-case info body)
(make-clambda-case info (color-program body))]))
;;;
(define (Clambda x)
(record-case x
[(clambda label case* free*)
(make-clambda label (map ClambdaCase case*) free*)]))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(make-codes (map Clambda code*) (color-program body))]))
;;;
(Program x))
#|chaitin module|#)
(define (flatten-codes x)
(define who 'flatten-codes)
;;;
(define (FVar i)
`(disp ,(* i (- wordsize)) ,fpr))
;;;
(define (C x)
(record-case x
[(code-loc label) (label-address label)]
[(foreign-label L) `(foreign-label ,L)]
[(closure label free*)
(unless (null? free*) (error who "nonempty closure"))
`(obj ,x)]
[(object o)
`(obj ,o)]
[else
(if (integer? x)
x
(error who "invalid constant C ~s" x))]))
(define (BYTE x)
(record-case x
[(constant x)
(unless (and (integer? x) (fx<= x 255) (fx<= 0 x))
(error who "invalid byte ~s" x))
x]
[else (error who "invalid byte ~s" x)]))
(define (D x)
(record-case x
[(constant c) (C c)]
[else
(if (symbol? x) x (error who "invalid D ~s" x))]))
(define (R x)
(record-case x
[(constant c) (C c)]
[(fvar i) (FVar i)]
[(disp s0 s1)
(let ([s0 (D s0)] [s1 (D s1)])
`(disp ,s0 ,s1))]
[else
(if (symbol? x) x (error who "invalid R ~s" x))]))
(define (reg/h x)
(cond
[(assq x '([%eax %ah] [%ebx %bh] [%ecx %ch] [%edx %dh]))
=> cadr]
[else (error who "invalid reg/h ~s" x)]))
(define (R/cl x)
(record-case x
[(constant i)
(unless (fixnum? i)
(error who "invalid R/cl ~s" x))
(fxlogand i 31)]
[else
(if (eq? x ecx)
'%cl
(error who "invalid R/cl ~s" x))]))
(define (interrupt? x)
(record-case x
[(primcall op args) (eq? op 'interrupt)]
[else #f]))
;;; flatten effect
(define (E x ac)
(record-case x
[(seq e0 e1) (E e0 (E e1 ac))]
[(conditional e0 e1 e2)
(cond
[(interrupt? e1)
(let ([L (or (exception-label)
(error who "no exception label"))])
(P e0 L #f (E e2 ac)))]
[(interrupt? e2)
(let ([L (or (exception-label)
(error who "no exception label"))])
(P e0 #f L (E e1 ac)))]
[else
(let ([lf (unique-label)] [le (unique-label)])
(P e0 #f lf
(E e1
(list* `(jmp ,le) lf
(E e2 (cons le ac))))))])]
[(ntcall target value args mask size)
(let ([LCALL (unique-label)])
(define (rp-label value)
(if value
(label-address SL_multiple_values_error_rp)
(label-address SL_multiple_values_ignore_rp)))
(cond
[(string? target) ;; foreign call
(list* `(subl ,(* (fxsub1 size) wordsize) ,fpr)
`(movl (foreign-label "ik_foreign_call") %ebx)
`(jmp ,LCALL)
`(byte-vector ,mask)
`(int ,(* size wordsize))
`(current-frame-offset)
(rp-label value)
'(byte 0)
'(byte 0)
'(byte 0)
LCALL
`(call %ebx)
`(addl ,(* (fxsub1 size) wordsize) ,fpr)
ac)]
[target ;;; known call
(list* `(subl ,(* (fxsub1 size) wordsize) ,fpr)
`(jmp ,LCALL)
`(byte-vector ,mask)
`(int ,(* size wordsize))
`(current-frame-offset)
(rp-label value)
LCALL
`(call (label ,target))
`(addl ,(* (fxsub1 size) wordsize) ,fpr)
ac)]
[else
(list* `(subl ,(* (fxsub1 size) wordsize) ,fpr)
`(jmp ,LCALL)
`(byte-vector ,mask)
`(int ,(* size wordsize))
`(current-frame-offset)
(rp-label value)
'(byte 0)
'(byte 0)
LCALL
`(call (disp ,(fx- disp-closure-code closure-tag) ,cp-register))
`(addl ,(* (fxsub1 size) wordsize) ,fpr)
ac)]))]
[(asm-instr op d s)
(case op
[(logand) (cons `(andl ,(R s) ,(R d)) ac)]
[(int+) (cons `(addl ,(R s) ,(R d)) ac)]
[(int*) (cons `(imull ,(R s) ,(R d)) ac)]
[(int-) (cons `(subl ,(R s) ,(R d)) ac)]
[(logor) (cons `(orl ,(R s) ,(R d)) ac)]
[(logxor) (cons `(xorl ,(R s) ,(R d)) ac)]
[(mset) (cons `(movl ,(R s) ,(R d)) ac)]
[(move)
(if (eq? d s)
ac
(cons `(movl ,(R s) ,(R d)) ac))]
[(bset/c) (cons `(movb ,(BYTE s) ,(R d)) ac)]
[(bset/h) (cons `(movb ,(reg/h s) ,(R d)) ac)]
[(sll) (cons `(sall ,(R/cl s) ,(R d)) ac)]
[(sra) (cons `(sarl ,(R/cl s) ,(R d)) ac)]
[(srl) (cons `(shrl ,(R/cl s) ,(R d)) ac)]
[(idiv) (cons `(idivl ,(R s)) ac)]
[(cltd) (cons `(cltd) ac)]
[(int-/overflow)
(let ([L (or (exception-label)
(error who "no exception label"))])
(list* `(subl ,(R s) ,(R d))
`(jo ,L)
ac))]
[(int*/overflow)
(let ([L (or (exception-label)
(error who "no exception label"))])
(list* `(imull ,(R s) ,(R d))
`(jo ,L)
ac))]
[(int+/overflow)
(let ([L (or (exception-label)
(error who "no exception label"))])
(list* `(addl ,(R s) ,(R d))
`(jo ,L)
ac))]
[else (error who "invalid instr ~s" x)])]
[(primcall op rands)
(case op
[(nop) ac]
[(interrupt)
(let ([l (or (exception-label)
(error who "no exception label"))])
(cons `(jmp ,l) ac))]
[else (error who "invalid effect ~s" (unparse x))])]
[(shortcut body handler)
(let ([L (unique-interrupt-label)] [L2 (unique-label)])
(let ([hand (cons L (E handler `((jmp ,L2))))])
(let ([tc (exceptions-conc)])
(set-cdr! tc (append hand (cdr tc)))))
(parameterize ([exception-label L])
(E body (cons L2 ac))))]
;[(shortcut body handler)
; (let ([L (unique-label)] [L2 (unique-label)])
; (let ([ac (cons L (E handler (cons L2 ac)))])
; (parameterize ([exception-label L])
; (E body (cons `(jmp ,L2) ac)))))]
[else (error who "invalid effect ~s" (unparse x))]))
;;;
(define (unique-interrupt-label)
(label (gensym "ERROR")))
(define (unique-label)
(label (gensym)))
;;;
(define (P x lt lf ac)
(record-case x
[(constant c)
(if c
(if lt (cons `(jmp ,lt) ac) ac)
(if lf (cons `(jmp ,lf) ac) ac))]
[(seq e0 e1)
(E e0 (P e1 lt lf ac))]
[(conditional e0 e1 e2)
(cond
[(and lt lf)
(let ([l (unique-label)])
(P e0 #f l
(P e1 lt lf
(cons l (P e2 lt lf ac)))))]
[lt
(let ([lf (unique-label)] [l (unique-label)])
(P e0 #f l
(P e1 lt lf
(cons l (P e2 lt #f (cons lf ac))))))]
[lf
(let ([lt (unique-label)] [l (unique-label)])
(P e0 #f l
(P e1 lt lf
(cons l (P e2 #f lf (cons lt ac))))))]
[else
(let ([lf (unique-label)] [l (unique-label)])
(P e0 #f l
(P e1 #f #f
(cons `(jmp ,lf)
(cons l (P e2 #f #f (cons lf ac)))))))])]
[(asm-instr op a0 a1)
(let ()
(define (notop x)
(cond
[(assq x '([= !=] [!= =] [< >=] [<= >] [> <=] [>= <]
[u< u>=] [u<= u>] [u> u<=] [u>= u<]))
=> cadr]
[else (error who "invalid op ~s" x)]))
(define (jmpname x)
(cond
[(assq x '([= je] [!= jne] [< jl] [<= jle] [> jg] [>= jge]
[u< jb] [u<= jbe] [u> ja] [u>= jae]))
=> cadr]
[else (error who "invalid jmpname ~s" x)]))
(define (revjmpname x)
(cond
[(assq x '([= je] [!= jne] [< jg] [<= jge] [> jl] [>= jle]
[u< ja] [u<= jae] [u> jb] [u>= jbe]))
=> cadr]
[else (error who "invalid jmpname ~s" x)]))
(define (cmp op a0 a1 lab ac)
(cond
[(or (symbol? a0) (constant? a1))
(list* `(cmpl ,(R a1) ,(R a0))
`(,(jmpname op) ,lab)
ac)]
[(or (symbol? a1) (constant? a0))
(list* `(cmpl ,(R a0) ,(R a1))
`(,(revjmpname op) ,lab)
ac)]
[else (error who "invalid ops ~s ~s" a0 a1)]))
(cond
[(and lt lf)
(cmp op a0 a1 lt
(cons `(jmp ,lf) ac))]
[lt
(cmp op a0 a1 lt ac)]
[lf
(cmp (notop op) a0 a1 lf ac)]
[else ac]))]
[(shortcut body handler)
(let ([L (unique-interrupt-label)] [lj (unique-label)])
(let ([ac (if (and lt lf) ac (cons lj ac))])
(let ([hand (cons L (P handler (or lt lj) (or lf lj) '()))])
(let ([tc (exceptions-conc)])
(set-cdr! tc (append hand (cdr tc)))))
(parameterize ([exception-label L])
(P body lt lf ac))))]
[else (error who "invalid pred ~s" x)]))
;;;
(define (T x ac)
(record-case x
[(seq e0 e1) (E e0 (T e1 ac))]
[(conditional e0 e1 e2)
(let ([L (unique-label)])
(P e0 #f L (T e1 (cons L (T e2 ac)))))]
[(primcall op rands)
(case op
[(return) (cons '(ret) ac)]
[(indirect-jump)
(cons `(jmp (disp ,(fx- disp-closure-code closure-tag) ,cp-register))
ac)]
[(direct-jump)
(cons `(jmp (label ,(code-loc-label (car rands)))) ac)]
[else (error who "invalid tail ~s" x)])]
[(shortcut body handler)
(let ([L (unique-interrupt-label)])
(let ([hand (cons L (T handler '()))])
(let ([tc (exceptions-conc)])
(set-cdr! tc (append hand (cdr tc)))))
(parameterize ([exception-label L])
(T body ac)))]
[else (error who "invalid tail ~s" x)]))
(define exception-label (make-parameter #f))
;;;
(define (handle-vararg fml-count ac)
(define CONTINUE_LABEL (unique-label))
(define DONE_LABEL (unique-label))
(define CONS_LABEL (unique-label))
(define LOOP_HEAD (unique-label))
(define L_CALL (unique-label))
(list* (cmpl (int (argc-convention (fxsub1 fml-count))) eax)
;(jg (label SL_invalid_args))
(jl CONS_LABEL)
(movl (int nil) ebx)
(jmp DONE_LABEL)
CONS_LABEL
(movl (pcb-ref 'allocation-redline) ebx)
(addl eax ebx)
(addl eax ebx)
(cmpl ebx apr)
(jle LOOP_HEAD)
; overflow
(addl eax esp) ; advance esp to cover args
(pushl cpr) ; push current cp
(pushl eax) ; push argc
(negl eax) ; make argc positive
(addl (int (fx* 4 wordsize)) eax) ; add 4 words to adjust frame size
(pushl eax) ; push frame size
(addl eax eax) ; double the number of args
(movl eax (mem (fx* -2 wordsize) fpr)) ; pass it as first arg
(movl (int (argc-convention 1)) eax) ; setup argc
(movl (primref-loc 'do-vararg-overflow) cpr) ; load handler
(jmp L_CALL) ; go to overflow handler
; NEW FRAME
'(int 0) ; if the framesize=0, then the framesize is dynamic
'(current-frame-offset)
'(int 0) ; multiarg rp
(byte 0)
(byte 0)
L_CALL
(indirect-cpr-call)
(popl eax) ; pop framesize and drop it
(popl eax) ; reload argc
(popl cpr) ; reload cp
(subl eax fpr) ; readjust fp
LOOP_HEAD
(movl (int nil) ebx)
CONTINUE_LABEL
(movl ebx (mem disp-cdr apr))
(movl (mem fpr eax) ebx)
(movl ebx (mem disp-car apr))
(movl apr ebx)
(addl (int pair-tag) ebx)
(addl (int pair-size) apr)
(addl (int (fxsll 1 fx-shift)) eax)
(cmpl (int (fx- 0 (fxsll fml-count fx-shift))) eax)
(jle CONTINUE_LABEL)
DONE_LABEL
(movl ebx (mem (fx- 0 (fxsll fml-count fx-shift)) fpr))
ac))
;;;
(define (properize args proper ac)
(cond
[proper ac]
[else
(handle-vararg (length (cdr args)) ac)]))
;;;
(define (ClambdaCase x ac)
(record-case x
[(clambda-case info body)
(record-case info
[(case-info L args proper)
(let ([lothers (unique-label)])
(list* `(cmpl ,(argc-convention
(if proper
(length (cdr args))
(length (cddr args))))
,argc-register)
(cond
[proper `(jne ,lothers)]
[(> (argc-convention 0) (argc-convention 1))
`(jg ,lothers)]
[else
`(jl ,lothers)])
(properize args proper
(cons (label L)
(T body (cons lothers ac))))))])]))
;;;
(define (Clambda x)
(record-case x
[(clambda L case* free*)
(list* (length free*)
(label L)
(let ([ac (list '(nop))])
(parameterize ([exceptions-conc ac])
(let f ([case* case*])
(cond
[(null? case*)
(cons `(jmp (label ,SL_invalid_args)) ac)]
[else
(ClambdaCase (car case*) (f (cdr case*)))])))))]))
;;;
(define exceptions-conc (make-parameter #f))
;;;
(define (Program x)
(record-case x
[(codes code* body)
(cons (list* 0
(label (gensym))
(let ([ac (list '(nop))])
(parameterize ([exceptions-conc ac])
(T body ac))))
(map Clambda code*))]))
;;;
;;; (print-code x)
(Program x))
(define (print-code x)
(parameterize ([print-gensym '#t])
(pretty-print (unparse x))))
(define (alt-cogen x)
(verify-new-cogen-input x)
(let* (
;[foo (printf "0")]
[x (remove-primcalls x)]
;[foo (printf "1")]
[x (eliminate-fix x)]
;[foo (printf "2")]
; [x (normalize-context x)]
;[foo (printf "3")]
; [x (remove-complex-operands x)]
[x (specify-representation x)]
;[foo (printf "4")]
[x (impose-calling-convention/evaluation-order x)]
;[foo (printf "5")]
[x (assign-frame-sizes x)]
;[foo (printf "6")]
[x (color-by-chaitin x)]
;[foo (printf "7")]
[ls (flatten-codes x)]
;[foo (printf "8")]
)
(when #f
(parameterize ([gensym-prefix "L"]
[print-gensym #f])
(for-each
(lambda (ls)
(newline)
(for-each (lambda (x) (printf " ~s\n" x)) ls))
ls)))
ls))
#|module alt-cogen|#)