;;;; structures for the second (virtual machine) intermediate ;;;; representation in the compiler, IR2 ;;;; This software is part of the SBCL system. See the README file for ;;;; more information. ;;;; ;;;; This software is derived from the CMU CL system, which was ;;;; written at Carnegie Mellon University and released into the ;;;; public domain. The software is in the public domain and is ;;;; provided with absolutely no warranty. See the COPYING and CREDITS ;;;; files for more information. (in-package "SB!C") ;;; the largest number of TNs whose liveness changes that we can have ;;; in any block (def!constant local-tn-limit 64) (deftype local-tn-number () `(integer 0 (,local-tn-limit))) (deftype local-tn-count () `(integer 0 ,local-tn-limit)) (deftype local-tn-vector () `(simple-vector ,local-tn-limit)) (deftype local-tn-bit-vector () `(simple-bit-vector ,local-tn-limit)) ;;; type of an SC number (deftype sc-number () `(integer 0 (,sc-number-limit))) ;;; types for vectors indexed by SC numbers (deftype sc-vector () `(simple-vector ,sc-number-limit)) (deftype sc-bit-vector () `(simple-bit-vector ,sc-number-limit)) ;;; the different policies we can use to determine the coding strategy (deftype ltn-policy () '(member :safe :small :fast :fast-safe)) ;;;; PRIMITIVE-TYPEs ;;; A PRIMITIVE-TYPE is used to represent the aspects of type ;;; interesting to the VM. Selection of IR2 translation templates is ;;; done on the basis of the primitive types of the operands, and the ;;; primitive type of a value is used to constrain the possible ;;; representations of that value. (defstruct (primitive-type (:copier nil)) ;; the name of this PRIMITIVE-TYPE (name nil :type symbol) ;; a list of the SC numbers for all the SCs that a TN of this type ;; can be allocated in (scs nil :type list) ;; the Lisp type equivalent to this type. If this type could never be ;; returned by PRIMITIVE-TYPE, then this is the NIL (or empty) type (specifier (missing-arg) :type type-specifier) ;; the template used to check that an object is of this type. This is a ;; template of one argument and one result, both of primitive-type T. If ;; the argument is of the correct type, then it is delivered into the ;; result. If the type is incorrect, then an error is signalled. (check nil :type (or template null))) (defprinter (primitive-type) name) ;;;; IR1 annotations used for IR2 conversion ;;; BLOCK-INFO ;;; Holds the IR2-BLOCK structure. If there are overflow blocks, ;;; then this points to the first IR2-BLOCK. The BLOCK-INFO of the ;;; dummy component head and tail are dummy IR2 blocks that begin ;;; and end the emission order thread. ;;; ;;; COMPONENT-INFO ;;; Holds the IR2-COMPONENT structure. ;;; ;;; LVAR-INFO ;;; Holds the IR2-LVAR structure. LVARs whose values aren't used ;;; won't have any. XXX ;;; ;;; CLEANUP-INFO ;;; If non-null, then a TN in which the affected dynamic ;;; environment pointer should be saved after the binding is ;;; instantiated. ;;; ;;; PHYSENV-INFO ;;; Holds the IR2-PHYSENV structure. ;;; ;;; TAIL-SET-INFO ;;; Holds the RETURN-INFO structure. ;;; ;;; NLX-INFO-INFO ;;; Holds the IR2-NLX-INFO structure. ;;; ;;; LEAF-INFO ;;; If a non-set lexical variable, the TN that holds the value in ;;; the home environment. If a constant, then the corresponding ;;; constant TN. If an XEP lambda, then the corresponding ;;; Entry-Info structure. ;;; ;;; BASIC-COMBINATION-INFO ;;; The template chosen by LTN, or ;;; :FULL if this is definitely a full call. ;;; :FUNNY if this is an oddball thing with IR2-convert. ;;; :LOCAL if this is a local call. ;;; ;;; NODE-TAIL-P ;;; After LTN analysis, this is true only in combination nodes that are ;;; truly tail recursive. ;;; An IR2-BLOCK holds information about a block that is used during ;;; and after IR2 conversion. It is stored in the BLOCK-INFO slot for ;;; the associated block. (defstruct (ir2-block (:include block-annotation) (:constructor make-ir2-block (block)) (:copier nil)) ;; the IR2-BLOCK's number, which differs from BLOCK's BLOCK-NUMBER ;; if any blocks are split. This is assigned by lifetime analysis. (number nil :type (or index null)) ;; information about unknown-values LVARs that is used by stack ;; analysis to do stack simulation. An UNKNOWN-VALUES LVAR is PUSHED ;; if its DEST is in another block. Similarly, a LVAR is POPPED if ;; its DEST is in this block but has its uses elsewhere. The LVARs ;; are in the order that are pushed/popped in the block. Note that ;; the args to a single MV-COMBINATION appear reversed in POPPED, ;; since we must effectively pop the last argument first. All pops ;; must come before all pushes (although internal MV uses may be ;; interleaved.) POPPED is computed by LTN, and PUSHED is computed ;; by stack analysis. (pushed () :type list) (popped () :type list) ;; the result of stack analysis: lists of all the unknown-values ;; LVARs on the stack at the block start and end, topmost LVAR ;; first. (start-stack () :type list) (end-stack () :type list) ;; the first and last VOP in this block. If there are none, both ;; slots are null. (start-vop nil :type (or vop null)) (last-vop nil :type (or vop null)) ;; the number of local TNs actually allocated (local-tn-count 0 :type local-tn-count) ;; a vector that maps local TN numbers to TNs. Some entries may be ;; NIL, indicating that that number is unused. (This allows us to ;; delete local conflict information without compressing the LTN ;; numbers.) ;; ;; If an entry is :MORE, then this block contains only a single VOP. ;; This VOP has so many more arguments and/or results that they ;; cannot all be assigned distinct LTN numbers. In this case, we ;; assign all the more args one LTN number, and all the more results ;; another LTN number. We can do this, since more operands are ;; referenced simultaneously as far as conflict analysis is ;; concerned. Note that all these :MORE TNs will be global TNs. (local-tns (make-array local-tn-limit) :type local-tn-vector) ;; Bit-vectors used during lifetime analysis to keep track of ;; references to local TNs. When indexed by the LTN number, the ;; index for a TN is non-zero in WRITTEN if it is ever written in ;; the block, and in LIVE-OUT if the first reference is a read. (written (make-array local-tn-limit :element-type 'bit :initial-element 0) :type local-tn-bit-vector) (live-out (make-array local-tn-limit :element-type 'bit) :type local-tn-bit-vector) ;; This is similar to the above, but is updated by lifetime flow ;; analysis to have a 1 for LTN numbers of TNs live at the end of ;; the block. This takes into account all TNs that aren't :LIVE. (live-in (make-array local-tn-limit :element-type 'bit :initial-element 0) :type local-tn-bit-vector) ;; a thread running through the global-conflicts structures for this ;; block, sorted by TN number (global-tns nil :type (or global-conflicts null)) ;; the assembler label that points to the beginning of the code for ;; this block, or NIL when we haven't assigned a label yet (%label nil) ;; the assembler label that points to the trampoline for this block, ;; or NIL if unassigned yet. Only meaningful for local call targets. (%trampoline-label nil) ;; T if the preceding block assumes it can drop thru to %label (dropped-thru-to nil) ;; list of LOCATION-INFO structures describing all the interesting ;; (to the debugger) locations in this block (locations nil :type list)) (defprinter (ir2-block) (pushed :test pushed) (popped :test popped) (start-vop :test start-vop) (last-vop :test last-vop) (local-tn-count :test (not (zerop local-tn-count))) (%label :test %label)) ;;; An IR2-LVAR structure is used to annotate LVARs that are used as a ;;; function result LVARs or that receive MVs. (defstruct (ir2-lvar (:constructor make-ir2-lvar (primitive-type)) (:copier nil)) ;; If this is :DELAYED, then this is a single value LVAR for which ;; the evaluation of the use is to be postponed until the evaluation ;; of destination. This can be done for ref nodes or predicates ;; whose destination is an IF. ;; ;; If this is :FIXED, then this LVAR has a fixed number of values, ;; with the TNs in LOCS. ;; ;; If this is :UNKNOWN, then this is an unknown-values LVAR, using ;; the passing locations in LOCS. ;; ;; If this is :UNUSED, then this LVAR should never actually be used ;; as the destination of a value: it is only used tail-recursively. (kind :fixed :type (member :delayed :fixed :unknown :unused)) ;; The primitive-type of the first value of this LVAR. This is ;; primarily for internal use during LTN, but it also records the ;; type restriction on delayed references. In multiple-value ;; contexts, this is null to indicate that it is meaningless. This ;; is always (primitive-type (lvar-type cont)), which may be more ;; restrictive than the tn-primitive-type of the value TN. This is ;; becase the value TN must hold any possible type that could be ;; computed (before type checking.) XXX (primitive-type nil :type (or primitive-type null)) ;; Locations used to hold the values of the LVAR. If the number of ;; values if fixed, then there is one TN per value. If the number of ;; values is unknown, then this is a two-list of TNs holding the ;; start of the values glob and the number of values. Note that ;; since type checking is the responsibility of the values receiver, ;; these TNs primitive type is only based on the proven type ;; information. (locs nil :type list) (stack-pointer nil :type (or tn null))) (defprinter (ir2-lvar) kind primitive-type locs) ;;; An IR2-COMPONENT serves mostly to accumulate non-code information ;;; about the component being compiled. (defstruct (ir2-component (:copier nil)) ;; the counter used to allocate global TN numbers (global-tn-counter 0 :type index) ;; NORMAL-TNS is the head of the list of all the normal TNs that ;; need to be packed, linked through the Next slot. We place TNs on ;; this list when we allocate them so that Pack can find them. ;; ;; RESTRICTED-TNS are TNs that must be packed within a finite SC. We ;; pack these TNs first to ensure that the restrictions will be ;; satisfied (if possible). ;; ;; WIRED-TNs are TNs that must be packed at a specific location. The ;; SC and OFFSET are already filled in. ;; ;; CONSTANT-TNs are non-packed TNs that represent constants. (normal-tns nil :type (or tn null)) (restricted-tns nil :type (or tn null)) (wired-tns nil :type (or tn null)) (constant-tns nil :type (or tn null)) ;; a list of all the :COMPONENT TNs (live throughout the component). ;; These TNs will also appear in the {NORMAL,RESTRICTED,WIRED} TNs ;; as appropriate to their location. (component-tns () :type list) ;; If this component has a NFP, then this is it. (nfp nil :type (or tn null)) ;; a list of the explicitly specified save TNs (kind ;; :SPECIFIED-SAVE). These TNs will also appear in the ;; {NORMAL,RESTRICTED,WIRED} TNs as appropriate to their location. (specified-save-tns () :type list) ;; a list of all the blocks whose IR2-BLOCK has a non-null value for ;; POPPED. This slot is initialized by LTN-ANALYZE as an input to ;; STACK-ANALYZE. (values-receivers nil :type list) ;; an adjustable vector that records all the constants in the ;; constant pool. A non-immediate :CONSTANT TN with offset 0 refers ;; to the constant in element 0, etc. Normal constants are ;; represented by the placing the CONSTANT leaf in this vector. A ;; load-time constant is distinguished by being a cons (KIND . ;; WHAT). KIND is a keyword indicating how the constant is computed, ;; and WHAT is some context. ;; ;; These load-time constants are recognized: ;; ;; (:entry . ) ;; Is replaced by the code pointer for the specified function. ;; This is how compiled code (including DEFUN) gets its hands on ;; a function. is the XEP lambda for the called ;; function; its LEAF-INFO should be an ENTRY-INFO structure. ;; ;; (:label .