;;; 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
      [(known x t)
       (struct-case x
         [(primref name)
          (if (primop? name)
              (make-primcall name arg*)
              (make-funcall op arg*))]
         [else (make-funcall op arg*)])]
      [(primref name)
       (cond
         [(primop? name)
          (make-primcall name arg*)]
         [else (make-funcall op arg*)])]
      [else (make-funcall op arg*)]))
  ;;;
  (define (A x)
    (struct-case x
      [(known x t) (make-known (Expr x) t)]
      [else (Expr x)]))
  (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 (A rator) (map A arg*))]
      [(jmpcall label rator arg*)
       (make-jmpcall label (Expr rator) (map Expr arg*))]
      [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 (A x)
      (struct-case x
        [(known x t) (make-known (Expr x) t)]
        [else (Expr x)]))
    (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 A arg*))]
        [(forcall op arg*)
         (make-forcall op (map Expr arg*))]
        [(funcall rator arg*)
         (make-funcall (A rator) (map A arg*))]
        [(jmpcall label rator arg*)
         (make-jmpcall label (Expr rator) (map Expr arg*))]
        [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 (known-primref? x)
    (struct-case x
      [(known x t) (known-primref? x)]
      [(primref)   #t]
      [else #f]))
  (define (A x)
    (struct-case x
      [(known x t) (Expr x)]
      [else (Expr x)]))
  (define (Expr x) 
    (struct-case x
      [(constant)                 #f]
      [(var)                      #f]
      [(primref)                  #f]
      [(jmpcall label rator arg*) #t]
      [(funcall rator arg*)
       (if (known-primref? rator) (ormap A 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 A 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 (A x)
    (struct-case x
      [(known x t) (NonTail x)]
      [else (NonTail x)]))
  (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] 
      [(primcall op arg*)     (ormap A arg*)] ;PUNT!!! FIXME!
      [(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))]
      [(forcall op arg*)      (ormap NonTail arg*)]
      [(known x t v) (NonTail x)]
      [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))

(include "pass-specify-rep.ss")

(define parameter-registers '(%edi)) 
(define return-value-register '%eax)
(define cp-register '%edi)
(define all-registers 
  (case wordsize
    [(4) '(%eax %edi %ebx %edx %ecx)]
    [else '(%eax %edi %ebx %edx %ecx %r8 %r9 %r10 %r11 %r14 %r15)]))

(define non-8bit-registers 
  (case wordsize
    [(4) '(%edi)]
    [else '(%edi)]))

(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 (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))]
      [(known x) (S x 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*)
                 (k (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)
    (define (test size)
      (if (struct-case size 
             [(constant i) (<= i 4096)]
             [else #f])
          (make-primcall '<= 
             (list 
               apr
               (make-primcall 'mref 
                 (list pcr (make-constant pcb-allocation-redline)))))
          (make-primcall '>= 
            (list (make-primcall 'int- 
                     (list 
                       (make-primcall 'mref 
                         (list pcr (make-constant pcb-allocation-redline))) 
                       apr))
                  size))))
    (E (make-shortcut
         (make-conditional ;;; PCB ALLOC-REDLINE
           (test size)
           (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 'load8 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))))]
         [(int-quotient)
          (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))))]
         [(int-remainder) 
          (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))] 
      [(known x) (V d x)]
      [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 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)))))]
           [else
            (Mem a
              (lambda (a)
                (Mem b 
                  (lambda (b)
                    (make-asm-instr op a b)))))]))]
         ;(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? singleton
   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 (singleton x)
    (make-set (list x)))
  (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 singleton 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 (singleton n)
    (set-add n (make-empty-set)))
  ;;;
  (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 load8 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))])))] 
         [(nop) (values vs rs fs ns)]
         [(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 
           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 load8 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 
              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) (singleton 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))]
           [(load8)
            (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)
            (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 
                   load8 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
              [(or (var? b) (symbol? b)) x]
              [else 
               (let ([u (mku)])
                 (make-seq
                   (E (make-asm-instr 'move u b))
                   (E (make-asm-instr 'idiv a u))))])]
           [(sll sra srl sll/overflow)
            (unless (or (constant? b)
                        (eq? b ecx))
              (error who "invalid shift" b))
            x]
           [(mset mset32 bset) 
            (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) 
            (check-disp-arg a
              (lambda (a)
                (check-disp-arg b
                  (lambda (b)
                    (make-asm-instr op a b)))))]
           [(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 (check-disp-arg x k)
      (cond
        [(small-operand? x)
         (k x)]
        [else
         (let ([u (mku)])
           (make-seq
             (E (make-asm-instr 'move u x))
             (k u)))]))
    (define (check-disp x k)
      (struct-case x 
        [(disp a b)
         (check-disp-arg a
           (lambda (a)
             (check-disp-arg b
               (lambda (b)
                 (k (make-disp a b))))))]
        [else (k x)]))
    (define (P x)
      (struct-case x
        [(constant) 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
           [(memq op '(fl:= fl:< fl:<= fl:> fl:>=)) 
            (if (mem? a)
                (let ([u (mku)])
                  (make-seq 
                    (E (make-asm-instr 'move u a))
                    (make-asm-instr op u b)))
                x)]
           [(and (not (mem? a)) (not (small-operand? a)))
            (let ([u (mku)])
              (make-seq
                (E (make-asm-instr 'move u a))
                (P (make-asm-instr op u b))))]
           [(and (not (mem? b)) (not (small-operand? b)))
            (let ([u (mku)])
              (make-seq
                (E (make-asm-instr 'move u b))
                (P (make-asm-instr op a u))))]
           [(and (mem? a) (mem? b))
            (let ([u (mku)])
              (make-seq
                (E (make-asm-instr 'move u b))
                (P (make-asm-instr op a u))))]
           [else 
            (check-disp a
              (lambda (a)
                (check-disp b
                  (lambda (b) 
                    (make-asm-instr op a b)))))])]
        [(shortcut body handler)
         (let ([body (P body)])
           (make-shortcut 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))]))
    (let ([x (T x)])
      (values un* x)))
  ;;;
  (define (color-program x)
    (define who 'color-program)
    (struct-case x 
      [(locals vars body)
       (let ([varvec (car vars)] [sp* (cdr vars)])
         (let loop ([sp* (list->set sp*)] [un* (make-empty-set)] [body body])
           (let-values ([(un* body) (add-unspillables un* body)])
             (let ([g (build-graph body)])
               (let-values ([(spills sp* env) (color-graph sp* un* g)])
                 (cond
                   [(null? spills) (substitute env body)]
                   [else 
                    (let* ([env (do-spill spills varvec)]
                           [body (substitute env body)])
                      (loop sp* un* body))]))))))]))
  ;;;
  (define (color-by-chaitin x)
    ;;;
    (define (ClambdaCase x) 
      (struct-case x
        [(clambda-case info body)
         (make-clambda-case info (color-program 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*) (color-program body))]))
    ;;;
    (Program x))
  #|chaitin module|#)



           
(define (compile-call-frame framesize livemask-vec multiarg-rp call-sequence)
  (let ([L_CALL (label (gensym))]
        [padding 
         (- call-instruction-size
            (instruction-size call-sequence))])
    (when (< padding 0) 
      (error 'compile-call-frame "call sequence too long" call-sequence))
    (list 'seq
      (if (or (= framesize 0) (= framesize 1))
          '(seq) 
          `(subl ,(* (fxsub1 framesize) wordsize) ,fpr))
      (jmp L_CALL) 
      `(byte-vector ,livemask-vec)
      `(int ,(* framesize wordsize))
      '(current-frame-offset)
      multiarg-rp
      `(byte-vector ,(make-vector padding 0))
      L_CALL
      call-sequence
      (if (or (= framesize 0) (= framesize 1))
          '(seq) 
          `(addl ,(* (fxsub1 framesize) wordsize) ,fpr)))))
 


(define (flatten-codes x)
  (define who 'flatten-codes)
  ;;;
  (define (FVar i)
    `(disp ,(* i (- wordsize)) ,fpr))
  ;;;
  (define (C x)
    (struct-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" x))]))
  (define (BYTE x)
    (struct-case x
      [(constant x)
       (unless (and (integer? x) (fx<= x 255) (fx<= -128 x))
         (error who "invalid byte" x))
       x]
      [else (error who "invalid byte" x)]))
  (define (D x)
    (struct-case x
      [(constant c) (C c)]
      [else
       (if (symbol? x) x (error who "invalid D" x))]))
  (define (R x)
    (struct-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" x))]))
  (define (R/l x)
    (struct-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) (reg/l x) (error who "invalid R/l" x))])) 
  (define (reg/h x)
    (cond
      [(assq x '([%eax %ah] [%ebx %bh] [%ecx %ch] [%edx %dh]))
       => cadr]
      [else (error who "invalid reg/h" x)]))
  (define (reg/l x)
    (cond
      [(assq x '([%eax %al] [%ebx %bl] [%ecx %cl] [%edx %dl]
                 [%r8 %r8l] [%r9 %r9l] [%r10 %r10l] [%r11 %r11l]
                 [%r12 %r12l] [%r13 %r13l] [%r14 %r14l] [%r15 %r15l]))
       => cadr]
      [else (error who "invalid reg/l" x)])) 
  (define (R/cl x)
    (struct-case x
      [(constant i) 
       (unless (fixnum? i)
         (error who "invalid R/cl" x))
       (fxlogand i (- (* wordsize 8) 1))]
      [else
       (if (eq? x ecx)
           '%cl
           (error who "invalid R/cl" x))]))
  (define (interrupt? x)
    (struct-case x
      [(primcall op args) (eq? op 'interrupt)]
      [else #f]))
  ;;; flatten effect
  (define (E x ac)
    (struct-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 
                  (cons* `(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-mv-error-rp-label))
               (label-address (sl-mv-ignore-rp-label))))
         (cond
           [(string? target) ;; foreign call
            (cons* `(movl (foreign-label "ik_foreign_call") %ebx)
                   (compile-call-frame 
                      size
                      mask
                      (rp-label value)
                      `(call %ebx))
                   ac)]
           [target ;;; known call
            (cons* (compile-call-frame 
                      size
                      mask
                      (rp-label value)
                      `(call (label ,target)))
                   ac)]
           [else
            (cons* (compile-call-frame 
                      size
                      mask
                      (rp-label value)
                      `(call (disp ,(fx- disp-closure-code closure-tag)
                                   ,cp-register)))
                   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))]
         [(load8) 
          (if (eq? d s)
              ac
              (cons `(movb ,(R/l s) ,(R/l d)) ac))]
         [(bset) (cons `(movb ,(R/l 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)]
         [(bswap!) 
          (let ([s (R s)] [d (R d)])
            (unless (eq? s d) (error who "invalid instr" x))
            (cons `(bswap ,s) ac))]
         [(mset32) (cons `(mov32 ,(R s) ,(R d)) ac)]
         [(load32) (cons `(mov32 ,(R s) ,(R d)) ac)]
         [(int-/overflow)
          (let ([L (or (exception-label) 
                       (error who "no exception label"))])
            (cons* `(subl ,(R s) ,(R d)) 
                   `(jo ,L)
                   ac))]
         [(sll/overflow)
          (let ([L (or (exception-label) 
                       (error who "no exception label"))])
            (cons* `(sall ,(R/cl s) ,(R d))
                   `(jo ,L)
                   ac))]
         [(int*/overflow)
          (let ([L (or (exception-label) 
                       (error who "no exception label"))])
            (cons* `(imull ,(R s) ,(R d)) 
                   `(jo ,L)
                   ac))] 
         [(int+/overflow)
          (let ([L (or (exception-label) 
                       (error who "no exception label"))])
            (cons* `(addl ,(R s) ,(R d)) 
                   `(jo ,L)
                   ac))]
         [(fl:store) 
          (cons `(movsd xmm0 ,(R (make-disp s d))) ac)]
         [(fl:store-single) 
          (cons `(movss xmm0 ,(R (make-disp s d))) ac)]
         [(fl:load) 
          (cons `(movsd ,(R (make-disp s d)) xmm0) ac)]
         [(fl:load-single) 
          (cons `(movss ,(R (make-disp s d)) xmm0) ac)]
         [(fl:from-int) 
          (cons `(cvtsi2sd ,(R s) xmm0) ac)]
         [(fl:shuffle) 
          (cons `(pshufb ,(R (make-disp s d)) xmm0) ac)]
         [(fl:add!) 
          (cons `(addsd ,(R (make-disp s d)) xmm0) ac)]
         [(fl:sub!) 
          (cons `(subsd ,(R (make-disp s d)) xmm0) ac)]
         [(fl:mul!) 
          (cons `(mulsd ,(R (make-disp s d)) xmm0) ac)]
         [(fl:div!) 
          (cons `(divsd ,(R (make-disp s d)) xmm0) ac)]
         [else (error who "invalid instr" x)])]
      [(primcall op rands)
       (case op
         [(nop) ac]
         [(interrupt) 
          (let ([l (or (exception-label)
                       (error who "no exception label"))])
            (cons `(jmp ,l) ac))]
         [(incr/zero?) 
          (let ([l (or (exception-label)
                       (error who "no exception label"))])
            (cons* 
              `(addl ,(D (caddr rands)) ,(R (make-disp (car rands) (cadr rands))))
              `(je ,l)
              ac))]
         [(fl:double->single)
          (cons '(cvtsd2ss xmm0 xmm0) ac)]
         [(fl:single->double)
          (cons '(cvtss2sd xmm0 xmm0) ac)]
         [else (error who "invalid effect" (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))))]
      [else (error who "invalid effect" (unparse x))]))
  ;;;
  (define (unique-interrupt-label)
    (label (gensym "ERROR")))
  (define (unique-label)
    (label (gensym)))
  ;;;
  (define (constant=? x k)
    (struct-case x 
      [(constant k0) (equal? k0 k)]
      [else #f]))
  ;;;
  (define (P x lt lf ac)
    (struct-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 (constant=? e1 #t) (constant=? e2 #f))
          (P e0 lt lf ac)]
         [(and (constant=? e1 #f) (constant=? e2 #t))
          (P e0 lf lt ac)]
         [(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<]
                        [fl:= fl:o!=] [fl:!= fl:o=] 
                        [fl:< fl:o>=] [fl:<= fl:o>] 
                        [fl:> fl:o<=] [fl:>= fl:o<]
                        ))
              => cadr]
             [else (error who "invalid notop" x)]))
         (define (jmpname x)
           (cond
             [(assq x '([= je] [!= jne] [< jl] [<= jle] [> jg] [>= jge]
                        [u< jb] [u<= jbe] [u> ja] [u>= jae]
                        [fl:= je] [fl:!= jne]
                        [fl:< jb] [fl:> ja] [fl:<= jbe] [fl:>= jae]
                        [fl:o= je] [fl:o!= jne]
                        [fl:o< jb] [fl:o> ja] [fl:o<= jbe] [fl:o>= jae]
                        ))
              => cadr]
             [else (error who "invalid jmpname" 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" x)]))
         (define (cmp op a0 a1 lab ac)
           (cond
             [(memq op '(fl:= fl:!= fl:< fl:<= fl:> fl:>=))
              (cons* `(ucomisd ,(R (make-disp a0 a1)) xmm0)
                     `(,(jmpname op) ,lab)
                     ;;; BOGUS!
                     ac)]
             [(memq op '(fl:o= fl:o!= fl:o< fl:o<= fl:o> fl:o>=))
              (cons* `(ucomisd ,(R (make-disp a0 a1)) xmm0)
                     `(jp ,lab)
                     `(,(jmpname op) ,lab)
                     ac)]
             [(or (symbol? a0) (constant? a1))
              (cons* `(cmpl ,(R a1) ,(R a0))
                     `(,(jmpname op) ,lab)
                     ac)]
             [(or (symbol? a1) (constant? a0))
              (cons* `(cmpl ,(R a0) ,(R a1))
                     `(,(revjmpname op) ,lab)
                     ac)]
             [else (error who "invalid cmpops" 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" x)]))
  ;;;
  (define (T x ac)
    (struct-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" 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" 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))
    (cons* (cmpl (int (argc-convention (fxsub1 fml-count))) eax)
           (jl CONS_LABEL)
           (movl (int nil) ebx)
           (jmp DONE_LABEL)
           CONS_LABEL
           (movl (mem pcb-allocation-redline pcr) 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 (obj (primref->symbol 'do-vararg-overflow)) cpr)
           (movl (mem (- disp-symbol-record-proc record-tag) cpr) cpr)
           ;(movl (primref-loc 'do-vararg-overflow) cpr) ; load handler
           (compile-call-frame 0 '#() '(int 0) (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) 
    (struct-case x
      [(clambda-case info body)
       (struct-case info
         [(case-info L args proper)
          (let ([lothers (unique-label)])
            (cons* `(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)
    (struct-case x
      [(clambda L case* cp free* name)
       (cons* (length free*) 
              `(name ,name)
              (label L)
          (let ([ac (list '(nop))])
            (parameterize ([exceptions-conc ac])
              (let f ([case* case*])
                (cond
                  [(null? case*) 
                   (cons `(jmp (label ,(sl-invalid-args-label))) ac)]
                  [else
                   (ClambdaCase (car case*) (f (cdr case*)))])))))]))
  ;;;
  (define exceptions-conc (make-parameter #f))
  ;;;
  (define (Program x)
    (struct-case x 
      [(codes code* body)
       (cons (cons* 0 
                    (label (gensym))
                    (let ([ac (list '(nop))])
                      (parameterize ([exceptions-conc ac])
                        (T body ac))))
             (map Clambda code*))]))
  (Program x))

(define (print-code x)
  (parameterize ([print-gensym '#t])
    (pretty-print (unparse x))))

(define (alt-cogen x)
  (define (time-it name proc)
    (proc))
  (let* ([x (introduce-primcalls x)]
         [x (eliminate-fix x)]
         [x (insert-engine-checks x)]
         [x (insert-stack-overflow-check x)]
         [x (specify-representation x)]
         [x (impose-calling-convention/evaluation-order x)]
         [x (time-it "frame" (lambda () (assign-frame-sizes x)))]
         [x (time-it "register" (lambda () (color-by-chaitin x)))]
         [ls (flatten-codes x)])
    ls))
  

#|module alt-cogen|#)