;;; np-languages.ss ;;; Copyright 1984-2017 Cisco Systems, Inc. ;;; ;;; Licensed under the Apache License, Version 2.0 (the "License"); ;;; you may not use this file except in compliance with the License. ;;; You may obtain a copy of the License at ;;; ;;; http://www.apache.org/licenses/LICENSE-2.0 ;;; ;;; Unless required by applicable law or agreed to in writing, software ;;; distributed under the License is distributed on an "AS IS" BASIS, ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ;;; See the License for the specific language governing permissions and ;;; limitations under the License. #!chezscheme (module np-languages () (export sorry! var? var-index var-index-set! prelex->uvar make-tmp make-assigned-tmp make-unspillable make-cpvar make-restricted-unspillable uvar? uvar-name uvar-type uvar-source uvar-referenced? uvar-referenced! uvar-assigned? uvar-assigned! uvar-was-closure-ref? uvar-was-closure-ref! uvar-unspillable? uvar-spilled? uvar-spilled! uvar-local-save? uvar-local-save! uvar-seen? uvar-seen! uvar-loop? uvar-loop! uvar-poison? uvar-poison! uvar-in-prefix? uvar-in-prefix! uvar-location uvar-location-set! uvar-move* uvar-move*-set! uvar-conflict* uvar-ref-weight uvar-ref-weight-set! uvar-save-weight uvar-save-weight-set! uvar-live-count uvar-live-count-set! uvar fv-offset var-spillable-conflict* var-spillable-conflict*-set! var-unspillable-conflict* var-unspillable-conflict*-set! uvar-degree uvar-degree-set! uvar-info-lambda uvar-info-lambda-set! uvar-iii uvar-iii-set! ur? block make-block block? block-label block-effect* block-src* block-pseudo-src block-in-link* block-flags block-label-set! block-effect*-set! block-src*-set! block-pseudo-src-set! block-in-link*-set! block-flags-set! block-live-in block-live-in-set! block-fp-offset block-fp-offset-set! block-depth block-depth-set! block-loop-headers block-loop-headers-set! block-weight block-weight-set! block-index block-index-set! block-pariah! block-seen! block-finished! block-return-point! block-repeater! block-loop-header! block-pariah? block-seen? block-finished? block-return-point? block-repeater? block-loop-header? L1 unparse-L1 L2 unparse-L2 L3 unparse-L3 L4 unparse-L4 L4.5 unparse-L4.5 L4.75 unparse-L4.75 L4.875 unparse-L4.875 L5 unparse-L5 L6 unparse-L6 L7 unparse-L7 L9 unparse-L9 L9.5 unparse-L9.5 L9.75 unparse-L9.75 L10 unparse-L10 L10.5 unparse-L10.5 L11 unparse-L11 L11.5 unparse-L11.5 L12 unparse-L12 L13 unparse-L13 L13.5 unparse-L13.5 L14 unparse-L14 L15a unparse-L15a L15b unparse-L15b L15c unparse-L15c L15d unparse-L15d L15e unparse-L15e L16 unparse-L16 info null-info live-info make-live-info live-info-live live-info-live-set! live-info-useless live-info-useless-set! primitive-pure? primitive-type primitive-handler primitive-handler-set! %primitive value-primitive? pred-primitive? effect-primitive? fv? $make-fv make-reg reg? reg-name reg-tc-disp reg-callee-save? reg-mdinfo reg-precolored reg-precolored-set! label? label-name libspec-label? make-libspec-label libspec-label-libspec libspec-label-live-reg* local-label? make-local-label local-label-func local-label-func-set! local-label-offset local-label-offset-set! local-label-iteration local-label-iteration-set! local-label-block local-label-block-set! local-label-overflow-check local-label-overflow-check-set! local-label-trap-check local-label-trap-check-set! direct-call-label? make-direct-call-label direct-call-label-referenced direct-call-label-referenced-set! Lsrc Lsrc? Ltype Ltype? unparse-Ltype unparse-Lsrc lookup-primref primref? primref-level primref-name primref-flags primref-arity preinfo-src preinfo-sexpr preinfo-lambda-name preinfo-lambda-flags preinfo-lambda-libspec prelex-name prelex-name-set!) (import (nanopass)) (include "base-lang.ss") ; r6rs says a quote subform should be a datum, not must be a datum ; chez scheme allows a quote subform to be any value (define datum? (lambda (x) #t)) (define-record-type var (fields (mutable index) (mutable spillable-conflict*) (mutable unspillable-conflict*)) (nongenerative) (protocol (lambda (new) (lambda () (new #f #f #f))))) (define-record-type (fv $make-fv fv?) (parent var) (fields offset) (nongenerative) (sealed #t) (protocol (lambda (pargs->new) (lambda (offset) ((pargs->new) offset))))) (module () (record-writer (record-type-descriptor fv) (lambda (x p wr) (fprintf p "fv~s" (fv-offset x))))) (define-record-type reg (parent var) (fields name mdinfo tc-disp callee-save? (mutable precolored)) (nongenerative) (sealed #t) (protocol (lambda (pargs->new) (lambda (name mdinfo tc-disp callee-save?) ((pargs->new) name mdinfo tc-disp callee-save? #f))))) (module () (record-writer (record-type-descriptor reg) (lambda (x p wr) (write (reg-name x) p)))) (define-syntax define-flag-field (lambda (exp) (syntax-case exp () ((_k type-name field (flag mask) ...) (let () (define getter-name (lambda (f) (construct-name #'_k #'type-name "-" f "?"))) (define setter-name (lambda (f) (construct-name #'_k #'type-name "-" f "!"))) (with-syntax ([field-ref (construct-name #'_k #'type-name "-" #'field)] [field-set! (construct-name #'_k #'type-name "-" #'field "-set!")] [(flag-ref ...) (map getter-name #'(flag ...))] [(flag-set! ...) (map setter-name #'(flag ...))] [f->m (construct-name #'_k #'type-name "-" #'field "-mask")]) #'(begin (define-flags f->m (flag mask) ...) (define flag-ref (lambda (x) (any-set? (f->m flag) (field-ref x)))) ... (define flag-set! (lambda (x bool) (field-set! x (let ([flags (field-ref x)]) (if bool (set-flags (f->m flag) flags) (reset-flags (f->m flag) flags)))))) ...))))))) (define-flag-field uvar flags (referenced #b00000000001) (assigned #b00000000010) (unspillable #b00000000100) (spilled #b00000001000) (seen #b00000010000) (was-closure-ref #b00000100000) (loop #b00001000000) (in-prefix #b00010000000) (local-save #b00100000000) (poison #b01000000000) ) (define-record-type (uvar $make-uvar uvar?) (parent var) (fields name source type conflict* (mutable flags) (mutable info-lambda) (mutable location) (mutable move*) (mutable degree) (mutable iii) ; inspector info index (mutable ref-weight) ; must be a fixnum! (mutable save-weight) ; must be a fixnum! (mutable live-count) ; must be a fixnum! ) (nongenerative) (sealed #t) (protocol (lambda (pargs->new) (lambda (name source type conflict* flags) ((pargs->new) name source type conflict* flags #f #f '() #f #f 0 0 0))))) (define prelex->uvar (lambda (x) ($make-uvar (prelex-name x) (prelex-source x) 'ptr '() (if (prelex-referenced x) (if (prelex-assigned x) (uvar-flags-mask referenced assigned) (uvar-flags-mask referenced)) (if (prelex-assigned x) (uvar-flags-mask assigned) (uvar-flags-mask)))))) (define make-tmp (case-lambda [(name) (make-tmp name 'ptr)] [(name type) ($make-uvar name #f type '() (uvar-flags-mask referenced))])) (define make-assigned-tmp (case-lambda [(name) (make-assigned-tmp name 'ptr)] [(name type) ($make-uvar name #f type '() (uvar-flags-mask referenced assigned))])) (define make-unspillable (lambda (name) ($make-uvar name #f 'ptr '() (uvar-flags-mask referenced unspillable)))) (define make-cpvar (lambda () (include "types.ss") ;; NB: cpsymbol is not a source object. Why is it put into the uvar-source field? ($make-uvar 'cp cpsymbol 'ptr '() (uvar-flags-mask referenced)))) (define make-restricted-unspillable (lambda (name conflict*) ($make-uvar name #f 'uptr conflict* (uvar-flags-mask referenced assigned unspillable)))) (module () (record-writer (record-type-descriptor uvar) (lambda (x p wr) (write (lookup-unique-uvar x) p)))) (define lookup-unique-uvar (let ([ht (make-eq-hashtable)]) (lambda (x) (or (eq-hashtable-ref ht x #f) (let ([sym (gensym (symbol->string (uvar-name x)))]) (eq-hashtable-set! ht x sym) sym))))) (define-record-type info (nongenerative)) (define null-info (make-info)) (module () (record-writer (record-type-descriptor info) (lambda (x p wr) (fprintf p "#")))) (define-record-type label (nongenerative) (fields name)) (define-record-type libspec-label (parent label) (nongenerative) (sealed #t) (fields libspec live-reg*) (protocol (lambda (pargs->new) (lambda (name libspec live-reg*) ((pargs->new name) libspec live-reg*))))) ; TODO: need better abstraction for reusing record fields for ; different purposes in different passes. (define-record-type local-label (parent label) (nongenerative) (fields (mutable func) (mutable offset) (mutable iteration) (mutable block) ; following used by place-overflow-and-trap-check pass (mutable overflow-check) (mutable trap-check)) (protocol (lambda (pargs->new) (lambda (name) ((pargs->new name) #f #f #f #f 'no 'no))))) (define-record-type direct-call-label (parent local-label) (nongenerative) (sealed #t) (fields (mutable referenced)) (protocol (lambda (pargs->new) (lambda (name) ((pargs->new name) #f))))) (module () (define lookup-unique-label (let ([ht (make-eq-hashtable)]) (lambda (x) (or (eq-hashtable-ref ht x #f) (let ([sym (gensym (symbol->string (label-name x)))]) (eq-hashtable-set! ht x sym) sym))))) (record-writer (record-type-descriptor local-label) (lambda (x p wr) (write (lookup-unique-label x) p))) (record-writer (record-type-descriptor libspec-label) (lambda (x p wr) (write (label-name x) p)))) (define maybe-var? (lambda (x) (or (eq? x #f) (var? x)))) (define maybe-label? (lambda (x) (or (eq? x #f) (label? x)))) ; language to replace prelex with uvar, create info records out of some of the complex ; records, and make sure other record types have been discarded. also formally sets up ; CaseLambdaClause as entry point for language. (define-language L1 (terminals (uvar (x)) (datum (d)) (source-object (src)) (info (info)) (fixnum (interface)) (primref (pr)) ) (entry CaseLambdaExpr) (Expr (e body) le x pr (quote d) (call info e0 e1 ...) => (e0 e1 ...) (if e0 e1 e2) (seq e0 e1) (set! x e) (letrec ([x le] ...) body) (moi) => "moi" (foreign info e) (fcallable info e) (profile src) => (profile) (pariah) ) (CaseLambdaExpr (le) (case-lambda info cl ...) => (case-lambda cl ...) ) (CaseLambdaClause (cl) (clause (x* ...) interface body) )) ; from this point on, if a uvar x is bound to a lambda expression le by letrec, ; (uvar-info-lambda x) must be equal to le's info-lambda ; introducing let (define-language L2 (extends L1) (entry CaseLambdaExpr) (Expr (e body) (+ (let ([x e] ...) body)))) ; removes moi; also adds name to info-lambda & info-foreign (define-language L3 (extends L2) (entry CaseLambdaExpr) (Expr (e body) (- (moi)))) ; removes assignable indefinite-extent variables from the language (define-language L4 (extends L3) (entry CaseLambdaExpr) (Expr (e body) (- (set! x e)))) ; introducing mvlet, and mvcall (define-language L4.5 (extends L4) (terminals (+ (maybe-label (mdcl)))) (entry CaseLambdaExpr) (Expr (e body) (- (call info e0 e1 ...)) (+ (call info mdcl e0 e1 ...) => (call mdcl e0 e1 ...) (mvcall info e1 e2) => (mvcall e1 e2) (mvlet e ((x** ...) interface* body*) ...)))) ; removes foreign, adds foreign-call, updates fcallable (define-language L4.75 (extends L4.5) (entry CaseLambdaExpr) (terminals (+ (label (l)))) (Expr (e body) (- (foreign info e) (fcallable info e)) (+ (label l body) (foreign-call info e e* ...) (fcallable info)))) ; adds loop form (define-language L4.875 (extends L4.75) (entry CaseLambdaExpr) (Expr (e body) (+ (loop x (x* ...) body) => (loop x body)))) ; moves all case lambda expressions into rhs of letrec (define-language L5 (extends L4.875) (entry CaseLambdaExpr) (Expr (e body) (- le))) ; replaces letrec with labels and closures forms (define-language L6 (extends L5) (terminals (+ (maybe-var (mcp)))) (entry CaseLambdaExpr) (Expr (e body) (- (letrec ([x le] ...) body)) (+ (closures ([x* (x** ...) le*] ...) body))) (CaseLambdaClause (cl) (- (clause (x* ...) interface body)) (+ (clause (x* ...) mcp interface body)))) ; move labels to top level and expands closures forms to more primitive operations (define-language L7 (extends L6) (terminals (- (uvar (x)) (fixnum (interface))) (+ (var (x)) (primitive (prim)) ; moved up one language to support closure instrumentation (fixnum (interface offset)) (immediate (imm)))) (entry Program) (Program (prog) (+ (labels ([l* le*] ...) l) => (labels ([l* le*] ...) (l)))) (CaseLambdaExpr (le) (+ (fcallable info l) => (fcallable info l))) (Lvalue (lvalue) (+ x (mref e1 e2 imm))) (Expr (e body) (- x (fcallable info) (closures ([x* (x** ...) le*] ...) body) (call info mdcl e0 e1 ...)) (+ lvalue (alloc info e) => (alloc info e) (literal info) => info (label-ref l offset) (immediate imm) => imm ; moved up one language to support closure instrumentation (inline info prim e* ...) => (inline info prim e* ...) (call info mdcl (maybe e0) e1 ...) => (call mdcl e0 e1 ...) (set! lvalue e) ; these two forms are added here so expand-inline handlers can expand into them (values info e* ...) (goto l)))) (define-record-type primitive (fields name type pure? (mutable handler)) (nongenerative) (sealed #t) (protocol (lambda (new) (lambda (name type pure?) (new name type pure? (lambda args (sorry! name "no primitive handler defined"))))))) (module () (record-writer (record-type-descriptor primitive) (lambda (x p wr) (fprintf p "~s" (primitive-name x))))) (define value-primitive? (lambda (x) (and (primitive? x) (eq? (primitive-type x) 'value)))) (define pred-primitive? (lambda (x) (and (primitive? x) (eq? (primitive-type x) 'pred)))) (define effect-primitive? (lambda (x) (and (primitive? x) (eq? (primitive-type x) 'effect)))) (define-syntax declare-primitive (lambda (x) (syntax-case x () [(_ name type pure?) (with-syntax ([%name (construct-name #'name "%" #'name)]) #'(begin (define %name (make-primitive 'name 'type pure?)) (export %name)))]))) (define-syntax %primitive (lambda (x) (syntax-case x () [(_ name) (let ([a (syntax->annotation #'name)] [sym (string->symbol (format "%~a" (datum name)))]) (datum->syntax #'name (if a (make-annotation sym (annotation-source a) sym) sym)))]))) (declare-primitive asmlibcall! effect #f) (declare-primitive c-call effect #f) (declare-primitive c-simple-call effect #f) (declare-primitive c-simple-return effect #f) (declare-primitive deactivate-thread effect #f) ; threaded version only (declare-primitive fl* effect #f) (declare-primitive fl+ effect #f) (declare-primitive fl- effect #f) (declare-primitive fl/ effect #f) (declare-primitive fldl effect #f) ; x86 (declare-primitive flds effect #f) ; x86 (declare-primitive flsqrt effect #f) ; not implemented for some ppc32 (so we don't use it) (declare-primitive flt effect #f) (declare-primitive inc-cc-counter effect #f) (declare-primitive inc-profile-counter effect #f) (declare-primitive invoke-prelude effect #f) (declare-primitive keep-live effect #f) (declare-primitive load-double effect #f) (declare-primitive load-double->single effect #f) (declare-primitive load-single effect #f) (declare-primitive load-single->double effect #f) (declare-primitive locked-decr! effect #f) (declare-primitive locked-incr! effect #f) (declare-primitive pause effect #f) (declare-primitive push effect #f) (declare-primitive pop-multiple effect #f) ; arm (declare-primitive push-multiple effect #f) ; arm (declare-primitive remember effect #f) (declare-primitive restore-flrv effect #f) (declare-primitive restore-lr effect #f) ; ppc (declare-primitive save-flrv effect #f) (declare-primitive save-lr effect #f) ; ppc (declare-primitive store effect #f) (declare-primitive store-double effect #f) (declare-primitive store-single effect #f) (declare-primitive store-single->double effect #f) (declare-primitive store-with-update effect #f) ; ppc (declare-primitive unactivate-thread effect #f) ; threaded version only (declare-primitive vpush-multiple effect #f) ; arm (declare-primitive vpop-multiple effect #f) ; arm (declare-primitive cas effect #f) (declare-primitive < pred #t) (declare-primitive <= pred #t) (declare-primitive > pred #t) (declare-primitive >= pred #t) (declare-primitive condition-code pred #t) (declare-primitive eq? pred #t) (declare-primitive fl< pred #t) (declare-primitive fl<= pred #t) (declare-primitive fl= pred #t) (declare-primitive lock! pred #f) (declare-primitive logtest pred #t) (declare-primitive log!test pred #t) (declare-primitive type-check? pred #t) (declare-primitive u< pred #t) (declare-primitive - value #t) (declare-primitive / value #t) (declare-primitive + value #t) (declare-primitive +/ovfl value #f) (declare-primitive +/carry value #f) (declare-primitive -/ovfl value #f) (declare-primitive -/eq value #f) (declare-primitive asmlibcall value #f) (declare-primitive fstpl value #f) ; x86 only (declare-primitive fstps value #f) ; x86 only (declare-primitive get-double value #t) ; x86_64 (declare-primitive get-tc value #f) ; threaded version only (declare-primitive activate-thread value #f) ; threaded version only (declare-primitive lea1 value #t) (declare-primitive lea2 value #t) (declare-primitive load value #t) (declare-primitive logand value #t) (declare-primitive logor value #t) (declare-primitive logxor value #t) (declare-primitive lognot value #t) (declare-primitive move value #t) (declare-primitive * value #t) (declare-primitive */ovfl value #f) (declare-primitive pop value #f) (declare-primitive read-performance-monitoring-counter value #t) ; on x86/x86_64 actually side-effects edx/rdx (declare-primitive read-time-stamp-counter value #t) ; on x86/x86_64 actually side-effects edx/rdx (declare-primitive sext8 value #t) (declare-primitive sext16 value #t) (declare-primitive sext32 value #t) ; 64-bit only (declare-primitive sll value #t) (declare-primitive srl value #t) (declare-primitive sra value #t) (declare-primitive trunc value #t) (declare-primitive zext8 value #t) (declare-primitive zext16 value #t) (declare-primitive zext32 value #t) ; 64-bit only (define immediate? (let ([low (- (bitwise-arithmetic-shift-left 1 (fx- (constant ptr-bits) 1)))] [high (- (bitwise-arithmetic-shift-left 1 (constant ptr-bits)) 1)]) (if (and (eqv? (constant most-negative-fixnum) (most-negative-fixnum)) (eqv? (constant most-positive-fixnum) (most-positive-fixnum))) (lambda (x) (or (fixnum? x) (and (bignum? x) (<= low x high)))) (lambda (x) (and (or (fixnum? x) (bignum? x)) (<= low x high)))))) (define imm->ptr (lambda (x) (cond [(= x (constant sfalse)) #f] [(= x (constant strue)) #t] [(= x (constant svoid)) (void)] [(= x (constant snil)) '()] [(= x (constant seof)) #!eof] [(= x (constant sunbound)) ($unbound-object)] [(= x (constant sbwp)) #!bwp] [(= (logand x (constant mask-fixnum)) (constant type-fixnum)) (ash (- x (constant type-fixnum)) (- (constant fixnum-offset)))] [(= (logand x (constant mask-char)) (constant type-char)) (integer->char (/ (- x (constant type-char)) (constant char-factor)))] [else ($oops 'cpnanopass-internal "imm->ptr got unrecognized immediate: ~s" x)]))) ; specifies the representation for simple scheme constants: #t, #f, (void), ; '(), (eof-object), ($unbound-object), #!bwp, characters, and fixnums as ; scheme-object ptrs and inlines primitive calls (define-language L9 (extends L7) (entry Program) (terminals (- (datum (d)) (primref (pr))) (+ (symbol (sym)))) (CaseLambdaExpr (le) (+ (hand-coded sym))) (Expr (e body) (- (quote d) pr))) ; determine where we should be placing interrupt and overflow (define-language L9.5 (extends L9) (entry Program) (terminals (+ (boolean (ioc)))) (Expr (e body) (+ (trap-check ioc e) (overflow-check e)))) ; remove the loop form (define-language L9.75 (extends L9.5) (entry Program) (Expr (e body) (- (loop x (x* ...) body)))) ; bindings are replaced with combination of a locals form and a series of set! ; expressions; value is broken into three categories: Triv, Rhs, and Expr. Triv ; expressions can appear as arguments to call and inline, or in any Rhs or Tail ; location, and are considered simple enough for the instruction selector to handle. ; Rhs expressions can appear on the right-hand-side of a set! or anywhere arbitrary ; Exprs can appear. Exprs appear in the body of a case-lambda clause. (define-language L10 (extends L9.75) (terminals (+ (uvar (local)))) (entry Program) (CaseLambdaClause (cl) (- (clause (x* ...) mcp interface body)) (+ (clause (x* ...) (local* ...) mcp interface body))) (Lvalue (lvalue) (- (mref e1 e2 imm)) (+ (mref x1 x2 imm))) (Triv (t) (+ lvalue (literal info) => info (immediate imm) => (quote imm) (label-ref l offset))) (Rhs (rhs) (+ t (call info mdcl (maybe t0) t1 ...) => (call mdcl t0 t1 ...) (alloc info t) => (alloc info t) (inline info prim t* ...) => (inline info prim t* ...) (mvcall info e t) => (mvcall e t) (foreign-call info t t* ...))) (Expr (e body) (- lvalue (values info e* ...) (literal info) (immediate imm) (label-ref l offset) (call info mdcl (maybe e0) e1 ...) (inline info prim e* ...) (alloc info e) (let ([x e] ...) body) (set! lvalue e) (mvcall info e1 e2) (foreign-call info e e* ...)) (+ rhs (values info t* ...) (set! lvalue rhs)))) (define-language L10.5 (extends L10) (entry Program) (Rhs (rhs) (- (call info mdcl (maybe t0) t1 ...) (mvcall info e t)) (+ (mvcall info mdcl (maybe t0) t1 ... (t* ...)) => (mvcall mdcl t0 t1 ... (t* ...)))) (Expr (e body) (- (mvlet e ((x** ...) interface* body*) ...)) (+ (mvset info (mdcl (maybe t0) t1 ...) (t* ...) ((x** ...) interface* l*) ...) => (mvset (mdcl t0 t1 ...) (t* ...) ((x** ...) interface* l*) ...) (mlabel e (l* e*) ...)))) ; expressions are normalized into Tail, Pred, or Effect context; primrefs ; are converted into inline expressions; make-closure, ; closure-ref, and closure-set! are converted into inline calls; numbers and ; labels used as arguments to make-closure, closure-ref, and closure-set! are ; marked as literals so they will not be turned into scheme constants again. (define-language L11 (extends L10.5) (terminals (- (primitive (prim))) (+ (value-primitive (value-prim)) (pred-primitive (pred-prim)) (effect-primitive (effect-prim)))) (entry Program) (CaseLambdaClause (cl) (- (clause (x* ...) (local* ...) mcp interface body)) (+ (clause (x* ...) (local* ...) mcp interface tlbody))) (Rhs (rhs) (- (inline info prim t* ...)) (+ (inline info value-prim t* ...) => (inline info value-prim t* ...))) (Expr (e body) (- rhs (label l body) (set! lvalue rhs) (if e0 e1 e2) (seq e0 e1) (mvset info (mdcl (maybe t0) t1 ...) (t* ...) ((x** ...) interface* l*) ...) (values info t* ...) (goto l) (mlabel e (l* e*) ...) (pariah) (trap-check ioc e) (overflow-check e) (profile src))) (Tail (tl tlbody) (+ rhs (if p0 tl1 tl2) (seq e0 tl1) (values info t* ...) => (values t* ...) (goto l))) (Pred (p pbody) (+ (true) => #t (false) => #f (inline info pred-prim t* ...) => (inline info pred-prim t* ...) (if p0 p1 p2) (seq e0 p1) (goto l) (mlabel p (l* p*) ...))) (Effect (e ebody) (+ (nop) (label l) (goto l) (pariah) (trap-check ioc) (overflow-check) (profile src) => (profile) (set! lvalue rhs) (inline info effect-prim t* ...) => (inline info effect-prim t* ...) (if p0 e1 e2) (seq e0 e1) (mvset info (mdcl (maybe t0) t1 ...) (t* ...) ((x** ...) interface* l*) ...) => (mvset (mdcl t0 t1 ...) (t* ...) ((x** ...) interface* l*) ...) (mvcall info mdcl (maybe t0) t1 ... (t* ...)) => (mvcall mdcl t0 t1 ... (t* ...)) (foreign-call info t t* ...) (tail tl)))) (define-language L11.5 (extends L11) (entry Program) (terminals (- (boolean (ioc)))) (Effect (e body) (- (trap-check ioc)))) (define-language L12 (extends L11.5) (terminals (- (fixnum (interface offset)) (label (l))) (+ (fixnum (fixed-args offset)) (label (l dcl)))) (entry Program) (CaseLambdaExpr (le) (- (case-lambda info cl ...)) (+ (lambda info (local* ...) tlbody) => (lambda (local* ...) tlbody))) (CaseLambdaClause (cl) (- (clause (x* ...) (local* ...) mcp interface tlbody))) (Tail (tl tlbody) (+ (entry-point (x* ...) dcl mcp tlbody))) (Effect (e ebody) (- (mvset info (mdcl (maybe t0) t1 ...) (t* ...) ((x** ...) interface* l*) ...)) (+ (do-rest fixed-args) (mvset info (mdcl (maybe t0) t1 ...) (t* ...) ((x** ...) ...) ebody) ; mventry-point and mverror-point can appear only within an mvset ebody ; ideally, grammar would reflect this (mventry-point (x* ...) l) (mverror-point)))) (define exact-integer? (lambda (x) (and (integer? x) (exact? x)))) ; calling conventions are imposed; clauses no longer have formals (they are ; now locals set by arguments from argument registers and frame); calls no ; longer have arguments; case-lambda is responsible for dispatching to correct ; clause, even when the game is being played (define-language L13 (terminals (fixnum (max-fv offset)) (fv (fv)) (reg (reg)) (var (x nfv cnfv var)) (uvar (local)) (effect-primitive (effect-prim)) (pred-primitive (pred-prim)) (value-primitive (value-prim)) (immediate (imm fs)) (exact-integer (lpm)) (info (info)) (maybe-label (mrvl)) (label (l rpl)) (source-object (src)) (symbol (sym))) (Program (prog) (labels ([l* le*] ...) l) => (letrec ([l* le*] ...) (l))) (CaseLambdaExpr (le) (lambda info max-fv (local* ...) tlbody) => (lambda (local* ...) tlbody) (hand-coded sym)) (Lvalue (lvalue) x (mref x1 x2 imm)) (Triv (t) lvalue (literal info) => info (immediate imm) => imm (label-ref l offset)) (Rhs (rhs) t (alloc info t) => (alloc info t) (inline info value-prim t* ...) => (inline info value-prim t* ...)) (Pred (p pbody) (inline info pred-prim t* ...) => (inline info pred-prim t* ...) (true) (false) (if p0 p1 p2) (seq e0 p1) (goto l) (mlabel p (l* p*) ...)) (Effect (e ebody) (overflow-check) (overflood-check) (fcallable-overflow-check) (new-frame info rpl* ... rpl) (return-point info rpl mrvl (cnfv* ...)) (rp-header mrvl fs lpm) (remove-frame info) (restore-local-saves info) (shift-arg reg imm info) (set! lvalue rhs) (inline info effect-prim t* ...) => (inline info effect-prim t* ...) (nop) (pariah) (if p0 e1 e2) (seq e0 e1) (label l) (goto l) (tail tl) (profile src) => (profile) (check-live reg* ...)) (Tail (tl tlbody) (jump t (var* ...)) (joto l (nfv* ...)) (asm-return reg* ...) (asm-c-return info reg* ...) (if p0 tl1 tl2) (seq e0 tl1) (goto l))) (define-language L13.5 (extends L13) (terminals (- (symbol (sym)))) (entry Program) (CaseLambdaExpr (le) (- (hand-coded sym)))) (define-language L14 (extends L13.5) (entry Program) (Rhs (rhs) (- (alloc info t)))) (define-record-type block (fields (mutable label) (mutable effect*) (mutable src*) (mutable pseudo-src) (mutable in-link*) (mutable flags) (mutable fp-offset) (mutable live-in) (mutable depth) (mutable loop-headers) (mutable index) (mutable weight)) (nongenerative) (protocol (lambda (new) (lambda () (new #f '() '() #f '() (block-flags-mask) #f 'uninitialized 0 #f #f #f))))) (define-flag-field block flags (pariah #b000001) (seen #b000010) (finished #b000100) (return-point #b001000) (repeater #b010000) (loop-header #b100000)) (define-record-type live-info (nongenerative) (sealed #t) (fields (mutable live) (mutable useless)) (protocol (lambda (new) (case-lambda [() (new 'uninitialized #f)] [(live) (new live #f)])))) (module () (record-writer (record-type-descriptor live-info) (lambda (x p wr) (if (eq? (live-info-live x) 'uninitialized) (display-string "#" p) (fprintf p "#" (live-info-live x)))))) (define-language L15a (terminals (var (x cnfv var)) (reg (reg)) (uvar (local)) (effect-primitive (effect-prim)) (pred-primitive (pred-prim)) (value-primitive (value-prim)) (immediate (imm fs)) (exact-integer (lpm)) (live-info (live-info)) (info (info)) (label (l rpl)) (maybe-label (mrvl)) (fixnum (max-fv offset)) (block (block entry-block))) (Program (pgm) (labels ([l* le*] ...) l) => (letrec ([l* le*] ...) (l))) (CaseLambdaExpr (le) (lambda info max-fv (local* ...) (entry-block* ...) (block* ...)) => (lambda (local* ...) (entry-block* ...) (block* ...))) (Dummy (dumdum) (dummy)) (Lvalue (lvalue) x (mref x1 x2 imm)) (Triv (t) lvalue (literal info) => info (immediate imm) => imm (label-ref l offset)) (Rhs (rhs) t (inline info value-prim t* ...)) (Pred (p) (inline live-info info pred-prim t* ...)) (Effect (e) (overflow-check live-info) (overflood-check live-info) (fcallable-overflow-check live-info) (return-point info rpl mrvl (cnfv* ...)) (rp-header mrvl fs lpm) (remove-frame live-info info) (restore-local-saves live-info info) (shift-arg live-info reg imm info) (set! live-info lvalue rhs) (inline live-info info effect-prim t* ...) (check-live live-info reg* ...)) (Tail (tl) (goto l) (jump live-info t (var* ...)) (asm-return reg* ...) (asm-c-return info reg* ...))) (define-language L15b (extends L15a) (terminals (- (var (x cnfv var)) (reg (reg)) (label (l rpl))) (+ (var (x var)) (label (l)))) (Effect (e) (- (remove-frame live-info info) (restore-local-saves live-info info) (return-point info rpl mrvl (cnfv* ...)) (shift-arg live-info reg imm info) (check-live live-info reg* ...)) (+ (fp-offset live-info imm))) (Tail (tl) (- (jump live-info t (var* ...)) (asm-return reg* ...) (asm-c-return info reg* ...)) (+ (jump live-info t) (asm-return) (asm-c-return info)))) (define ur? (lambda (x) (or (reg? x) (uvar? x)))) (define-language L15c (extends L15b) (terminals (- (var (x var))) (+ (ur (x)))) ; NB: base and index are really either regs or (mref %sfp %zero imm) (Lvalue (lvalue) (- (mref x1 x2 imm)) (+ (mref lvalue1 lvalue2 imm))) (Effect (e) (- (fp-offset live-info imm)))) (define-language L15d (extends L15c) (terminals (- (pred-primitive (pred-prim)) (value-primitive (value-prim)) (effect-primitive (effect-prim))) (+ (procedure (proc)) => $procedure-name)) (entry Program) (Lvalue (lvalue) (- (mref lvalue1 lvalue2 imm)) (+ (mref x1 x2 imm))) (Rhs (rhs) (- (inline info value-prim t* ...)) (+ (asm info proc t* ...) => (asm proc t* ...))) (Effect (e) (- (inline live-info info effect-prim t* ...) (overflow-check live-info) (overflood-check live-info) (fcallable-overflow-check live-info)) (+ (asm info proc t* ...) => (asm proc t* ...) (move-related x1 x2) (overflow-check p e* ...))) (Pred (p pbody) (- (inline live-info info pred-prim t* ...)) (+ (asm info proc t* ...) => (asm proc t* ...))) (Tail (tl) (- (jump live-info t)) (+ (jump t)))) (define-language L15e (extends L15d) (terminals (- (ur (x))) (+ (reg (x)))) (entry Program) (CaseLambdaExpr (le) (- (lambda info max-fv (local* ...) (entry-block* ...) (block* ...))) (+ (lambda info (entry-block* ...) (block* ...)) => (lambda (entry-block* ...) (block* ...)))) (Effect (e) (- (set! live-info lvalue rhs) (move-related x1 x2)) (+ (set! lvalue rhs)))) (define-language L16 (extends L15e) (entry Program) (Effect (e) (- (overflow-check p e* ...)))) (meta-cond [(not (eqv? (optimize-level) 3)) (pretty-format 'define-language '(alt (_ var #f ('terminals #f x ...) #f (_ _ #f ...) ...) (_ var ('extends x) #f ('definitions #f x ...) #f ('terminals #f x ...) #f (_ _ #f ...) ...) (_ var #f ('definitions #f x ...) #f ('terminals #f x ...) #f (_ _ #f ...) ...) (_ var ('extends x) #f ('terminals #f x ...)) (_ var ('extends x) #f ('terminals #f x ...) #f (_ _ #f ...) ...) (_ var ('extends x) #f (_ _ #f ...) ...))) (pretty-format 'labels '(_ ([bracket x e] 0 ...) #f e ...)) (pretty-format 'blocks '(_ #f [bracket (x ...) 0 e] ...))]) (primitive-handler-set! %keep-live (lambda (info x) (with-output-language (L15d Effect) `(asm ,info ,(lambda (code*) code*))))) )