ikarus/scheme/ikarus.compiler.altcogen.ss

2982 lines
102 KiB
Scheme

;;; 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 <http://www.gnu.org/licenses/>.
(module (alt-cogen compile-call-frame)
;;; 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
;;; | (forcall "name" <Expr>*)
;;; | (funcall <Expr> <Expr>*)
;;; | (jmpcall <label> <Expr> <Expr>*)
;;; | (mvcall <Expr> <clambda>)
;;; <codeloc> ::= (code-loc <label>)
;;; <clambda> ::= (clambda <label> <case>* <cp> <free var>*)
;;; <case> ::= (clambda-case <info> <body>)
;;; <info> ::= (clambda-info label <arg var>* proper)
;;; <Program> ::= (codes <clambda>* <Expr>)
(define (introduce-primcalls x)
;;;
(define who 'introduce-primcalls)
;;;
(define (check-gensym x)
(unless (gensym? x)
(error who "invalid gensym" x)))
;;;
(define (check-label x)
(struct-case x
[(code-loc label)
(check-gensym label)]
[else (error who "invalid label" x)]))
;;;
(define (check-var x)
(struct-case x
[(var) (void)]
[else (error who "invalid var" x)]))
;;;
(define (check-closure x)
(struct-case x
[(closure label free*)
(check-label label)
(for-each check-var free*)]
[else (error who "invalid closure" x)]))
;;;
(define (mkfuncall op arg*)
(import primops)
(struct-case op
[(primref name)
(cond
[(primop? name)
(make-primcall name arg*)]
[else (make-funcall op arg*)])]
[else (make-funcall op arg*)]))
;;;
(define (Expr x)
(struct-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]
[(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" x)]))
;;;
(define (ClambdaCase x)
(struct-case x
[(clambda-case info body)
(make-clambda-case info (Expr body))]
[else (error who "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 who "invalid clambda" x)]))
;;;
(define (Program x)
(struct-case x
[(codes code* body)
(make-codes (map Clambda code*) (Expr body))]
[else (error who "invalid program" x)]))
;;;
(Program x))
(define (eliminate-fix x)
;;;
(define who 'eliminate-fix)
;;;
(define (Expr main-cpvar cpvar free*)
;;;
(define (Var x)
(cond
[(eq? x main-cpvar) cpvar]
[else
(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)
(struct-case x
[(closure code free* well-known?)
(make-closure code (map Var free*) well-known?)]))
(make-fix lhs* (map handle-closure rhs*) body))
(define (Expr x)
(struct-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" x)]))
Expr)
;;;
(define (ClambdaCase main-cp free*)
(lambda (x)
(struct-case x
[(clambda-case info body)
(struct-case info
[(case-info label args proper)
(let ([cp (unique-var 'cp)])
(make-clambda-case
(make-case-info label (cons cp args) proper)
((Expr main-cp cp free*) body)))])]
[else (error who "invalid clambda-case" x)])))
;;;
(define (Clambda x)
(struct-case x
[(clambda label case* cp free* name)
(make-clambda label (map (ClambdaCase cp free*) case*)
#f free* name)]
[else (error who "invalid clambda" x)]))
;;;
(define (Program x)
(struct-case x
[(codes code* body)
(make-codes (map Clambda code*) ((Expr #f #f '()) body))]
[else (error who "invalid program" x)]))
;;;
(Program x))
(define-syntax seq*
(syntax-rules ()
[(_ e) e]
[(_ e* ... e)
(make-seq (seq* e* ...) e)]))
(define (insert-engine-checks x)
(define who 'insert-engine-checks)
(define (Expr x)
(struct-case x
[(constant) #f]
[(var) #f]
[(primref) #f]
[(jmpcall label rator arg*) #t]
[(mvcall rator k) #t]
[(funcall rator arg*)
(if (primref? rator) (ormap Expr arg*) #t)]
[(bind lhs* rhs* body) (or (ormap Expr rhs*) (Expr body))]
[(fix lhs* rhs* body) (Expr body)]
[(conditional e0 e1 e2) (or (Expr e0) (Expr e1) (Expr e2))]
[(seq e0 e1) (or (Expr e0) (Expr e1))]
[(primcall op arg*) (ormap Expr arg*)]
[(forcall op arg*) (ormap Expr arg*)]
[else (error who "invalid expr" x)]))
(define (Main x)
(if (Expr x)
(make-seq (make-primcall '$do-event '()) x)
x))
(define (CaseExpr x)
(struct-case x
[(clambda-case info body)
(make-clambda-case info (Main body))]))
(define (CodeExpr x)
(struct-case x
[(clambda L cases cp free name)
(make-clambda L (map CaseExpr cases) cp free name)]))
(define (CodesExpr x)
(struct-case x
[(codes list body)
(make-codes (map CodeExpr list) (Main body))]))
(CodesExpr x))
(define (insert-stack-overflow-check x)
(define who 'insert-stack-overflow-check)
(define (NonTail x)
(struct-case x
[(constant) #f]
[(var) #f]
[(primref) #f]
[(funcall rator arg*) #t]
[(jmpcall label rator arg*) #t]
[(mvcall rator k) #t]
[(bind lhs* rhs* body) (or (ormap NonTail rhs*) (NonTail body))]
[(fix lhs* rhs* body) (NonTail body)]
[(conditional e0 e1 e2) (or (NonTail e0) (NonTail e1) (NonTail e2))]
[(seq e0 e1) (or (NonTail e0) (NonTail e1))]
[(primcall op arg*) (ormap NonTail arg*)]
[(forcall op arg*) (ormap NonTail arg*)]
[else (error who "invalid expr" x)]))
(define (Tail x)
(struct-case x
[(constant) #f]
[(var) #f]
[(primref) #f]
[(bind lhs* rhs* body) (or (ormap NonTail rhs*) (Tail body))]
[(fix lhs* rhs* body) (Tail body)]
[(conditional e0 e1 e2) (or (NonTail e0) (Tail e1) (Tail e2))]
[(seq e0 e1) (or (NonTail e0) (Tail e1))]
[(primcall op arg*) (ormap NonTail arg*)]
[(forcall op arg*) (ormap NonTail arg*)]
[(funcall rator arg*) (or (NonTail rator) (ormap NonTail arg*))]
[(jmpcall label rator arg*) (or (NonTail rator) (ormap NonTail arg*))]
[(mvcall rator k) #t] ; punt
[else (error who "invalid expr" x)]))
(define (insert-check x)
(make-seq (make-primcall '$stack-overflow-check '()) x))
(define (ClambdaCase x)
(struct-case x
[(clambda-case info body)
(make-clambda-case info (Main body))]))
(define (Clambda x)
(struct-case x
[(clambda label case* cp free* name)
(make-clambda label (map ClambdaCase case*) cp free* name)]))
(define (Main x)
(if (Tail x)
(insert-check x)
x))
(define (Program x)
(struct-case x
[(codes code* body)
(make-codes (map Clambda code*) (Main body))]))
(Program x))
(define (insert-dummy-type-annotations x)
(define who 'insert-dummy-type-annotations)
(define (Closure x)
(struct-case x
[(closure code free*)
x]
;(make-closure (Expr code) (map Var free*))]
[else (error who "not a closure" x)]))
(define (Expr x)
(struct-case x
[(constant i)
(make-known x 'constant i)]
[(var) x]
[(primref op)
(make-known x 'primitive op)]
[(bind lhs* rhs* body)
(make-bind lhs* (map Expr rhs*) (Expr body))]
[(fix lhs* rhs* body)
(make-fix lhs* (map Closure rhs*) (Expr body))]
[(conditional e0 e1 e2)
(make-conditional (Expr e0) (Expr e1) (Expr e2))]
[(seq e0 e1)
(make-seq (Expr e0) (Expr e1))]
[(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) (Expr k))]
[else (error who "invalid expr" x)]))
(define (ClambdaCase x)
(struct-case x
[(clambda-case info body)
(make-clambda-case info (Expr body))]))
(define (Clambda x)
(struct-case x
[(clambda label case* cp free* name)
(make-clambda label (map ClambdaCase case*) cp free* name)]))
(define (Program x)
(struct-case x
[(codes code* body)
(make-codes (map Clambda code*) (Expr body))]))
(Program x))
(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 %ecx))
(define argc-register '%eax)
;;; apr = %ebp
;;; esp = %esp
;;; pcr = %esi
;;; cpr = %edi
(define (register-index x)
(cond
[(assq x '([%eax 0] [%edi 1] [%ebx 2] [%edx 3]
[%ecx 4] [%esi 5] [%esp 6] [%ebp 7]))
=> cadr]
[else (error 'register-index "not a register" x)]))
(define non-8bit-registers
'(%edi))
(define (impose-calling-convention/evaluation-order x)
(define who 'impose-calling-convention/evaluation-order)
;;;
;;;
(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)
(struct-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) (symbol? x)) (k x)]
[(var? x)
(cond
[(var-loc x) => k]
[else (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" x)])]))
;(define (Mem x k)
; (struct-case x
; [(primcall op arg*)
; (if (eq? op 'mref)
; (S* arg*
; (lambda (arg*)
; (make-disp (car arg*) (cadr arg*))))
; (S x k))]
; [else (S x k)]))
;;;
(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
(cons* 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 (primref->symbol 'do-overflow)))
;;; (make-constant (- disp-symbol-record-proc symbol-ptag))))
;;; (list size)))))
(define (alloc-check size)
(E (make-shortcut
(make-conditional ;;; PCB ALLOC-REDLINE
(make-primcall '<=
(list (make-primcall 'int+ (list apr size))
(make-primcall 'mref
(list pcr
(make-constant pcb-allocation-redline)))))
(make-primcall 'nop '())
(make-primcall 'interrupt '()))
(make-funcall
(make-primcall 'mref
(list
(make-constant (make-object (primref->symbol 'do-overflow)))
(make-constant (- disp-symbol-record-proc symbol-ptag))))
(list size)))))
;;; impose value
(define (V d x)
(struct-case x
[(constant) (make-set d x)]
[(var)
(cond
[(var-loc x) => (lambda (loc) (make-set d loc))]
[else (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)
(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)
(make-set d (make-disp (car rands) (cadr rands)))))]
[(mref32)
(S* rands
(lambda (rands)
(make-asm-instr 'load32 d
(make-disp (car rands) (cadr rands)))))]
[(bref)
(S* rands
(lambda (rands)
(make-asm-instr 'move-byte d
(make-disp (car rands) (cadr rands)))))]
[(logand logxor logor int+ int- int*
int-/overflow int+/overflow int*/overflow)
(make-seq
(V d (car rands))
(S (cadr rands)
(lambda (s)
(make-asm-instr op d s))))]
[(remainder)
(S* rands
(lambda (rands)
(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)
(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 sll/overflow)
(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" 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" (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 pcr esp apr return-value-register))))))
;;; impose effect
(define (E x)
(struct-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 bset/c bset/h mset32)
(S* rands
(lambda (s*)
(make-asm-instr op
(make-disp (car s*) (cadr s*))
(caddr s*))))]
[(fl:load fl:store fl:add! fl:sub! fl:mul! fl:div!
fl:from-int fl:shuffle bswap!
fl:store-single fl:load-single)
(S* rands
(lambda (s*)
(make-asm-instr op (car s*) (cadr s*))))]
[(nop interrupt incr/zero? fl:double->single
fl:single->double) x]
[else (error 'impose-effect "invalid instr" 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" x)]))
;;; impose pred
(define (P x)
(struct-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)
(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)))))]
;[(constant? a)
; (Mem b (lambda (b) (make-asm-instr op a b)))]
;[(constant? b)
; (Mem a (lambda (a) (make-asm-instr op a 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" x)]))
;;;
(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
(cons* argc-register
pcr esp apr
locs)))]
[else
(make-primcall 'indirect-jump
(cons* 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))
(var? (car args))
(eq? (car locs) (var-loc (car args))))
(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)
(struct-case x
[(constant) (VT x)]
[(var) (VT x)]
[(primcall op rands)
(case op
[($call-with-underflow-handler)
(let ([t0 (unique-var 't)]
[t1 (unique-var 't)]
[t2 (unique-var 't)]
[handler (car rands)]
[proc (cadr rands)]
[k (caddr rands)])
(set! locals (cons* t0 t1 t2 locals))
(seq*
(V t0 handler)
(V t1 k)
(V t2 proc)
(make-set (mkfvar 1) t0)
(make-set (mkfvar 2) t1)
(make-set cpr t2)
(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" x)]))
;;;
(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 (partition-formals ls)
(let f ([regs parameter-registers] [ls ls])
(cond
[(null? regs)
(let ([flocs
(let f ([i 1] [ls ls])
(cond
[(null? ls) '()]
[else (cons (mkfvar i) (f (fxadd1 i) (cdr ls)))]))])
(values '() '() ls flocs))]
[(null? ls)
(values '() '() '() '())]
[else
(let-values ([(rargs rlocs fargs flocs)
(f (cdr regs) (cdr ls))])
(values (cons (car ls) rargs)
(cons (car regs) rlocs)
fargs flocs))])))
;;;
(define (ClambdaCase x)
(struct-case x
[(clambda-case info body)
(struct-case info
[(case-info label args proper)
(let-values ([(rargs rlocs fargs flocs)
(partition-formals args)])
(set! locals rargs)
(for-each set-var-loc! fargs flocs)
(let ([body (let f ([args rargs] [locs rlocs])
(cond
[(null? args) (Tail body)]
[else
(make-seq
(make-set (car args) (car locs))
(f (cdr args) (cdr locs)))]))])
(make-clambda-case
(make-case-info label (append rlocs flocs) proper)
(make-locals locals body))))])]))
;;;
(define (Clambda x)
(struct-case x
[(clambda label case* cp free* name)
(make-clambda label (map ClambdaCase case*) cp free* name)]))
;;;
(define (Main x)
(set! locals '())
(let ([x (Tail x)])
(make-locals locals x)))
;;;
(define (Program x)
(struct-case x
[(codes code* body)
(make-codes (map Clambda code*) (Main body))]))
;;;
; (print-code x)
(Program x))
(module ListySet
(make-empty-set set-member? set-add set-rem set-difference set-union
empty-set?
set->list list->set)
(define-struct set (v))
(define (make-empty-set) (make-set '()))
(define (set-member? x s)
;(unless (fixnum? x) (error 'set-member? "not a fixnum" x))
(unless (set? s) (error 'set-member? "not a set" s))
(memq x (set-v s)))
(define (empty-set? s)
(unless (set? s) (error 'empty-set? "not a set" s))
(null? (set-v s)))
(define (set->list s)
(unless (set? s) (error 'set->list "not a set" s))
(set-v s))
(define (set-add x s)
;(unless (fixnum? x) (error 'set-add "not a fixnum" x))
(unless (set? s) (error 'set-add "not a set" s))
(cond
[(memq x (set-v s)) s]
[else (make-set (cons x (set-v s)))]))
(define (rem x s)
(cond
[(null? s) '()]
[(eq? x (car s)) (cdr s)]
[else (cons (car s) (rem x (cdr s)))]))
(define (set-rem x s)
;(unless (fixnum? x) (error 'set-rem "not a fixnum" x))
(unless (set? s) (error 'set-rem "not a set" s))
(make-set (rem x (set-v s))))
(define (difference s1 s2)
(cond
[(null? s2) s1]
[else (difference (rem (car s2) s1) (cdr s2))]))
(define (set-difference s1 s2)
(unless (set? s1) (error 'set-difference "not a set" s1))
(unless (set? s2) (error 'set-difference "not a set" s2))
(make-set (difference (set-v s1) (set-v s2))))
(define (set-union s1 s2)
(unless (set? s1) (error 'set-union "not a set" s1))
(unless (set? s2) (error 'set-union "not a set" s2))
(make-set (union (set-v s1) (set-v s2))))
(define (list->set ls)
;(unless (andmap fixnum? ls) (error 'set-rem "not a list of fixnum" ls))
(make-set ls))
(define (union s1 s2)
(cond
[(null? s1) s2]
[(memq (car s1) s2) (union (cdr s1) s2)]
[else (cons (car s1) (union (cdr s1) s2))])))
(module IntegerSet
(make-empty-set set-member? set-add set-rem set-difference
set-union empty-set? set->list list->set)
;;;
(begin
(define-syntax car (identifier-syntax $car))
(define-syntax cdr (identifier-syntax $cdr))
(define-syntax fxsll (identifier-syntax $fxsll))
(define-syntax fxsra (identifier-syntax $fxsra))
(define-syntax fxlogor (identifier-syntax $fxlogor))
(define-syntax fxlogand (identifier-syntax $fxlogand))
(define-syntax fxlognot (identifier-syntax $fxlognot))
(define-syntax fx+ (identifier-syntax $fx+))
(define-syntax fxzero? (identifier-syntax $fxzero?))
(define-syntax fxeven?
(syntax-rules ()
[(_ x) ($fxzero? ($fxlogand x 1))])))
;;;
(define bits 28)
(define (index-of n) (fxquotient n bits))
(define (mask-of n) (fxsll 1 (fxremainder n bits)))
;;;
(define (make-empty-set) 0)
(define (empty-set? s) (eqv? s 0))
(define (set-member? n s)
(unless (fixnum? n) (error 'set-member? "not a fixnum" n))
(let f ([s s] [i (index-of n)] [j (mask-of n)])
(cond
[(pair? s)
(if (fxeven? i)
(f (car s) (fxsra i 1) j)
(f (cdr s) (fxsra i 1) j))]
[(eq? i 0) (eq? j (fxlogand s j))]
[else #f])))
;;;
(define (set-add n s)
(unless (fixnum? n) (error 'set-add "not a fixnum" n))
(let f ([s s] [i (index-of n)] [j (mask-of n)])
(cond
[(pair? s)
(if (fxeven? i)
(let ([a0 (car s)])
(let ([a1 (f a0 (fxsra i 1) j)])
(if (eq? a0 a1) s (cons a1 (cdr s)))))
(let ([d0 (cdr s)])
(let ([d1 (f d0 (fxsra i 1) j)])
(if (eq? d0 d1) s (cons (car s) d1)))))]
[(eq? i 0) (fxlogor s j)]
[else
(if (fxeven? i)
(cons (f s (fxsra i 1) j) 0)
(cons s (f 0 (fxsra i 1) j)))])))
;;;
(define (cons^ a d)
(if (and (eq? d 0) (fixnum? a))
a
(cons a d)))
;;;
(define (set-rem n s)
(unless (fixnum? n) (error 'set-rem "not a fixnum" n))
(let f ([s s] [i (index-of n)] [j (mask-of n)])
(cond
[(pair? s)
(if (fxeven? i)
(let ([a0 (car s)])
(let ([a1 (f a0 (fxsra i 1) j)])
(if (eq? a0 a1) s (cons^ a1 (cdr s)))))
(let ([d0 (cdr s)])
(let ([d1 (f d0 (fxsra i 1) j)])
(if (eq? d0 d1) s (cons^ (car s) d1)))))]
[(eq? i 0) (fxlogand s (fxlognot j))]
[else s])))
(define (set-union^ s1 m2)
(if (pair? s1)
(let ([a0 (car s1)])
(let ([a1 (set-union^ a0 m2)])
(if (eq? a0 a1) s1 (cons a1 (cdr s1)))))
(fxlogor s1 m2)))
;;;
(define (set-union s1 s2)
(if (pair? s1)
(if (pair? s2)
(if (eq? s1 s2)
s1
(cons (set-union (car s1) (car s2))
(set-union (cdr s1) (cdr s2))))
(let ([a0 (car s1)])
(let ([a1 (set-union^ a0 s2)])
(if (eq? a0 a1) s1 (cons a1 (cdr s1))))))
(if (pair? s2)
(let ([a0 (car s2)])
(let ([a1 (set-union^ a0 s1)])
(if (eq? a0 a1) s2 (cons a1 (cdr s2)))))
(fxlogor s1 s2))))
;;;
(define (set-difference^ s1 m2)
(if (pair? s1)
(let ([a0 (car s1)])
(let ([a1 (set-difference^ a0 m2)])
(if (eq? a0 a1) s1 (cons^ a1 (cdr s1)))))
(fxlogand s1 (fxlognot m2))))
(define (set-difference^^ m1 s2)
(if (pair? s2)
(set-difference^^ m1 (car s2))
(fxlogand m1 (fxlognot s2))))
;;;
(define (set-difference s1 s2)
(if (pair? s1)
(if (pair? s2)
(if (eq? s1 s2)
0
(cons^ (set-difference (car s1) (car s2))
(set-difference (cdr s1) (cdr s2))))
(let ([a0 (car s1)])
(let ([a1 (set-difference^ a0 s2)])
(if (eq? a0 a1) s1 (cons^ a1 (cdr s1))))))
(if (pair? s2)
(set-difference^^ s1 (car s2))
(fxlogand s1 (fxlognot s2)))))
;;;
(define (list->set ls)
(unless (andmap fixnum? ls) (error 'list->set "not a list of fixnum" ls))
(let f ([ls ls] [s 0])
(cond
[(null? ls) s]
[else (f (cdr ls) (set-add (car ls) s))])))
;;;
(define (set->list s)
(let f ([i 0] [j 1] [s s] [ac '()])
(cond
[(pair? s)
(f i (fxsll j 1) (car s)
(f (fxlogor i j) (fxsll j 1) (cdr s) ac))]
[else
(let f ([i (fx* i bits)] [m s] [ac ac])
(cond
[(fxeven? m)
(if (fxzero? m)
ac
(f (fx+ i 1) (fxsra m 1) ac))]
[else
(f (fx+ i 1) (fxsra m 1) (cons i ac))]))])))
#|IntegerSet|#)
(module ListyGraphs
(empty-graph add-edge! empty-graph? print-graph node-neighbors
delete-node!)
(import ListySet)
;;;
(define-struct graph (ls))
;;;
(define (empty-graph) (make-graph '()))
;;;
(define (empty-graph? g)
(andmap (lambda (x) (empty-set? (cdr x))) (graph-ls g)))
;;;
(define (single x)
(set-add x (make-empty-set)))
;;;
(define (add-edge! g x y)
(let ([ls (graph-ls g)])
(cond
[(assq x ls) =>
(lambda (p0)
(unless (set-member? y (cdr p0))
(set-cdr! p0 (set-add y (cdr p0)))
(cond
[(assq y ls) =>
(lambda (p1)
(set-cdr! p1 (set-add x (cdr p1))))]
[else
(set-graph-ls! g
(cons (cons y (single x)) ls))])))]
[(assq y ls) =>
(lambda (p1)
(set-cdr! p1 (set-add x (cdr p1)))
(set-graph-ls! g (cons (cons x (single y)) ls)))]
[else
(set-graph-ls! g
(cons* (cons x (single y))
(cons y (single 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 (set->list rhs*)))))
(graph-ls g)))
(printf "}\n"))
(define (node-neighbors x g)
(cond
[(assq x (graph-ls g)) => cdr]
[else (make-empty-set)]))
;;;
(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)))))
(set->list (cdr p)))
(set-cdr! p (make-empty-set)))]
[else (void)])))
;;;
#|ListyGraphs|#)
(module IntegerGraphs
(empty-graph add-edge! empty-graph? print-graph node-neighbors
delete-node!)
(import IntegerSet)
;;;
(define-struct graph (ls))
;;;
(define (empty-graph) (make-graph '()))
;;;
(define (empty-graph? g)
(andmap (lambda (x) (empty-set? (cdr x))) (graph-ls g)))
;;;
(define (single x)
(set-add x (make-empty-set)))
;;;
(define (add-edge! g x y)
(let ([ls (graph-ls g)])
(cond
[(assq x ls) =>
(lambda (p0)
(unless (set-member? y (cdr p0))
(set-cdr! p0 (set-add y (cdr p0)))
(cond
[(assq y ls) =>
(lambda (p1)
(set-cdr! p1 (set-add x (cdr p1))))]
[else
(set-graph-ls! g
(cons (cons y (single x)) ls))])))]
[(assq y ls) =>
(lambda (p1)
(set-cdr! p1 (set-add x (cdr p1)))
(set-graph-ls! g (cons (cons x (single y)) ls)))]
[else
(set-graph-ls! g
(cons* (cons x (single y))
(cons y (single 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 (set->list rhs*)))))
(graph-ls g)))
(printf "}\n"))
(define (node-neighbors x g)
(cond
[(assq x (graph-ls g)) => cdr]
[else (make-empty-set)]))
;;;
(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)))))
(set->list (cdr p)))
(set-cdr! p (make-empty-set)))]
[else (void)])))
;;;
#|IntegerGraphs|#)
(module conflict-helpers
(empty-var-set rem-var add-var union-vars mem-var? for-each-var init-vars!
empty-nfv-set rem-nfv add-nfv union-nfvs mem-nfv? for-each-nfv init-nfv!
empty-frm-set rem-frm add-frm union-frms mem-frm?
empty-reg-set rem-reg add-reg union-regs mem-reg?
reg?)
(import IntegerSet)
(begin
(define (add-frm x s) (set-add (fvar-idx x) s))
(define (rem-nfv x s)
(remq1 x s))
(define (init-var! x i)
(set-var-index! x i)
(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-vars! ls)
(let f ([ls ls] [i 0])
(unless (null? ls)
(init-var! (car ls) i)
(f (cdr ls) (fxadd1 i)))))
(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-var-set) (make-empty-set))
(define (add-var x s) (set-add (var-index x) s))
(define (mem-var? x s) (set-member? (var-index x) s))
(define (rem-var x s) (set-rem (var-index x) s))
(define (union-vars s1 s2) (set-union s1 s2))
(define (for-each-var s varvec f)
(for-each (lambda (i) (f (vector-ref varvec i)))
(set->list s)))
(define (empty-reg-set) (make-empty-set))
(define (add-reg x s) (set-add (register-index x) s))
(define (rem-reg x s) (set-rem (register-index x) s))
(define (mem-reg? x s) (set-member? (register-index x) s))
(define (union-regs s1 s2) (set-union s1 s2))
(define (empty-frm-set) (make-empty-set))
(define (mem-frm? x s) (set-member? (fvar-idx x) s))
(define (rem-frm x s) (set-rem (fvar-idx x) s))
(define (union-frms s1 s2) (set-union s1 s2))
(define (empty-nfv-set) '())
(define (add-nfv x s)
(cond
[(memq x s) s]
[else (cons x s)]))
(define (mem-nfv? x s)
(memq x s))
(define (union-nfvs s1 s2)
(let f ([s1 s1] [s2 s2])
(cond
[(null? s1) s2]
[(memq (car s1) s2) (f (cdr s1) s2)]
[else (cons (car s1) (f (cdr s1) s2))])))
(define (for-each-nfv s f)
(for-each f s))))
(define (uncover-frame-conflicts x varvec)
(import IntegerSet)
(import conflict-helpers)
(define who 'uncover-frame-conflicts)
(define spill-set (make-empty-set))
(define (mark-reg/vars-conf! r vs)
(for-each-var vs varvec
(lambda (v)
(set-var-reg-conf! v
(add-reg r (var-reg-conf v))))))
(define (mark-frm/vars-conf! f vs)
(for-each-var vs varvec
(lambda (v)
(set-var-frm-conf! v
(add-frm f (var-frm-conf v))))))
(define (mark-frm/nfvs-conf! 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)
(for-each-var vs varvec
(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)
(set-var-frm-conf! v
(union-frms fs (var-frm-conf v))))
(define (mark-var/regs-conf! v rs)
(set-var-reg-conf! v
(union-regs rs (var-reg-conf v))))
(define (mark-var/nfvs-conf! 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)
(set-nfv-var-conf! n
(union-vars vs (nfv-var-conf n))))
(define (mark-nfv/frms-conf! n fs)
(set-nfv-frm-conf! n
(union-frms fs (nfv-frm-conf n))))
(define (mark-nfv/nfvs-conf! 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" 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)
(struct-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 move-byte load32)
(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))]
[(fvar? s)
(let ([rs (rem-reg d rs)])
(mark-reg/vars-conf! d vs)
(values vs rs (add-frm s fs) ns))]
[else (error who "invalid rs" (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)])]
[(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-frm s fs) ns))]
[else (error who "invalid vs" 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))]
[(fvar? s)
(let ([ns (rem-nfv d ns)]
[fs (rem-frm s fs)])
(mark-nfv/vars-conf! d vs)
(mark-nfv/frms-conf! d fs)
(values vs rs (add-frm s fs) ns))]
[else (error who "invalid ns" s)])]
[else (error who "invalid d" d)])]
[(int-/overflow int+/overflow int*/overflow)
(let ([v (exception-live-set)])
(unless (vector? v)
(error who "unbound exception" x v))
(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 (add-var 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 (add-reg 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" (unparse x))])))]
[(logand logor logxor sll sra srl int+ int- int* bswap!
sll/overflow)
(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 (add-var d vs) rs fs ns))])]
[(reg? d)
(cond
[(not (mem-reg? d rs))
(set-asm-instr-op! x 'nop)
(values vs rs fs ns)]
[else
(let ([rs (rem-reg d rs)])
(mark-reg/vars-conf! d vs)
(R s vs (add-reg 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" (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 mset32 bset bset/c bset/h
fl:load fl:store fl:add! fl:sub! fl:mul! fl:div! fl:from-int
fl:shuffle fl:load-single fl:store-single)
(R* (list s d) vs rs fs ns)]
[else (error who "invalid effect op" (unparse x))])]
[(ntcall target value args mask size)
(set! spill-set (union-vars vs spill-set))
(for-each-var vs varvec (lambda (x) (set-var-loc! x #t)))
(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 fl:double->single fl:single->double) (values vs rs fs ns)]
[(interrupt incr/zero?)
(let ([v (exception-live-set)])
(unless (vector? v)
(error who "unbound exception2"))
(values (vector-ref v 0)
(vector-ref v 1)
(vector-ref v 2)
(vector-ref v 3)))]
[else (error who "invalid effect op" 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" (unparse x))]))
(define (P x vst rst fst nst
vsf rsf fsf nsf
vsu rsu fsu nsu)
(struct-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" (unparse x))]))
(define (T x)
(struct-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" 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" x)]))
(define exception-live-set
(make-parameter #f))
(T x)
spill-set)
(module (assign-frame-sizes)
;;; assign-frame-sizes module
(define indent (make-parameter 0))
(import IntegerSet)
(import conflict-helpers)
(define (rewrite x varvec)
(define who 'rewrite)
(define (assign x)
(let ()
(define (assign-any)
(let ([frms (var-frm-conf x)]
[vars (var-var-conf x)])
(let f ([i 1])
(cond
[(set-member? i frms) (f (fxadd1 i))]
[else
(let ([fv (mkfvar i)])
(set-var-loc! x fv)
(for-each-var vars varvec
(lambda (var)
(set-var-frm-conf! var
(add-frm fv (var-frm-conf var)))))
fv)]))))
(define (assign-move x)
(let ([mr (set->list
(set-difference
(var-frm-move x)
(var-frm-conf x)))])
(cond
[(null? mr) #f]
[else
(let ([fv (mkfvar (car mr))])
(set-var-loc! x fv)
(for-each-var (var-var-conf x) varvec
(lambda (var)
(set-var-frm-conf! var
(add-frm fv (var-frm-conf var)))))
(for-each-var (var-var-move x) varvec
(lambda (var)
(set-var-frm-move! var
(add-frm fv (var-frm-move var)))))
fv)])))
(or (assign-move x)
(assign-any))))
(define (NFE idx mask x)
(struct-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" 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" (unparse x))]))
(define (E x)
(struct-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 move-byte load32)
(let ([d (R d)] [s (R s)])
(cond
[(eq? d s)
(make-primcall 'nop '())]
[else
(make-asm-instr op d s)]))]
[(logand logor logxor int+ int- int* mset bset mset32 bset/c bset/h
sll sra srl bswap!
cltd idiv int-/overflow int+/overflow int*/overflow
fl:load fl:store fl:add! fl:sub! fl:mul! fl:div!
fl:from-int fl:shuffle fl:load-single fl:store-single
sll/overflow)
(make-asm-instr op (R d) (R s))]
[(nop) (make-primcall 'nop '())]
[else (error who "invalid op" op)])]
[(nframe vars live body)
(let ([live-frms1
(map (lambda (i) (Var (vector-ref varvec i)))
(set->list (vector-ref live 0)))]
[live-frms2 (set->list (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-ls ls i)
(cond
[(null? ls) i]
[else
(max-ls (cdr ls) (max i (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 (fvar-idx loc))))]))
(define (actual-frame-size vars i)
(define (var-conflict? i vs)
(ormap (lambda (xi)
(let ([loc (var-loc (vector-ref varvec xi))])
(and (fvar? loc)
(fx= i (fvar-idx loc)))))
(set->list vs)))
(define (frame-size-ok? i vars)
(or (null? vars)
(let ([x (car vars)])
(and (not (set-member? i (nfv-frm-conf x)))
(not (var-conflict? i (nfv-var-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 (j)
; (when (fx= j i)
; (error who "invalid assignment")))
; (set->list (nfv-frm-conf v)))
(for-each
(lambda (x)
(let ([loc (nfv-loc x)])
(cond
[loc
(when (fx= (fvar-idx 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-var (nfv-var-conf v) varvec
(lambda (x)
(let ([loc (var-loc x)])
(cond
[(fvar? loc)
(when (fx= (fvar-idx loc) i)
(error who "invalid assignment"))]
[else
(set-var-frm-conf! x
(add-frm fv (var-frm-conf x)))])))))
(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 set-bit 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-ls live-frms2 0)))))])
(assign-frame-vars! vars i)
(NFE (fxsub1 i) (make-mask (fxsub1 i)) body)))]
[(primcall op args)
(case op
[(nop interrupt incr/zero? fl:double->single
fl:single->double) x]
[else (error who "invalid effect prim" op)])]
[(shortcut body handler)
(make-shortcut (E body) (E handler))]
[else (error who "invalid effect" (unparse x))]))
(define (P x)
(struct-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" (unparse x))]))
(define (T x)
(struct-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" (unparse x))]))
(T x))
;;;
(define (Main x)
(struct-case x
[(locals vars body)
(init-vars! vars)
(let ([varvec (list->vector vars)])
(let ([call-live* (uncover-frame-conflicts body varvec)])
(let ([body (rewrite body varvec)])
(make-locals
(cons varvec
(let f ([vars vars])
(cond
[(null? vars) '()]
[(var-loc (car vars)) (f (cdr vars))]
[else (cons (car vars) (f (cdr vars)))])))
body))))]
[else (error 'assign-frame-sizes "invalid main" x)]))
;;;
(define (ClambdaCase x)
(struct-case x
[(clambda-case info body)
(make-clambda-case info (Main body))]))
;;;
(define (Clambda x)
(struct-case x
[(clambda label case* cp free* name)
(make-clambda label (map ClambdaCase case*) cp free* name)]))
;;;
(define (Program x)
(struct-case x
[(codes code* body)
(make-codes (map Clambda code*) (Main body))]))
;;;
(define (assign-frame-sizes x)
(let ([v (Program x)])
v)))
(module (color-by-chaitin)
(import ListySet)
(import ListyGraphs)
;(import IntegerSet)
;(import IntegerGraphs)
;;;
(define (set-for-each f s)
(for-each f (set->list s)))
;;;
(define (build-graph x)
(define who 'build-graph)
(define g (empty-graph))
(define (R* ls)
(cond
[(null? ls) (make-empty-set)]
[else (set-union (R (car ls)) (R* (cdr ls)))]))
(define (R x)
(struct-case x
[(constant) (make-empty-set)]
[(var) (list->set (list x))]
[(disp s0 s1) (set-union (R s0) (R s1))]
[(fvar) (make-empty-set)]
[(code-loc) (make-empty-set)]
[else
(cond
[(symbol? x)
(if (memq x all-registers)
(set-add x (make-empty-set))
(make-empty-set))]
[else (error who "invalid R" x)])]))
;;; build effect
(define (E x s)
(struct-case x
[(asm-instr op d v)
(case op
[(move load32)
(let ([s (set-rem d s)])
(set-for-each (lambda (y) (add-edge! g d y)) s)
(set-union (R v) s))]
[(move-byte)
(let ([s (set-rem d s)])
(set-for-each (lambda (y) (add-edge! g d y)) s)
(when (var? d)
(for-each (lambda (r) (add-edge! g d r)) non-8bit-registers))
(when (var? v)
(for-each (lambda (r) (add-edge! g v r)) non-8bit-registers))
(set-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)))])
(set-for-each (lambda (y) (add-edge! g d y)) s)
(set-union (set-union (R v) (R d)) s))]
[(logand logxor int+ int- int* logor sll sra srl bswap!
sll/overflow)
(let ([s (set-rem d s)])
(set-for-each (lambda (y) (add-edge! g d y)) s)
(set-union (set-union (R v) (R d)) s))]
[(bset/c)
(set-union (set-union (R v) (R d)) s)]
[(bset/h bset)
(when (var? v)
(for-each (lambda (r) (add-edge! g v r))
non-8bit-registers))
(set-union (set-union (R v) (R d)) s)]
[(cltd)
(let ([s (set-rem edx s)])
(when (register? edx)
(set-for-each (lambda (y) (add-edge! g edx y)) s))
(set-union (R eax) s))]
[(idiv)
(let ([s (set-rem eax (set-rem edx s))])
(when (register? eax)
(set-for-each
(lambda (y) (add-edge! g eax y) (add-edge! g edx y))
s))
(set-union (set-union (R eax) (R edx))
(set-union (R v) s)))]
[(mset mset32 fl:load fl:store fl:add! fl:sub! fl:mul! fl:div!
fl:from-int fl:shuffle fl:store-single
fl:load-single)
(set-union (R v) (set-union (R d) s))]
[else (error who "invalid effect" 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)
(set-union (R* args) s)]
[(primcall op arg*)
(case op
[(nop fl:single->double fl:double->single) s]
[(interrupt incr/zero?)
(or (exception-live-set) (error who "uninitialized exception"))]
[else (error who "invalid effect primcall" op)])]
[(shortcut body handler)
(let ([s2 (E handler s)])
(parameterize ([exception-live-set s2])
(E body s)))]
[else (error who "invalid effect" (unparse x))]))
(define (P x st sf su)
(struct-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)
(set-union (set-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" (unparse x))]))
(define (T x)
(struct-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" (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 (set->list (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]))
(set->list confs))])
(let ([r* (set->list
(set-difference
(list->set all-registers)
(list->set 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" x)))
(cond
[(and (empty-set? sp*) (empty-set? un*))
(values '() (make-empty-set) '())]
[(find-low-degree (set->list 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 (set->list 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 (set-add sp sp*)
(cons (cons sp r) env))))))]
[(pair? (set->list sp*))
(let ([sp (car (set->list 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 (set-add sp sp*)
(cons (cons sp r) env))
(values (cons sp spills) sp* env))))))]
[else (error 'color-graph "whoaaa")]))
;;;
(define (substitute env x)
(define who 'substitute)
(define (Var x)
(cond
[(assq x env) => cdr]
[else x]))
(define (Rhs x)
(struct-case x
[(var) (Var x)]
[(primcall op rand*)
(make-primcall op (map Rand rand*))]
[else x]))
(define (Rand x)
(struct-case x
[(var) (Var x)]
[else x]))
(define (Lhs x)
(struct-case x
[(var) (Var x)]
[(nfv confs loc)
(or loc (error who "LHS not set" x))]
[else x]))
(define (D x)
(struct-case x
[(constant) x]
[(var) (Var x)]
[(fvar) x]
[else
(if (symbol? x) x (error who "invalid D" x))]))
(define (R x)
(struct-case x
[(constant) x]
[(var) (Var x)]
[(fvar) x]
[(nfv c loc)
(or loc (error who "unset nfv in R" x))]
[(disp s0 s1) (make-disp (D s0) (D s1))]
[else
(if (symbol? x) x (error who "invalid R" x))]))
;;; substitute effect
(define (E x)
(struct-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" (unparse x))]))
(define (P x)
(struct-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" (unparse x))]))
(define (T x)
(struct-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" (unparse x))]))
;(print-code x)
(T x))
;;;
(define (do-spill sp* varvec)
(import conflict-helpers)
(define (find/set-loc x)
(let f ([i 1] [conf (var-frm-conf x)])
(let ([fv (mkfvar i)])
(cond
[(mem-frm? fv conf) (f (fxadd1 i) conf)]
[else
(for-each-var (var-var-conf x) varvec
(lambda (y)
(set-var-var-conf! y
(rem-var x (var-var-conf y)))
(set-var-frm-conf! y
(add-frm fv (var-frm-conf y)))))
(set-var-loc! x fv)
(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* (set-add 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 (long-imm? x)
(struct-case x
[(constant n)
(cond
[(integer? n)
(not (<= (- (expt 2 31)) n (- (expt 2 31) 1)))]
[else #t])]
[else #f]))
(define (small-operand? x)
(case wordsize
[(4) (not (mem? x))]
[(8)
(struct-case x
[(constant n)
(cond
[(integer? n)
(<= (- (expt 2 31)) n (- (expt 2 31) 1))]
[else #f])]
[else (or (register? x) (var? x))])]
[else (error 'small-operand? "huh?")]))
(define (mem? x)
(or (disp? x) (fvar? x)))
;;; unspillable effect
(define (E x)
(struct-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
move-byte load32
int-/overflow int+/overflow int*/overflow)
(cond
[(and (eq? op 'move) (eq? a b))
(make-primcall 'nop '())]
[(and (= wordsize 8)
(not (eq? op 'move))
(long-imm? b))
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u b))
(E (make-asm-instr op a u))))]
[(and (memq op '(int* int*/overflow)) (mem? a))
(let ([u (mku)])
(make-seq
(make-seq
(E (make-asm-instr 'move u a))
(E (make-asm-instr op u b)))
(E (make-asm-instr 'move a u))))]
[(and (mem? a) (not (small-operand? b)))
(case op
[(load32)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'load32 u b))
(E (make-asm-instr 'move a u))))]
[else
(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
[(not (small-operand? s0))
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s0))
(E (make-asm-instr op (make-disp u s1) b))))]
[(not (small-operand? s1))
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s1))
(E (make-asm-instr op (make-disp s0 u) b))))]
[(small-operand? b) x]
[else
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u b))
(E (make-asm-instr op a u))))]))]
[(disp? b)
(let ([s0 (disp-s0 b)] [s1 (disp-s1 b)])
(cond
[(not (small-operand? s0))
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u s0))
(E (make-asm-instr op a (make-disp u s1)))))]
[(not (small-operand? 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])]
[(bswap!)
(cond
[(mem? b)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u a))
(E (make-asm-instr 'bswap! u u))
(E (make-asm-instr 'move b u))))]
[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" b)]
[else x])]
[(sll sra srl sll/overflow)
(unless (or (constant? b)
(eq? b ecx))
(error who "invalid shift" b))
x]
[(mset mset32 bset bset/c bset/h)
(cond
[(not (small-operand? 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]))])]
[(fl:load fl:store fl:add! fl:sub! fl:mul! fl:div!
fl:load-single fl:store-single)
(cond
[(mem? a)
(let ([u (mku)])
(make-seq
(E (make-asm-instr 'move u a))
(E (make-asm-instr op u b))))]
[else x])]
[(fl:from-int fl:shuffle) x]
[else (error who "invalid effect op" op)])]
[(primcall op rands)
(case op
[(nop interrupt incr/zero? fl:single->double
fl:double->single) x]
[else (error who "invalid op in" (unparse x))])]
[(ntcall) x]
[(shortcut body handler)
(let ([body (E body)])
(make-shortcut body (E handler)))]
[else (error who "invalid effect" (unparse x))]))
(define (P x)
(struct-case x
[(constant) x]
[(conditional e0 e1 e2)
(make-conditional (P e0) (P e