home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / ir2tran.lisp < prev    next >
Encoding:
Text File  |  1992-07-28  |  61.2 KB  |  1,795 lines

  1. ;;; -*- Package: C; Log: C.Log -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: ir2tran.lisp,v 1.40.2.1 92/07/28 17:10:04 ram Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;;    This file contains the virtual machine independent parts of the code
  15. ;;; which does the actual translation of nodes to VOPs.
  16. ;;;
  17. ;;; Written by Rob MacLachlan
  18. ;;;
  19. (in-package "C")
  20. (in-package "KERNEL")
  21. (export '(%caller-frame-and-pc))
  22. (in-package "C")
  23.  
  24.  
  25. ;;;; Moves and type checks:
  26.  
  27. ;;; Emit-Move  --  Internal
  28. ;;;
  29. ;;;    Move X to Y unless they are EQ.
  30. ;;;
  31. (defun emit-move (node block x y)
  32.   (declare (type node node) (type ir2-block block) (type tn x y))
  33.   (unless (eq x y)
  34.     (vop move node block x y))
  35.   (undefined-value))
  36.  
  37.  
  38. ;;; Type-Check-Template  --  Interface
  39. ;;;
  40. ;;;    If there is any CHECK-xxx template for Type, then return it, otherwise
  41. ;;; return NIL.
  42. ;;;
  43. (defun type-check-template (type)
  44.   (declare (type ctype type))
  45.   (multiple-value-bind (check-ptype exact)
  46.                (primitive-type type)
  47.     (if exact
  48.     (primitive-type-check check-ptype)
  49.     (let ((name (hairy-type-check-template type)))
  50.       (if name
  51.           (template-or-lose name *backend*)
  52.           nil)))))
  53.  
  54.  
  55. ;;; Emit-Type-Check  --  Internal
  56. ;;;
  57. ;;;    Emit code in Block to check that Value is of the specified Type,
  58. ;;; yielding the checked result in Result.  Value and result may be of any
  59. ;;; primitive type.  There must be CHECK-xxx VOP for Type.  Any other type
  60. ;;; checks should have been converted to an explicit type test.
  61. ;;;
  62. (defun emit-type-check (node block value result type)
  63.   (declare (type tn value result) (type node node) (type ir2-block block)
  64.        (type ctype type))
  65.   (emit-move-template node block (type-check-template type) value result)
  66.   (undefined-value))
  67.  
  68.  
  69. ;;;; Leaf reference:
  70.  
  71. ;;; Find-In-Environment  --  Internal
  72. ;;;
  73. ;;;    Return the TN that holds the value of Thing in the environment Env.
  74. ;;;
  75. (defun find-in-environment (thing env)
  76.   (declare (type (or nlx-info lambda-var) thing) (type environment env)
  77.        (values tn))
  78.   (or (cdr (assoc thing (ir2-environment-environment (environment-info env))))
  79.       (etypecase thing
  80.     (lambda-var
  81.      (assert (eq env (lambda-environment (lambda-var-home thing))))
  82.      (leaf-info thing))
  83.     (nlx-info
  84.      (assert (eq env (block-environment (nlx-info-target thing))))
  85.      (ir2-nlx-info-home (nlx-info-info thing))))))
  86.  
  87.  
  88. ;;; Constant-TN  --  Internal
  89. ;;;
  90. ;;;    If Leaf already has a constant TN, return that, otherwise make a TN for
  91. ;;; it.
  92. ;;;
  93. (defun constant-tn (leaf)
  94.   (declare (type constant leaf))
  95.   (or (leaf-info leaf)
  96.       (setf (leaf-info leaf)
  97.         (make-constant-tn leaf))))
  98.  
  99.   
  100. ;;; Leaf-TN  --  Internal
  101. ;;;
  102. ;;;    Return a TN that represents the value of Leaf, or NIL if Leaf isn't
  103. ;;; directly represented by a TN.  Env is the environment that the reference is
  104. ;;; done in.
  105. ;;;
  106. (defun leaf-tn (leaf env)
  107.   (declare (type leaf leaf) (type environment env))
  108.   (typecase leaf
  109.     (lambda-var
  110.      (unless (lambda-var-indirect leaf)
  111.        (find-in-environment leaf env)))
  112.     (constant (constant-tn leaf))
  113.     (t nil)))
  114.  
  115.  
  116. ;;; Emit-Constant  --  Internal
  117. ;;;
  118. ;;;    Used to conveniently get a handle on a constant TN during IR2
  119. ;;; conversion.  Returns a constant TN representing the Lisp object Value.
  120. ;;;
  121. (defun emit-constant (value)
  122.   (constant-tn (find-constant value)))
  123.  
  124.  
  125. ;;; IR2-Convert-Hairy-Function-Ref  --  Internal
  126. ;;;
  127. ;;;    Handle a function Ref that can't be converted to a symbol access.  We
  128. ;;; convert a call to FDEFINITION with Name as the argument.
  129. ;;;
  130. (defun ir2-convert-hairy-function-ref (node block name)
  131.   (declare (type ref node) (type ir2-block block) (type tn name))
  132.   (when (policy node (> speed brevity))
  133.     (let ((*compiler-error-context* node))
  134.       (compiler-note "Compiling a full call to FDEFINITION.")))
  135.   (let* ((arg (standard-argument-location 0))
  136.      (res (standard-argument-location 0))
  137.      (fun (emit-constant 'fdefinition))
  138.      (fp (make-stack-pointer-tn)))
  139.     (vop allocate-full-call-frame node block 1 fp)
  140.     (vop* call-named node block (fp fun name nil) (res nil) (list arg) 1 1)
  141.     (move-continuation-result node block (list res) (node-cont node)))
  142.   (undefined-value))
  143.  
  144.  
  145. ;;; IR2-Convert-Ref  --  Internal
  146. ;;;
  147. ;;;    Convert a Ref node.  The reference must not be delayed.
  148. ;;;
  149. (defun ir2-convert-ref (node block)
  150.   (declare (type ref node) (type ir2-block block))
  151.   (let* ((cont (node-cont node))
  152.      (leaf (ref-leaf node))
  153.      (name (leaf-name leaf))
  154.      (locs (continuation-result-tns
  155.         cont (list (primitive-type (leaf-type leaf)))))
  156.      (res (first locs)))
  157.     (etypecase leaf
  158.       (lambda-var
  159.        (let ((tn (find-in-environment leaf (node-environment node))))
  160.      (if (lambda-var-indirect leaf)
  161.          (vop value-cell-ref node block tn res)
  162.          (emit-move node block tn res))))
  163.       (constant
  164.        (if (legal-immediate-constant-p leaf)
  165.        (emit-move node block (constant-tn leaf) res)
  166.        (let ((name-tn (emit-constant name)))
  167.          (if (policy node (zerop safety))
  168.          (vop fast-symbol-value node block name-tn res)
  169.          (vop symbol-value node block name-tn res)))))
  170.       (functional
  171.        (ir2-convert-closure node block leaf res))
  172.       (global-var
  173.        (let ((name-tn (emit-constant name))
  174.          (unsafe (policy node (zerop safety))))
  175.      (ecase (global-var-kind leaf)
  176.        ((:special :global :constant)
  177.         (assert (symbolp name))
  178.         (if unsafe
  179.         (vop fast-symbol-value node block name-tn res)
  180.         (vop symbol-value node block name-tn res)))
  181.        (:global-function
  182.         (unless (symbolp name)
  183.           (ir2-convert-hairy-function-ref node block name-tn)
  184.           (return-from ir2-convert-ref (undefined-value)))
  185.  
  186.         (if unsafe
  187.         (vop fast-symbol-function node block name-tn res)
  188.         (vop symbol-function node block name-tn res)))))))
  189.  
  190.     (move-continuation-result node block locs cont))
  191.   (undefined-value))
  192.  
  193.  
  194. ;;; IR2-Convert-Closure  --  Internal
  195. ;;;
  196. ;;;    Emit code to load a function object representing Leaf into Res.  This
  197. ;;; gets interesting when the referenced function is a closure: we must make
  198. ;;; the closure and move the closed over values into it.
  199. ;;;
  200. ;;; Leaf is either a :TOP-LEVEL-XEP functional or the XEP lambda for the called
  201. ;;; function, since local call analysis converts all closure references.  If a
  202. ;;; TL-XEP, we know it is not a closure.
  203. ;;;
  204. ;;; If a closed-over lambda-var has no refs (is deleted), then we don't
  205. ;;; initialize that slot.  This can happen with closures over top-level
  206. ;;; variables, where optimization of the closure deleted the variable.  Since
  207. ;;; we committed to the closure format when we pre-analyzed the top-level code,
  208. ;;; we just leva an empty slot.
  209. ;;;
  210. (defun ir2-convert-closure (node block leaf res)
  211.   (declare (type ref node) (type ir2-block block)
  212.        (type functional leaf) (type tn res))
  213.   (unless (leaf-info leaf)
  214.     (setf (leaf-info leaf) (make-entry-info)))
  215.   (let ((entry (make-load-time-constant-tn :entry leaf))
  216.     (closure (etypecase leaf
  217.            (clambda
  218.             (environment-closure (get-lambda-environment leaf)))
  219.            (functional
  220.             (assert (eq (functional-kind leaf) :top-level-xep))
  221.             nil))))
  222.     (cond (closure
  223.        (let ((this-env (node-environment node)))
  224.          (vop make-closure node block (emit-constant (length closure))
  225.           entry res)
  226.          (loop for what in closure and n from 0 do
  227.            (unless (and (lambda-var-p what)
  228.                 (null (leaf-refs what)))
  229.          (vop closure-init node block
  230.               res
  231.               (find-in-environment what this-env)
  232.               n)))))
  233.       (t
  234.        (emit-move node block entry res))))
  235.   (undefined-value))
  236.  
  237.  
  238. ;;; IR2-Convert-Set  --  Internal
  239. ;;;
  240. ;;;    Convert a Set node.  If the node's cont is annotated, then we also
  241. ;;; deliver the value to that continuation.  If the var is a lexical variable
  242. ;;; with no refs, then we don't actually set anything, since the variable has
  243. ;;; been deleted.
  244. ;;;
  245. (defun ir2-convert-set (node block)
  246.   (declare (type cset node) (type ir2-block block))
  247.   (let* ((cont (node-cont node))
  248.      (leaf (set-var node))
  249.      (val (continuation-tn node block (set-value node)))
  250.      (locs (if (continuation-info cont)
  251.            (continuation-result-tns
  252.             cont (list (primitive-type (leaf-type leaf))))
  253.            nil)))
  254.     (etypecase leaf
  255.       (lambda-var
  256.        (when (leaf-refs leaf)
  257.      (let ((tn (find-in-environment leaf (node-environment node))))
  258.        (if (lambda-var-indirect leaf)
  259.            (vop value-cell-set node block tn val)
  260.            (emit-move node block val tn)))))
  261.       (global-var
  262.        (ecase (global-var-kind leaf)
  263.      ((:special :global)
  264.       (assert (symbolp (leaf-name leaf)))
  265.       (vop set node block (emit-constant (leaf-name leaf)) val
  266.            (make-normal-tn (backend-any-primitive-type *backend*)))))))
  267.  
  268.     (when locs
  269.       (emit-move node block val (first locs))
  270.       (move-continuation-result node block locs cont)))
  271.   (undefined-value))
  272.  
  273.  
  274. ;;;; Utilities for receiving fixed values:
  275.  
  276. ;;; Continuation-TN  --  Internal
  277. ;;;
  278. ;;;    Return a TN that can be referenced to get the value of Cont.  Cont must
  279. ;;; be LTN-Annotated either as a delayed leaf ref or as a fixed, single-value
  280. ;;; continuation.  If a type check is called for, do it.
  281. ;;;
  282. ;;;    The primitive-type of the result will always be the same as the
  283. ;;; ir2-continuation-primitive-type, ensuring that VOPs are always called with
  284. ;;; TNs that satisfy the operand primitive-type restriction.  We may have to
  285. ;;; make a temporary of the desired type and move the actual continuation TN
  286. ;;; into it.  This happens when we delete a type check in unsafe code or when
  287. ;;; we locally know something about the type of an argument variable.
  288. ;;;
  289. (defun continuation-tn (node block cont)
  290.   (declare (type node node) (type ir2-block block) (type continuation cont))
  291.   (let* ((2cont (continuation-info cont))
  292.      (cont-tn 
  293.       (ecase (ir2-continuation-kind 2cont)
  294.         (:delayed
  295.          (let ((ref (continuation-use cont)))
  296.            (leaf-tn (ref-leaf ref) (node-environment ref))))
  297.         (:fixed
  298.          (assert (= (length (ir2-continuation-locs 2cont)) 1))
  299.          (first (ir2-continuation-locs 2cont)))))
  300.      (ptype (ir2-continuation-primitive-type 2cont)))
  301.     
  302.     (cond ((eq (continuation-type-check cont) t)
  303.        (multiple-value-bind (check types)
  304.                 (continuation-check-types cont)
  305.          (assert (eq check :simple))
  306.          (let ((temp (make-normal-tn ptype)))
  307.            (emit-type-check node block cont-tn temp (first types))
  308.            temp)))
  309.       ((eq (tn-primitive-type cont-tn) ptype) cont-tn)
  310.       (t
  311.        (let ((temp (make-normal-tn ptype)))
  312.          (emit-move node block cont-tn temp)
  313.          temp)))))
  314.  
  315.  
  316. ;;; CONTINUATION-TNS  --  Internal
  317. ;;;
  318. ;;;    Similar to CONTINUATION-TN, but hacks multiple values.  We return
  319. ;;; continuations holding the values of Cont with Ptypes as their primitive
  320. ;;; types.  Cont must be annotated for the same number of fixed values are
  321. ;;; there are Ptypes.
  322. ;;;
  323. ;;;    If the continuation has a type check, check the values into temps and
  324. ;;; return the temps.  When we have more values than assertions, we move the
  325. ;;; extra values with no check.
  326. ;;; 
  327. (defun continuation-tns (node block cont ptypes)
  328.   (declare (type node node) (type ir2-block block)
  329.        (type continuation cont) (list ptypes))
  330.   (let* ((locs (ir2-continuation-locs (continuation-info cont)))
  331.      (nlocs (length locs)))
  332.     (assert (= nlocs (length ptypes)))
  333.     (if (eq (continuation-type-check cont) t)
  334.     (multiple-value-bind (check types)
  335.                  (continuation-check-types cont)
  336.       (assert (eq check :simple))
  337.       (let ((ntypes (length types)))
  338.         (mapcar #'(lambda (from to-type assertion)
  339.             (let ((temp (make-normal-tn to-type)))
  340.               (if assertion
  341.                   (emit-type-check node block from temp assertion)
  342.                   (emit-move node block from temp))
  343.               temp))
  344.             locs ptypes
  345.             (if (< ntypes nlocs)
  346.             (append types (make-list (- nlocs ntypes)
  347.                          :initial-element nil))
  348.             types))))
  349.     (mapcar #'(lambda (from to-type)
  350.             (if (eq (tn-primitive-type from) to-type)
  351.             from
  352.             (let ((temp (make-normal-tn to-type)))
  353.               (emit-move node block from temp)
  354.               temp)))
  355.         locs ptypes))))
  356.  
  357.  
  358. ;;;; Utilities for delivering values to continuations:
  359.  
  360. ;;; Continuation-Result-TNs  --  Internal
  361. ;;;
  362. ;;;    Return a list of TNs with the specifier Types that can be used as result
  363. ;;; TNs to evaluate an expression into the continuation Cont.  This is used
  364. ;;; together with Move-Continuation-Result to deliver fixed values to a
  365. ;;; continuation.
  366. ;;;
  367. ;;;    If the continuation isn't annotated (meaning the values are discarded)
  368. ;;; or is unknown-values, the then we make temporaries for each supplied value,
  369. ;;; providing a place to compute the result in until we decide what to do with
  370. ;;; it (if anything.)
  371. ;;;
  372. ;;;    If the continuation is fixed-values, and wants the same number of values
  373. ;;; as the user wants to deliver, then we just return the
  374. ;;; IR2-Continuation-Locs.  Otherwise we make a new list padded as necessary by
  375. ;;; discarded TNs.  We always return a TN of the specified type, using the
  376. ;;; continuation locs only when they are of the correct type.
  377. ;;;
  378. (defun continuation-result-tns (cont types)
  379.   (declare (type continuation cont) (type list types))
  380.   (let ((2cont (continuation-info cont)))
  381.     (if (not 2cont)
  382.     (mapcar #'make-normal-tn types)
  383.     (ecase (ir2-continuation-kind 2cont)
  384.       (:fixed
  385.        (let* ((locs (ir2-continuation-locs 2cont))
  386.           (nlocs (length locs))
  387.           (ntypes (length types)))
  388.          (if (and (= nlocs ntypes)
  389.               (do ((loc locs (cdr loc))
  390.                (type types (cdr type)))
  391.               ((null loc) t)
  392.             (unless (eq (tn-primitive-type (car loc)) (car type))
  393.               (return nil))))
  394.          locs
  395.          (mapcar #'(lambda (loc type)
  396.                  (if (eq (tn-primitive-type loc) type)
  397.                  loc
  398.                  (make-normal-tn type)))
  399.              (if (< nlocs ntypes)
  400.                  (append locs
  401.                      (mapcar #'make-normal-tn
  402.                          (subseq types nlocs)))
  403.                  locs)
  404.              types))))
  405.       (:unknown
  406.        (mapcar #'make-normal-tn types))))))
  407.  
  408.  
  409. ;;; Make-Standard-Value-Tns  --  Internal
  410. ;;;
  411. ;;;    Make the first N standard value TNs, returning them in a list.
  412. ;;;
  413. (defun make-standard-value-tns (n)
  414.   (declare (type unsigned-byte n))
  415.   (collect ((res))
  416.     (dotimes (i n)
  417.       (res (standard-argument-location i)))
  418.     (res)))
  419.  
  420.  
  421. ;;; Standard-Result-TNs  --  Internal
  422. ;;;
  423. ;;;    Return a list of TNs wired to the standard value passing conventions
  424. ;;; that can be used to receive values according to the unknown-values
  425. ;;; convention.  This is used with together Move-Continuation-Result for
  426. ;;; delivering unknown values to a fixed values continuation.
  427. ;;;
  428. ;;;    If the continuation isn't annotated, then we treat as 0-values,
  429. ;;; returning an empty list of temporaries.
  430. ;;;
  431. ;;;    If the continuation is annotated, then it must be :Fixed.
  432. ;;;
  433. (defun standard-result-tns (cont)
  434.   (declare (type continuation cont))
  435.   (let ((2cont (continuation-info cont)))
  436.     (if 2cont
  437.     (ecase (ir2-continuation-kind 2cont)
  438.       (:fixed
  439.        (make-standard-value-tns (length (ir2-continuation-locs 2cont)))))
  440.     ())))
  441.  
  442.  
  443. ;;; Move-Results-Coerced  --  Internal
  444. ;;;
  445. ;;;    Just move each Src TN into the corresponding Dest TN, defaulting any
  446. ;;; unsupplied source values to NIL.  We let Emit-Move worry about doing the
  447. ;;; appropriate coercions.
  448. ;;;
  449. (defun move-results-coerced (node block src dest)
  450.   (declare (type node node) (type ir2-block block) (list src dest))
  451.   (let ((nsrc (length src))
  452.     (ndest (length dest)))
  453.     (mapc #'(lambda (from to)
  454.           (unless (eq from to)
  455.         (emit-move node block from to)))
  456.       (if (> ndest nsrc)
  457.           (append src (make-list (- ndest nsrc)
  458.                      :initial-element (emit-constant nil)))
  459.           src)
  460.       dest))
  461.   (undefined-value))
  462.  
  463.  
  464. ;;; Move-Continuation-Result  --  Internal
  465. ;;;
  466. ;;;    If necessary, emit coercion code needed to deliver the
  467. ;;; Results to the specified continuation.  Node and block provide context for
  468. ;;; emitting code.  Although usually obtained from Standard-Result-TNs or
  469. ;;; Continuation-Result-TNs, Results my be a list of any type or number of TNs.
  470. ;;;
  471. ;;;    If the continuation is fixed values, then move the results into the
  472. ;;; continuation locations.  If the continuation is unknown values, then do the
  473. ;;; moves into the standard value locations, and use Push-Values to put the
  474. ;;; values on the stack.
  475. ;;;
  476. (defun move-continuation-result (node block results cont)
  477.   (declare (type node node) (type ir2-block block)
  478.        (list results) (type continuation cont))
  479.   (let* ((2cont (continuation-info cont)))
  480.     (when 2cont
  481.       (ecase (ir2-continuation-kind 2cont)
  482.     (:fixed
  483.      (let ((locs (ir2-continuation-locs 2cont)))
  484.        (unless (eq locs results)
  485.          (move-results-coerced node block results locs))))
  486.     (:unknown
  487.      (let* ((nvals (length results))
  488.         (locs (make-standard-value-tns nvals)))
  489.        (move-results-coerced node block results locs)
  490.        (vop* push-values node block
  491.          ((reference-tn-list locs nil))
  492.          ((reference-tn-list (ir2-continuation-locs 2cont) t))
  493.          nvals))))))
  494.   (undefined-value))
  495.  
  496.  
  497. ;;;; Template conversion:
  498.  
  499.  
  500. ;;; Reference-Arguments  --  Internal
  501. ;;;
  502. ;;;    Build a TN-Refs list that represents access to the values of the
  503. ;;; specified list of continuations Args for Template.  Any :CONSTANT arguments
  504. ;;; are returned in the second value as a list rather than being accessed as a
  505. ;;; normal argument.  Node and Block provide the context for emitting any
  506. ;;; necessary type-checking code.
  507. ;;;
  508. (defun reference-arguments (node block args template)
  509.   (declare (type node node) (type ir2-block block) (list args)
  510.        (type template template))
  511.   (collect ((info-args))
  512.     (let ((last nil)
  513.       (first nil))
  514.       (do ((args args (cdr args))
  515.        (types (template-arg-types template) (cdr types)))
  516.       ((null args))
  517.     (let ((type (first types))
  518.           (arg (first args)))
  519.       (if (and (consp type) (eq (car type) ':constant))
  520.           (info-args (continuation-value arg))
  521.           (let ((ref (reference-tn (continuation-tn node block arg) nil)))
  522.         (if last
  523.             (setf (tn-ref-across last) ref)
  524.             (setf first ref))
  525.         (setq last ref)))))
  526.  
  527.       (values (the (or tn-ref null) first) (info-args)))))
  528.  
  529.  
  530. ;;; IR2-Convert-Conditional  --  Internal
  531. ;;;
  532. ;;;    Convert a conditional template.  We try to exploit any drop-through, but
  533. ;;; emit an unconditional branch afterward if we fail.  Not-P is true if the
  534. ;;; sense of the Template's test should be negated.
  535. ;;;
  536. (defun ir2-convert-conditional (node block template args info-args if not-p)
  537.   (declare (type node node) (type ir2-block block)
  538.        (type template template) (type (or tn-ref null) args)
  539.        (list info-args) (type cif if) (type boolean not-p))
  540.   (assert (= (template-info-arg-count template) (+ (length info-args) 2)))
  541.   (let ((consequent (if-consequent if))
  542.     (alternative (if-alternative if)))
  543.     (cond ((drop-thru-p if consequent)
  544.        (emit-template node block template args nil
  545.               (list* (block-label alternative) (not not-p)
  546.                  info-args)))
  547.       (t
  548.        (emit-template node block template args nil
  549.               (list* (block-label consequent) not-p info-args))
  550.        (unless (drop-thru-p if alternative)
  551.          (vop branch node block (block-label alternative)))))))
  552.  
  553.  
  554. ;;; IR2-Convert-IF  --  Internal
  555. ;;;
  556. ;;;    Convert an IF that isn't the DEST of a conditional template.
  557. ;;;
  558. (defun ir2-convert-if (node block)
  559.   (declare (type ir2-block block) (type cif node))
  560.   (let* ((test (if-test node))
  561.      (test-ref (reference-tn (continuation-tn node block test) nil))
  562.      (nil-ref (reference-tn (emit-constant nil) nil)))
  563.     (setf (tn-ref-across test-ref) nil-ref)
  564.     (ir2-convert-conditional node block (template-or-lose 'if-eq *backend*)
  565.                  test-ref () node t)))
  566.  
  567.  
  568. ;;; FIND-TEMPLATE-RESULT-TYPES  --  Internal
  569. ;;;
  570. ;;;    Return a list of primitive-types that we can pass to
  571. ;;; CONTINUATION-RESULT-TNS describing the result types we want for a template
  572. ;;; call.  We duplicate here the determination of output type that was done in
  573. ;;; initially selecting the template, so we know that the types we find are
  574. ;;; allowed by the template output type restrictions.
  575. ;;;
  576. (defun find-template-result-types (call cont template rtypes)
  577.   (declare (type combination call) (type continuation cont)
  578.        (type template template) (list rtypes))
  579.   (let* ((dtype (node-derived-type call))
  580.      (type (if (and (or (eq (template-policy template) :safe)
  581.                 (policy call (= safety 0)))
  582.             (continuation-type-check cont))
  583.            (values-type-intersection
  584.             dtype
  585.             (continuation-asserted-type cont))
  586.            dtype))
  587.      (types (mapcar #'primitive-type
  588.             (if (values-type-p type)
  589.                 (append (values-type-required type)
  590.                     (values-type-optional type))
  591.                 (list type)))))
  592.     (let ((nvals (length rtypes))
  593.       (ntypes (length types)))
  594.       (cond ((< ntypes nvals)
  595.          (append types
  596.              (make-list (- nvals ntypes)
  597.                 :initial-element
  598.                 (backend-any-primitive-type *backend*))))
  599.         ((> ntypes nvals)
  600.          (subseq types 0 nvals))
  601.         (t
  602.          types)))))
  603.  
  604.  
  605. ;;; MAKE-TEMPLATE-RESULT-TNS  --  Internal
  606. ;;;
  607. ;;;    Return a list of TNs usable in a Call to Template delivering values to
  608. ;;; Cont.  As an efficiency hack, we pick off the common case where the
  609. ;;; contiuation is fixed values and has locations that satisfy the result
  610. ;;; restrictions.  This can fail when there is a type check or a values count
  611. ;;; mismatch.
  612. ;;;
  613. (defun make-template-result-tns (call cont template rtypes)
  614.   (declare (type combination call) (type continuation cont)
  615.        (type template template) (list rtypes))
  616.   (let ((2cont (continuation-info cont)))
  617.     (if (and 2cont (eq (ir2-continuation-kind 2cont) :fixed))
  618.     (let ((locs (ir2-continuation-locs 2cont)))
  619.       (if (and (= (length rtypes) (length locs))
  620.            (do ((loc locs (cdr loc))
  621.             (rtype rtypes (cdr rtype)))
  622.                ((null loc) t)
  623.              (unless (operand-restriction-ok
  624.                   (car rtype)
  625.                   (tn-primitive-type (car loc))
  626.                   :t-ok nil)
  627.                (return nil))))
  628.           locs
  629.           (continuation-result-tns
  630.            cont
  631.            (find-template-result-types call cont template rtypes))))
  632.     (continuation-result-tns
  633.      cont
  634.      (find-template-result-types call cont template rtypes)))))
  635.  
  636.  
  637. ;;; IR2-Convert-Template  --  Internal
  638. ;;;
  639. ;;;    Get the operands into TNs, make TN-Refs for them, and then call the
  640. ;;; template emit function. 
  641. ;;;
  642. (defun ir2-convert-template (call block)
  643.   (declare (type combination call) (type ir2-block block))
  644.   (let* ((template (combination-info call))
  645.      (cont (node-cont call))
  646.      (rtypes (template-result-types template)))
  647.     (multiple-value-bind
  648.     (args info-args)
  649.     (reference-arguments call block (combination-args call) template)
  650.       (assert (not (template-more-results-type template)))
  651.       (if (eq rtypes :conditional)
  652.       (ir2-convert-conditional call block template args info-args
  653.                    (continuation-dest cont) nil)
  654.       (let* ((results (make-template-result-tns call cont template rtypes))
  655.          (r-refs (reference-tn-list results t)))
  656.         (assert (= (length info-args)
  657.                (template-info-arg-count template)))
  658.         (if info-args
  659.         (emit-template call block template args r-refs info-args)
  660.         (emit-template call block template args r-refs))
  661.         (move-continuation-result call block results cont)))))
  662.   (undefined-value))
  663.  
  664.  
  665. ;;; %%Primitive IR2 Convert  --  Internal
  666. ;;;
  667. ;;;    We don't have to do much because operand count checking is done by IR1
  668. ;;; conversion.  The only difference between this and the function case of
  669. ;;; IR2-Convert-Template is that there can be codegen-info arguments.
  670. ;;;
  671. (defoptimizer (%%primitive ir2-convert) ((template info &rest args) call block)
  672.   (let* ((template (continuation-value template))
  673.      (info (continuation-value info))
  674.      (cont (node-cont call))
  675.      (rtypes (template-result-types template))
  676.      (results (make-template-result-tns call cont template rtypes))
  677.      (r-refs (reference-tn-list results t)))
  678.     (multiple-value-bind
  679.     (args info-args)
  680.     (reference-arguments call block (cddr (combination-args call))
  681.                  template)
  682.       (assert (not (template-more-results-type template)))
  683.       (assert (not (eq rtypes :conditional)))
  684.       (assert (null info-args))
  685.       
  686.       (if info
  687.       (emit-template call block template args r-refs info)
  688.       (emit-template call block template args r-refs))
  689.       
  690.       (move-continuation-result call block results cont)))
  691.   (undefined-value))
  692.  
  693.  
  694. ;;;; Local call:
  695.  
  696. ;;; IR2-Convert-Let  --  Internal
  697. ;;;
  698. ;;;    Convert a let by moving the argument values into the variables.  Since a
  699. ;;; a let doesn't have any passing locations, we move the arguments directly
  700. ;;; into the variables.  We must also allocate any indirect value cells, since
  701. ;;; there is no function prologue to do this.
  702. ;;;
  703. (defun ir2-convert-let (node block fun)
  704.   (declare (type combination node) (type ir2-block block) (type clambda fun))
  705.   (mapc #'(lambda (var arg)
  706.         (when arg
  707.           (let ((src (continuation-tn node block arg))
  708.             (dest (leaf-info var)))
  709.         (if (lambda-var-indirect var)
  710.             (vop make-value-cell node block src dest)
  711.             (emit-move node block src dest)))))
  712.     (lambda-vars fun) (basic-combination-args node))
  713.   (undefined-value))
  714.  
  715.  
  716. ;;; EMIT-PSETQ-MOVES  --  Internal
  717. ;;;
  718. ;;;    Emit any necessary moves into assignment temps for a local call to Fun.
  719. ;;; We return two lists of TNs: TNs holding the actual argument values, and
  720. ;;; (possibly EQ) TNs that are the actual destination of the arguments.  When
  721. ;;; necessary, we allocate temporaries for arguments to preserve paralell
  722. ;;; assignment semantics.   These lists exclude unused arguments and include
  723. ;;; implicit environment arguments, i.e. they exactly correspond to the
  724. ;;; arguments passed.
  725. ;;;
  726. ;;; OLD-FP is the TN currently holding the value we want to pass as OLD-FP.  If
  727. ;;; null, then the call is to the same environment (an :ASSIGNMENT), so we
  728. ;;; only move the arguments, and leave the environment alone.
  729. ;;;
  730. (defun emit-psetq-moves (node block fun old-fp)
  731.   (declare (type combination node) (type ir2-block block) (type clambda fun)
  732.        (type (or tn null) old-fp))
  733.   (let* ((called-env (environment-info (lambda-environment fun)))
  734.      (this-1env (node-environment node))
  735.      (actuals (mapcar #'(lambda (x)
  736.                  (when x
  737.                    (continuation-tn node block x)))
  738.              (combination-args node))))
  739.     (collect ((temps)
  740.           (locs))
  741.       (dolist (var (lambda-vars fun))
  742.     (let ((actual (pop actuals))
  743.           (loc (leaf-info var)))
  744.       (when actual
  745.         (cond
  746.          ((lambda-var-indirect var)
  747.           (let ((temp
  748.              (make-normal-tn (backend-any-primitive-type *backend*))))
  749.         (vop make-value-cell node block actual temp)
  750.         (temps temp)))
  751.          ((member actual (locs))
  752.           (let ((temp (make-normal-tn (tn-primitive-type loc))))
  753.         (emit-move node block actual temp)
  754.         (temps temp)))
  755.          (t
  756.           (temps actual)))
  757.         (locs loc))))
  758.  
  759.       (when old-fp
  760.     (dolist (thing (ir2-environment-environment called-env))
  761.       (temps (find-in-environment (car thing) this-1env))
  762.       (locs (cdr thing)))
  763.     
  764.     (temps old-fp)
  765.     (locs (ir2-environment-old-fp called-env)))
  766.  
  767.       (values (temps) (locs)))))
  768.  
  769.  
  770. ;;; IR2-Convert-Tail-Local-Call   --  Internal
  771. ;;;
  772. ;;;    A tail-recursive local call is done by emitting moves of stuff into the
  773. ;;; appropriate passing locations.  After setting up the args and environment,
  774. ;;; we just move our return-pc into the called function's passing
  775. ;;; location.
  776. ;;;
  777. (defun ir2-convert-tail-local-call (node block fun)
  778.   (declare (type combination node) (type ir2-block block) (type clambda fun))
  779.   (let ((this-env (environment-info (node-environment node))))
  780.     (multiple-value-bind
  781.     (temps locs)
  782.     (emit-psetq-moves node block fun (ir2-environment-old-fp this-env))
  783.       
  784.       (mapc #'(lambda (temp loc)
  785.         (emit-move node block temp loc))
  786.         temps locs))
  787.   
  788.     (emit-move node block
  789.            (ir2-environment-return-pc this-env)
  790.            (ir2-environment-return-pc-pass
  791.         (environment-info
  792.          (lambda-environment fun)))))
  793.   
  794.   (undefined-value))
  795.  
  796.  
  797. ;;; IR2-CONVERT-ASSIGNMENT  --  Internal
  798. ;;;
  799. ;;;    Convert an :ASSIGNMENT call.  This is just like a tail local call,
  800. ;;; except that the caller and callee environment are the same, so we don't
  801. ;;; need to mess with the environment locations, return PC, etc.
  802. ;;;
  803. (defun ir2-convert-assignment (node block fun)
  804.   (declare (type combination node) (type ir2-block block) (type clambda fun))
  805.     (multiple-value-bind
  806.     (temps locs)
  807.     (emit-psetq-moves node block fun nil)
  808.       
  809.       (mapc #'(lambda (temp loc)
  810.         (emit-move node block temp loc))
  811.         temps locs))
  812.   (undefined-value))
  813.  
  814.  
  815. ;;; IR2-CONVERT-LOCAL-CALL-ARGS  --  Internal
  816. ;;;
  817. ;;;    Do stuff to set up the arguments to a non-tail local call (including
  818. ;;; implicit environment args.)  We allocate a frame (returning the FP and
  819. ;;; NFP), and also compute the TN-Refs list for the values to pass and the list
  820. ;;; of passing location TNs.
  821. ;;;
  822. (defun ir2-convert-local-call-args (node block fun)
  823.   (declare (type combination node) (type ir2-block block) (type clambda fun))
  824.   (let ((fp (make-stack-pointer-tn))
  825.     (nfp (make-number-stack-pointer-tn))
  826.     (old-fp (make-stack-pointer-tn)))
  827.     (multiple-value-bind (temps locs)
  828.              (emit-psetq-moves node block fun old-fp)
  829.       (vop current-fp node block old-fp)
  830.       (vop allocate-frame node block
  831.        (environment-info (lambda-environment fun))
  832.        fp nfp)
  833.       (values fp nfp temps (mapcar #'make-alias-tn locs)))))
  834.  
  835.  
  836. ;;; IR2-Convert-Local-Known-Call  --  Internal
  837. ;;;
  838. ;;;    Handle a non-TR known-values local call.  We Emit the call, then move
  839. ;;; the results to the continuation's destination.
  840. ;;;
  841. (defun ir2-convert-local-known-call (node block fun returns cont start)
  842.   (declare (type node node) (type ir2-block block) (type clambda fun)
  843.        (type return-info returns) (type continuation cont)
  844.        (type label start))
  845.   (multiple-value-bind (fp nfp temps arg-locs)
  846.                (ir2-convert-local-call-args node block fun)
  847.     (let ((locs (return-info-locations returns)))
  848.       (vop* known-call-local node block
  849.         (fp nfp (reference-tn-list temps nil))
  850.         ((reference-tn-list locs t))
  851.         arg-locs (environment-info (lambda-environment fun)) start)
  852.       (move-continuation-result node block locs cont)))
  853.   (undefined-value))
  854.  
  855.  
  856. ;;; IR2-Convert-Local-Unknown-Call  --  Internal
  857. ;;;
  858. ;;;    Handle a non-TR unknown-values local call.  We do different things
  859. ;;; depending on what kind of values the continuation wants.
  860. ;;;
  861. ;;;    If Cont is :Unknown, then we use the "Multiple-" variant, directly
  862. ;;; specifying the continuation's Locs as the VOP results so that we don't have
  863. ;;; to do anything after the call.
  864. ;;;
  865. ;;;    Otherwise, we use Standard-Result-Tns to get wired result TNs, and
  866. ;;; then call Move-Continuation-Result to do any necessary type checks or
  867. ;;; coercions.
  868. ;;;
  869. (defun ir2-convert-local-unknown-call (node block fun cont start)
  870.   (declare (type node node) (type ir2-block block) (type clambda fun)
  871.        (type continuation cont) (type label start))
  872.   (multiple-value-bind (fp nfp temps arg-locs)
  873.                (ir2-convert-local-call-args node block fun)
  874.     (let ((2cont (continuation-info cont))
  875.       (env (environment-info (lambda-environment fun)))
  876.       (temp-refs (reference-tn-list temps nil)))
  877.       (if (and 2cont (eq (ir2-continuation-kind 2cont) :unknown))
  878.       (vop* multiple-call-local node block (fp nfp temp-refs)
  879.         ((reference-tn-list (ir2-continuation-locs 2cont) t))
  880.         arg-locs env start)
  881.       (let ((locs (standard-result-tns cont)))
  882.         (vop* call-local node block
  883.           (fp nfp temp-refs)
  884.           ((reference-tn-list locs t))
  885.           arg-locs env start (length locs))
  886.         (move-continuation-result node block locs cont)))))
  887.   (undefined-value))
  888.  
  889.  
  890. ;;; IR2-Convert-Local-Call  --  Internal
  891. ;;;
  892. ;;;    Dispatch to the appropriate function, depending on whether we have a
  893. ;;; let, tail or normal call.  If the function doesn't return, call it using
  894. ;;; the unknown-value convention.  We could compile it as a tail call, but that
  895. ;;; might seem confusing in the debugger.
  896. ;;;
  897. (defun ir2-convert-local-call (node block)
  898.   (declare (type combination node) (type ir2-block block))
  899.   (let* ((fun (ref-leaf (continuation-use (basic-combination-fun node))))
  900.      (kind (functional-kind fun)))
  901.     (cond ((eq kind :let)
  902.        (ir2-convert-let node block fun))
  903.       ((eq kind :assignment)
  904.        (ir2-convert-assignment node block fun))
  905.       ((node-tail-p node)
  906.        (ir2-convert-tail-local-call node block fun))
  907.       (t
  908.        (let ((start (block-label (node-block (lambda-bind fun))))
  909.          (returns (tail-set-info (lambda-tail-set fun)))
  910.          (cont (node-cont node)))
  911.          (ecase (if returns
  912.             (return-info-kind returns)
  913.             :unknown)
  914.            (:unknown
  915.         (ir2-convert-local-unknown-call node block fun cont start))
  916.            (:fixed
  917.         (ir2-convert-local-known-call node block fun returns
  918.                           cont start)))))))
  919.   (undefined-value))
  920.  
  921.  
  922. ;;;; Full call:
  923.  
  924.  
  925. ;;; Function-Continuation-TN  --  Internal
  926. ;;;
  927. ;;;    Given a function continuation Fun, return as values a TN holding the
  928. ;;; thing that we call and true if the thing is a symbol (false if it is a
  929. ;;; function).  There are three interesting non-symbol cases:
  930. ;;; -- Known to be a function, no check needed: return the continuation loc.
  931. ;;; -- Known to be a function or a symbol, may need to be coerced.
  932. ;;; -- Not known what it is.
  933. ;;;
  934. (defun function-continuation-tn (node block cont)
  935.   (declare (type continuation cont))
  936.   (let* ((2cont (continuation-info cont))
  937.      (name (if (eq (ir2-continuation-kind 2cont) :delayed)
  938.            (let ((res (continuation-function-name cont t)))
  939.              (assert res)
  940.              res)
  941.            nil)))
  942.     (if name
  943.     (values (emit-constant name) t)
  944.     (let* ((locs (ir2-continuation-locs 2cont))
  945.            (loc (first locs))
  946.            (check (continuation-type-check cont))
  947.            (function-ptype (primitive-type-or-lose 'function *backend*)))
  948.       (assert (and (eq (ir2-continuation-kind 2cont) :fixed)
  949.                (= (length locs) 1)))
  950.       (cond ((eq (tn-primitive-type loc) function-ptype)
  951.          (assert (not (eq check t)))
  952.          (values loc nil))
  953.         (t
  954.          (let ((temp (make-normal-tn function-ptype)))
  955.            (cond ((eq (ir2-continuation-primitive-type 2cont)
  956.                   function-ptype)
  957.               (assert (eq check t))
  958.               (emit-type-check node block loc temp
  959.                        (specifier-type 'function)))
  960.              (t
  961.               (when (policy node (> speed brevity))
  962.                 (let ((*compiler-error-context* node))
  963.                   (compiler-note
  964.                    "Called function might be a ~
  965.                    symbol, so must coerce at run-time.")))
  966.  
  967.               (if (eq check t)
  968.                   (vop coerce-to-function node block loc temp)
  969.                   (vop fast-safe-coerce-to-function node block
  970.                    loc temp))))
  971.  
  972.            (values temp nil))))))))
  973.  
  974.  
  975. ;;; MOVE-TAIL-FULL-CALL-ARGS  --  Internal
  976. ;;;
  977. ;;;    Set up the args to Node in the current frame, and return a tn-ref list
  978. ;;; for the passing locations.
  979. ;;;
  980. (defun move-tail-full-call-args (node block)
  981.   (declare (type combination node) (type ir2-block block))
  982.   (let ((args (basic-combination-args node))
  983.     (last nil)
  984.     (first nil))
  985.     (dotimes (num (length args))
  986.       (let ((loc (standard-argument-location num)))
  987.     (emit-move node block (continuation-tn node block (elt args num)) loc)
  988.     (let ((ref (reference-tn loc nil)))
  989.       (if last
  990.           (setf (tn-ref-across last) ref)
  991.           (setf first ref))
  992.       (setq last ref))))
  993.       first))
  994.  
  995.  
  996. ;;; IR2-Convert-Tail-Full-Call  --  Internal
  997. ;;;
  998. ;;;    Move the arguments into the passing locations and do a (possibly named)
  999. ;;; tail call.
  1000. ;;;
  1001. (defun ir2-convert-tail-full-call (node block)
  1002.   (declare (type combination node) (type ir2-block block))
  1003.   (let* ((env (environment-info (node-environment node)))
  1004.      (args (basic-combination-args node))
  1005.      (nargs (length args))
  1006.      (pass-refs (move-tail-full-call-args node block))
  1007.      (old-fp (ir2-environment-old-fp env))
  1008.      (return-pc (ir2-environment-return-pc env)))
  1009.  
  1010.     (multiple-value-bind
  1011.     (fun-tn named)
  1012.     (function-continuation-tn node block (basic-combination-fun node))
  1013.       (if named
  1014.       (vop* tail-call-named node block
  1015.         (fun-tn old-fp return-pc pass-refs)
  1016.         (nil)
  1017.         nargs)
  1018.       (vop* tail-call node block
  1019.         (fun-tn old-fp return-pc pass-refs)
  1020.         (nil)
  1021.         nargs))))
  1022.  
  1023.   (undefined-value))
  1024.  
  1025.  
  1026. ;;; IR2-CONVERT-FULL-CALL-ARGS  --  Internal
  1027. ;;;
  1028. ;;;    Like IR2-CONVERT-LOCAL-CALL-ARGS, only different.
  1029. ;;;
  1030. (defun ir2-convert-full-call-args (node block)
  1031.   (declare (type combination node) (type ir2-block block))
  1032.   (let* ((args (basic-combination-args node))
  1033.      (fp (make-stack-pointer-tn))
  1034.      (nargs (length args)))
  1035.     (vop allocate-full-call-frame node block nargs fp)
  1036.     (collect ((locs))
  1037.       (let ((last nil)
  1038.         (first nil))
  1039.     (dotimes (num nargs)
  1040.       (locs (standard-argument-location num))
  1041.       (let ((ref (reference-tn (continuation-tn node block (elt args num))
  1042.                    nil)))
  1043.         (if last
  1044.         (setf (tn-ref-across last) ref)
  1045.         (setf first ref))
  1046.         (setq last ref)))
  1047.     
  1048.     (values fp first (locs) nargs)))))
  1049.  
  1050.  
  1051. ;;; IR2-Convert-Fixed-Full-Call  --  Internal
  1052. ;;;
  1053. ;;;    Do full call when a fixed number of values are desired.  We make
  1054. ;;; Standard-Result-TNs for our continuation, then deliver the result using
  1055. ;;; Move-Continuation-Result.  We do named or normal call, as appropriate.
  1056. ;;;
  1057. (defun ir2-convert-fixed-full-call (node block)
  1058.   (declare (type combination node) (type ir2-block block))
  1059.   (multiple-value-bind (fp args arg-locs nargs)
  1060.                (ir2-convert-full-call-args node block)
  1061.     (let* ((cont (node-cont node))
  1062.        (locs (standard-result-tns cont))
  1063.        (loc-refs (reference-tn-list locs t))
  1064.        (nvals (length locs)))
  1065.       (multiple-value-bind
  1066.       (fun-tn named)
  1067.       (function-continuation-tn node block (basic-combination-fun node))
  1068.     (if named
  1069.         (vop* call-named node block (fp fun-tn args) (loc-refs)
  1070.           arg-locs nargs nvals)
  1071.         (vop* call node block (fp fun-tn args) (loc-refs)
  1072.           arg-locs nargs nvals))
  1073.     (move-continuation-result node block locs cont))))
  1074.   (undefined-value))
  1075.  
  1076.  
  1077. ;;; IR2-Convert-Multiple-Full-Call  --  Internal
  1078. ;;;
  1079. ;;;    Do full call when unknown values are desired.
  1080. ;;;
  1081. (defun ir2-convert-multiple-full-call (node block)
  1082.   (declare (type combination node) (type ir2-block block))
  1083.   (multiple-value-bind (fp args arg-locs nargs)
  1084.                (ir2-convert-full-call-args node block)
  1085.     (let* ((cont (node-cont node))
  1086.        (locs (ir2-continuation-locs (continuation-info cont)))
  1087.        (loc-refs (reference-tn-list locs t)))
  1088.       (multiple-value-bind
  1089.       (fun-tn named)
  1090.       (function-continuation-tn node block (basic-combination-fun node))
  1091.     (if named
  1092.         (vop* multiple-call-named node block (fp fun-tn args) (loc-refs)
  1093.           arg-locs nargs)
  1094.         (vop* multiple-call node block (fp fun-tn args) (loc-refs)
  1095.           arg-locs nargs)))))
  1096.   (undefined-value))
  1097.  
  1098.  
  1099. ;;; IR2-Convert-Full-Call  --  Internal
  1100. ;;;
  1101. ;;;    If the call is in a TR position and the return convention is standard,
  1102. ;;; then do a tail full call.  If one or fewer values are desired, then use a
  1103. ;;; single-value call, otherwise use a multiple-values call.
  1104. ;;;
  1105. (defun ir2-convert-full-call (node block)
  1106.   (declare (type combination node) (type ir2-block block))
  1107.   (let ((2cont (continuation-info (node-cont node))))
  1108.     (cond ((node-tail-p node)
  1109.        (ir2-convert-tail-full-call node block))
  1110.       ((and 2cont
  1111.         (eq (ir2-continuation-kind 2cont) :unknown))
  1112.        (ir2-convert-multiple-full-call node block))
  1113.       (t
  1114.        (ir2-convert-fixed-full-call node block))))
  1115.   (undefined-value))
  1116.  
  1117.  
  1118. ;;;; Function entry:
  1119.  
  1120. ;;; Init-XEP-Environment  --  Internal
  1121. ;;;
  1122. ;;;    Do all the stuff that needs to be done on XEP entry:
  1123. ;;; -- Create frame
  1124. ;;; -- Copy any more arg
  1125. ;;; -- Set up the environment, accessing any closure variables
  1126. ;;; -- Move args from the standard passing locations to their internal
  1127. ;;;    locations.
  1128. ;;; 
  1129. (defun init-xep-environment (node block fun)
  1130.   (declare (type bind node) (type ir2-block block) (type clambda fun))
  1131.   (let ((start-label (entry-info-offset (leaf-info fun)))
  1132.     (env (environment-info (node-environment node))))
  1133.     (vop xep-allocate-frame node block start-label)
  1134.     (let ((ef (functional-entry-function fun)))
  1135.       (when (and (optional-dispatch-p ef)
  1136.          (optional-dispatch-more-entry ef))
  1137.     (vop copy-more-arg node block (optional-dispatch-max-args ef))))
  1138.     
  1139.     (if (ir2-environment-environment env)
  1140.     (let ((closure
  1141.            (make-normal-tn (backend-any-primitive-type *backend*))))
  1142.       (vop setup-closure-environment node block start-label closure)
  1143.       (let ((n -1))
  1144.         (dolist (loc (ir2-environment-environment env))
  1145.           (vop closure-ref node block closure (incf n) (cdr loc)))))
  1146.     (vop setup-environment node block start-label))
  1147.     
  1148.     (unless (eq (functional-kind fun) :top-level)
  1149.       (let ((vars (lambda-vars fun))
  1150.         (n 0))
  1151.     (when (leaf-refs (first vars))
  1152.       (emit-move node block (make-argument-count-location)
  1153.              (leaf-info (first vars))))
  1154.     (dolist (arg (rest vars))
  1155.       (when (leaf-refs arg)
  1156.         (let ((pass (standard-argument-location n))
  1157.           (home (leaf-info arg)))
  1158.           (if (lambda-var-indirect arg)
  1159.           (vop make-value-cell node block pass home)
  1160.           (emit-move node block pass home))))
  1161.       (incf n))))
  1162.     
  1163.     (emit-move node block (make-old-fp-passing-location t)
  1164.            (ir2-environment-old-fp env)))
  1165.   
  1166.   (undefined-value))
  1167.  
  1168.  
  1169. ;;; IR2-Convert-Bind  --  Internal
  1170. ;;;
  1171. ;;;    Emit function prolog code.  This is only called on bind nodes for
  1172. ;;; functions that allocate environments.  All semantics of let calls are
  1173. ;;; handled by IR2-Convert-Let.
  1174. ;;;
  1175. ;;;    If not an XEP, all we do is move the return PC from its passing
  1176. ;;; location, since in a local call, the caller allocates the frame and sets up
  1177. ;;; the arguments.
  1178. ;;;
  1179. (defun ir2-convert-bind (node block)
  1180.   (declare (type bind node) (type ir2-block block))
  1181.   (let* ((fun (bind-lambda node))
  1182.      (env (environment-info (lambda-environment fun))))
  1183.     (assert (member (functional-kind fun)
  1184.             '(nil :external :optional :top-level :cleanup)))
  1185.  
  1186.     (when (external-entry-point-p fun)
  1187.       (init-xep-environment node block fun)
  1188.       (when *collect-dynamic-statistics*
  1189.     (vop count-me node block *dynamic-counts-tn*
  1190.          (1- (block-number (ir2-block-block block))))))
  1191.  
  1192.     (emit-move node block (ir2-environment-return-pc-pass env)
  1193.            (ir2-environment-return-pc env))
  1194.  
  1195.     (let ((lab (gen-label)))
  1196.       (setf (ir2-environment-environment-start env) lab)
  1197.       (vop note-environment-start node block lab)))
  1198.   
  1199.   (undefined-value))
  1200.  
  1201.  
  1202. ;;;; Function return:
  1203.  
  1204. ;;; IR2-Convert-Return  --  Internal
  1205. ;;;
  1206. ;;;    Do stuff to return from a function with the specified values and
  1207. ;;; convention.  If the return convention is :Fixed and we aren't returning
  1208. ;;; from an XEP, then we do a known return (letting representation selection
  1209. ;;; insert the correct move-arg VOPs.)  Otherwise, we use the unknown-values
  1210. ;;; convention.  If there is a fixed number of return values, then use Return,
  1211. ;;; otherwise use Return-Multiple.
  1212. ;;;
  1213. (defun ir2-convert-return (node block)
  1214.   (declare (type creturn node) (type ir2-block block))
  1215.   (let* ((cont (return-result node))
  1216.      (2cont (continuation-info cont))
  1217.      (cont-kind (ir2-continuation-kind 2cont))
  1218.      (fun (return-lambda node))
  1219.      (env (environment-info (lambda-environment fun)))
  1220.      (old-fp (ir2-environment-old-fp env))
  1221.      (return-pc (ir2-environment-return-pc env))
  1222.      (returns (tail-set-info (lambda-tail-set fun))))
  1223.     (cond
  1224.      ((and (eq (return-info-kind returns) :fixed)
  1225.        (not (external-entry-point-p fun)))
  1226.       (let ((locs (continuation-tns node block cont
  1227.                     (return-info-types returns))))
  1228.     (vop* known-return node block
  1229.           (old-fp return-pc (reference-tn-list locs nil))
  1230.           (nil)
  1231.           (return-info-locations returns))))
  1232.      ((eq cont-kind :fixed)
  1233.       (let* ((types (mapcar #'tn-primitive-type (ir2-continuation-locs 2cont)))
  1234.          (cont-locs (continuation-tns node block cont types))
  1235.          (nvals (length cont-locs))
  1236.          (locs (make-standard-value-tns nvals)))
  1237.     (mapc #'(lambda (val loc)
  1238.           (emit-move node block val loc))
  1239.           cont-locs
  1240.           locs)
  1241.     (vop* return node block
  1242.           (old-fp return-pc (reference-tn-list locs nil))
  1243.           (nil)
  1244.           nvals)))
  1245.      (t
  1246.       (assert (eq cont-kind :unknown))
  1247.       (vop* return-multiple node block
  1248.         (old-fp return-pc
  1249.             (reference-tn-list (ir2-continuation-locs 2cont) nil))
  1250.         (nil)))))
  1251.  
  1252.   (undefined-value))
  1253.  
  1254.  
  1255. ;;;; Debugger hooks:
  1256.  
  1257. ;;; This is used by the debugger to find the top function on the stack.  It
  1258. ;;; returns the OLD-FP and RETURN-PC for the current function as multiple
  1259. ;;; values.
  1260. ;;;
  1261. (defoptimizer (kernel:%caller-frame-and-pc ir2-convert) (() node block)
  1262.   (let ((env (environment-info (node-environment node))))
  1263.     (move-continuation-result node block
  1264.                   (list (ir2-environment-old-fp env)
  1265.                     (ir2-environment-return-pc env))
  1266.                   (node-cont node))))
  1267.                 
  1268.  
  1269. ;;;; Multiple values:
  1270.  
  1271. ;;; IR2-Convert-MV-Bind  --  Internal
  1272. ;;;
  1273. ;;;    Almost identical to IR2-Convert-Let.  Since LTN annotates the
  1274. ;;; continuation for the correct number of values (with the continuation user
  1275. ;;; responsible for defaulting), we can just pick them up from the
  1276. ;;; continuation.
  1277. ;;;
  1278. (defun ir2-convert-mv-bind (node block)
  1279.   (declare (type mv-combination node) (type ir2-block block))
  1280.   (let* ((cont (first (basic-combination-args node)))
  1281.      (fun (ref-leaf (continuation-use (basic-combination-fun node))))
  1282.      (vars (lambda-vars fun)))
  1283.     (assert (eq (functional-kind fun) :mv-let))
  1284.     (mapc #'(lambda (src var)
  1285.           (when (leaf-refs var)
  1286.         (let ((dest (leaf-info var)))
  1287.           (if (lambda-var-indirect var)
  1288.               (vop make-value-cell node block src dest)
  1289.               (emit-move node block src dest)))))
  1290.       (continuation-tns node block cont
  1291.                 (mapcar #'(lambda (x)
  1292.                     (primitive-type (leaf-type x)))
  1293.                     vars))
  1294.       vars))
  1295.   (undefined-value))
  1296.  
  1297.  
  1298. ;;; IR2-Convert-MV-Call  --  Internal
  1299. ;;;
  1300. ;;;    Emit the appropriate fixed value, unknown value or tail variant of
  1301. ;;; Call-Variable.  Note that we only need to pass the values start for the
  1302. ;;; first argument: all the other argument continuation TNs are ignored.  This
  1303. ;;; is because we require all of the values globs to be contiguous and on stack
  1304. ;;; top. 
  1305. ;;;
  1306. (defun ir2-convert-mv-call (node block)
  1307.   (declare (type mv-combination node) (type ir2-block block))
  1308.   (assert (basic-combination-args node))
  1309.   (let* ((start-cont (continuation-info (first (basic-combination-args node))))
  1310.      (start (first (ir2-continuation-locs start-cont)))
  1311.      (tails (and (node-tail-p node)
  1312.              (lambda-tail-set (node-home-lambda node))))
  1313.      (cont (node-cont node))
  1314.      (2cont (continuation-info cont)))
  1315.     (multiple-value-bind
  1316.     (fun named)
  1317.     (function-continuation-tn node block (basic-combination-fun node))
  1318.       (assert (and (not named)
  1319.            (eq (ir2-continuation-kind start-cont) :unknown)))
  1320.       (cond
  1321.        (tails
  1322.     (let ((env (environment-info (node-environment node))))
  1323.       (vop tail-call-variable node block start fun
  1324.            (ir2-environment-old-fp env)
  1325.            (ir2-environment-return-pc env))))
  1326.        ((and 2cont
  1327.          (eq (ir2-continuation-kind 2cont) :unknown))
  1328.     (vop* multiple-call-variable node block (start fun nil)
  1329.           ((reference-tn-list (ir2-continuation-locs 2cont) t))))
  1330.        (t
  1331.     (let ((locs (standard-result-tns cont)))
  1332.       (vop* call-variable node block (start fun nil)
  1333.         ((reference-tn-list locs t)) (length locs))
  1334.       (move-continuation-result node block locs cont)))))))
  1335.  
  1336.  
  1337. ;;; %Pop-Values IR2 convert  --  Internal
  1338. ;;;
  1339. ;;;    Reset the stack pointer to the start of the specified unknown-values
  1340. ;;; continuation (discarding it and all values globs on top of it.)
  1341. ;;;
  1342. (defoptimizer (%pop-values ir2-convert) ((continuation) node block)
  1343.   (let ((2cont (continuation-info (continuation-value continuation))))
  1344.     (assert (eq (ir2-continuation-kind 2cont) :unknown))
  1345.     (vop reset-stack-pointer node block
  1346.      (first (ir2-continuation-locs 2cont)))))
  1347.  
  1348.  
  1349. ;;; Values IR2 convert  --  Internal
  1350. ;;;
  1351. ;;;    Deliver the values TNs to Cont using Move-Continuation-Result.
  1352. ;;;
  1353. (defoptimizer (values ir2-convert) ((&rest values) node block)
  1354.   (let ((tns (mapcar #'(lambda (x)
  1355.              (continuation-tn node block x))
  1356.              values)))
  1357.     (move-continuation-result node block tns (node-cont node))))
  1358.  
  1359.  
  1360. ;;; Values-List IR2 convert  --  Internal
  1361. ;;;
  1362. ;;;    In the normal case where unknown values are desired, we use the
  1363. ;;; Values-List VOP.  In the relatively unimportant case of Values-List for a
  1364. ;;; fixed number of values, we punt by doing a full call to the Values-List
  1365. ;;; function.  This gets the full call VOP to deal with defaulting any
  1366. ;;; unsupplied values.  It seems unworthwhile to optimize this case.
  1367. ;;;
  1368. (defoptimizer (values-list ir2-convert) ((list) node block)
  1369.   (let* ((cont (node-cont node))
  1370.      (2cont (continuation-info cont)))
  1371.     (when 2cont
  1372.       (ecase (ir2-continuation-kind 2cont)
  1373.     (:fixed (ir2-convert-full-call node block))
  1374.     (:unknown
  1375.      (let ((locs (ir2-continuation-locs 2cont)))
  1376.        (vop* values-list node block
  1377.          ((continuation-tn node block list) nil)
  1378.          ((reference-tn-list locs t)))))))))
  1379.  
  1380.  
  1381. ;;;; Special binding:
  1382.  
  1383. ;;; %Special-Bind, %Special-Unbind IR2 convert  --  Internal
  1384. ;;;
  1385. ;;;    Trivial, given our assumption of a shallow-binding implementation.
  1386. ;;;
  1387. (defoptimizer (%special-bind ir2-convert) ((var value) node block)
  1388.   (let ((name (leaf-name (continuation-value var))))
  1389.     (vop bind node block (continuation-tn node block value)
  1390.      (emit-constant name))))
  1391. ;;;
  1392. (defoptimizer (%special-unbind ir2-convert) ((var) node block)
  1393.   (vop unbind node block))
  1394.  
  1395.  
  1396. ;;; PROGV IR1 convert  --  Internal
  1397. ;;;
  1398. ;;; ### Not clear that this really belongs in this file, or should really be
  1399. ;;; done this way, but this is the least violation of abstraction in the
  1400. ;;; current setup.  We don't want to wire shallow-binding assumptions into
  1401. ;;; IR1tran.
  1402. ;;;
  1403. (def-ir1-translator progv ((vars vals &body body) start cont)
  1404.   (ir1-convert
  1405.    start cont
  1406.    (if *converting-for-interpreter*
  1407.        `(%progv ,vars ,vals #'(lambda () ,@body))
  1408.        (once-only ((n-save-bs '(%primitive current-binding-pointer)))
  1409.      `(unwind-protect
  1410.           (progn
  1411.         (mapc #'(lambda (var val)
  1412.               (%primitive bind val var))
  1413.               ,vars
  1414.               ,vals)
  1415.         ,@body)
  1416.         (%primitive unbind-to-here ,n-save-bs))))))
  1417.  
  1418.  
  1419. ;;;; Non-local exit:
  1420.  
  1421. ;;; IR2-Convert-Exit  --  Internal
  1422. ;;;
  1423. ;;;    Convert a non-local lexical exit.  First find the NLX-Info in our
  1424. ;;; environment.  Note that this is never called on the escape exits for Catch
  1425. ;;; and Unwind-Protect, since the escape functions aren't IR2 converted.
  1426. ;;;
  1427. (defun ir2-convert-exit (node block)
  1428.   (declare (type exit node) (type ir2-block block))
  1429.   (let ((loc (find-in-environment (find-nlx-info (exit-entry node)
  1430.                          (node-cont node))
  1431.                   (node-environment node)))
  1432.     (temp (make-stack-pointer-tn))
  1433.     (value (exit-value node)))
  1434.     (vop value-cell-ref node block loc temp)
  1435.     (if value
  1436.     (let ((locs (ir2-continuation-locs (continuation-info value))))
  1437.       (vop unwind node block temp (first locs) (second locs)))
  1438.     (let ((0-tn (emit-constant 0)))
  1439.       (vop unwind node block temp 0-tn 0-tn))))
  1440.  
  1441.   (undefined-value))
  1442.  
  1443.  
  1444. ;;; Cleanup-point doesn't to anything except prevent the body from being
  1445. ;;; entirely deleted.
  1446. ;;;
  1447. (defoptimizer (%cleanup-point ir2-convert) (() node block) node block)
  1448.  
  1449.   
  1450. ;;; This function invalidates a lexical exit on exiting from the dynamic
  1451. ;;; extent.  This is done by storing 0 into the indirect value cell that holds
  1452. ;;; the closed unwind block.
  1453. ;;;
  1454. (defoptimizer (%lexical-exit-breakup ir2-convert) ((info) node block)
  1455.   (vop value-cell-set node block
  1456.        (find-in-environment (continuation-value info) (node-environment node))
  1457.        (emit-constant 0)))
  1458.  
  1459.  
  1460. ;;; IR2-Convert-Throw  --  Internal
  1461. ;;;
  1462. ;;;    We have to do a spurious move of no values to the result continuation so
  1463. ;;; that lifetime analysis won't get confused.
  1464. ;;;
  1465. (defun ir2-convert-throw (node block)
  1466.   (declare (type mv-combination node) (type ir2-block block))
  1467.   (let ((args (basic-combination-args node)))
  1468.     (vop* throw node block
  1469.       ((continuation-tn node block (first args))
  1470.        (reference-tn-list
  1471.         (ir2-continuation-locs (continuation-info (second args)))
  1472.         nil))
  1473.       (nil)))
  1474.  
  1475.   (move-continuation-result node block () (node-cont node))
  1476.   (undefined-value))
  1477.  
  1478.  
  1479. ;;; Emit-NLX-Start  --  Internal
  1480. ;;;
  1481. ;;;    Emit code to set up a non-local-exit.  Info is the NLX-Info for the
  1482. ;;; exit, and Tag is the continuation for the catch tag (if any.)  We get at
  1483. ;;; the target PC by passing in the label to the vop.  The vop is responsible
  1484. ;;; for building a return-PC object.
  1485. ;;;
  1486. (defun emit-nlx-start (node block info tag)
  1487.   (declare (type node node) (type ir2-block block) (type nlx-info info)
  1488.        (type (or continuation null) tag))
  1489.   (let* ((2info (nlx-info-info info))
  1490.      (kind (cleanup-kind (nlx-info-cleanup info)))
  1491.      (block-tn (environment-live-tn
  1492.             (make-normal-tn (primitive-type-or-lose 'catch-block
  1493.                                 *backend*))
  1494.             (node-environment node)))
  1495.      (res (make-stack-pointer-tn))
  1496.      (target-label (ir2-nlx-info-target 2info)))
  1497.  
  1498.     (vop current-binding-pointer node block
  1499.      (car (ir2-nlx-info-dynamic-state 2info)))
  1500.     (vop* save-dynamic-state node block
  1501.       (nil)
  1502.       ((reference-tn-list (cdr (ir2-nlx-info-dynamic-state 2info)) t)))
  1503.     (vop current-stack-pointer node block (ir2-nlx-info-save-sp 2info))
  1504.  
  1505.     (ecase kind
  1506.       (:catch
  1507.        (vop make-catch-block node block block-tn
  1508.         (continuation-tn node block tag) target-label res))
  1509.       ((:unwind-protect :block :tagbody)
  1510.        (vop make-unwind-block node block block-tn target-label res)))
  1511.  
  1512.     (ecase kind
  1513.       ((:block :tagbody)
  1514.        (vop make-value-cell node block res (ir2-nlx-info-home 2info)))
  1515.       (:unwind-protect
  1516.        (vop set-unwind-protect node block block-tn))
  1517.       (:catch)))
  1518.  
  1519.   (undefined-value))
  1520.  
  1521.  
  1522. ;;; IR2-Convert-Entry  --  Internal
  1523. ;;;
  1524. ;;;    Scan each of Entry's exits, setting up the exit for each lexical exit.
  1525. ;;;
  1526. (defun ir2-convert-entry (node block)
  1527.   (declare (type entry node) (type ir2-block block))
  1528.   (dolist (exit (entry-exits node))
  1529.     (let ((info (find-nlx-info node (node-cont exit))))
  1530.       (when (and info
  1531.          (member (cleanup-kind (nlx-info-cleanup info))
  1532.              '(:block :tagbody)))
  1533.     (emit-nlx-start node block info nil))))
  1534.   (undefined-value))
  1535.  
  1536.  
  1537. ;;; %Catch, %Unwind-Protect IR2 convert  --  Internal
  1538. ;;;
  1539. ;;;    Set up the unwind block for these guys.
  1540. ;;;
  1541. (defoptimizer (%catch ir2-convert) ((info-cont tag) node block)
  1542.   (emit-nlx-start node block (continuation-value info-cont) tag))
  1543. ;;;
  1544. (defoptimizer (%unwind-protect ir2-convert) ((info-cont cleanup) node block)
  1545.   (emit-nlx-start node block (continuation-value info-cont) nil))
  1546.  
  1547.  
  1548. ;;; %NLX-Entry IR2 convert  --  Internal
  1549. ;;;
  1550. ;;; Emit the entry code for a non-local exit.  We receive values and restore
  1551. ;;; dynamic state.
  1552. ;;;
  1553. ;;; In the case of a lexical exit or Catch, we look at the exit continuation's
  1554. ;;; kind to determine which flavor of entry VOP to emit.  If unknown values,
  1555. ;;; emit the xxx-MULTIPLE variant to the continuation locs.  If fixed values,
  1556. ;;; make the appropriate number of temps in the standard values locations and
  1557. ;;; use the other variant, delivering the temps to the continuation using
  1558. ;;; Move-Continuation-Result.
  1559. ;;;
  1560. ;;; In the Unwind-Protect case, we deliver the first register argument, the
  1561. ;;; argument count and the argument pointer to our continuation as multiple
  1562. ;;; values.  These values are the block exited to and the values start and
  1563. ;;; count.
  1564. ;;;
  1565. ;;; After receiving values, we restore dynamic state.  Except in the
  1566. ;;; Unwind-Protect case, the values receiving restores the stack pointer.  In
  1567. ;;; an Unwind-Protect cleanup, we want to leave the stack pointer alone, since
  1568. ;;; the thrown values are still out there.
  1569. ;;;
  1570. (defoptimizer (%nlx-entry ir2-convert) ((info-cont) node block)
  1571.   (let* ((info (continuation-value info-cont))
  1572.      (cont (nlx-info-continuation info))
  1573.      (2cont (continuation-info cont))
  1574.      (2info (nlx-info-info info))
  1575.      (top-loc (ir2-nlx-info-save-sp 2info))
  1576.      (start-loc (make-old-fp-passing-location t))
  1577.      (count-loc (make-argument-count-location))
  1578.      (target (ir2-nlx-info-target 2info)))
  1579.  
  1580.     (ecase (cleanup-kind (nlx-info-cleanup info))
  1581.       ((:catch :block :tagbody)
  1582.        (if (and 2cont (eq (ir2-continuation-kind 2cont) :unknown))
  1583.        (vop* nlx-entry-multiple node block
  1584.          (top-loc start-loc count-loc nil)
  1585.          ((reference-tn-list (ir2-continuation-locs 2cont) t))
  1586.          target)
  1587.        (let ((locs (standard-result-tns cont)))
  1588.          (vop* nlx-entry node block
  1589.            (top-loc start-loc count-loc nil)
  1590.            ((reference-tn-list locs t))
  1591.            target
  1592.            (length locs))
  1593.          (move-continuation-result node block locs cont))))
  1594.       (:unwind-protect
  1595.        (let ((block-loc (standard-argument-location 0)))
  1596.      (vop uwp-entry node block target block-loc start-loc count-loc)
  1597.      (move-continuation-result
  1598.       node block
  1599.       (list block-loc start-loc count-loc)
  1600.       cont))))
  1601.  
  1602.     (when *collect-dynamic-statistics*
  1603.       (vop count-me node block *dynamic-counts-tn*
  1604.        (1- (block-number (ir2-block-block block)))))
  1605.  
  1606.     (vop* restore-dynamic-state node block
  1607.       ((reference-tn-list (cdr (ir2-nlx-info-dynamic-state 2info)) nil))
  1608.       (nil))
  1609.     (vop unbind-to-here node block
  1610.      (car (ir2-nlx-info-dynamic-state 2info)))))
  1611.  
  1612.  
  1613. ;;;; N-arg functions:
  1614.  
  1615. (macrolet ((frob (name)
  1616.          `(defoptimizer (,name ir2-convert) ((&rest args) node block)
  1617.         (let* ((refs (move-tail-full-call-args node block))
  1618.                (cont (node-cont node))
  1619.                (res (continuation-result-tns
  1620.                  cont
  1621.                  (list (primitive-type (specifier-type 'list))))))
  1622.           (vop* ,name node block (refs) ((first res) nil)
  1623.             (length args))
  1624.           (move-continuation-result node block res cont)))))
  1625.   (frob list)
  1626.   (frob list*))
  1627.  
  1628.  
  1629. ;;;; Structure accessors:
  1630. ;;;
  1631. ;;;    These guys have to bizarrely determine the slot offset by looking at the
  1632. ;;; called function.
  1633.  
  1634. (defoptimizer (%slot-accessor ir2-convert) ((str) node block)
  1635.   (let* ((cont (node-cont node))
  1636.      (res (continuation-result-tns cont
  1637.                        (list (backend-any-primitive-type
  1638.                           *backend*)))))
  1639.     (vop structure-ref node block
  1640.      (continuation-tn node block str)
  1641.      (dsd-index
  1642.       (slot-accessor-slot
  1643.        (ref-leaf
  1644.         (continuation-use
  1645.          (combination-fun node)))))
  1646.      (first res))
  1647.     (move-continuation-result node block res cont)))
  1648.  
  1649. (defoptimizer (%slot-setter ir2-convert) ((value str) node block)
  1650.   (let ((val (continuation-tn node block value)))
  1651.     (vop structure-set node block
  1652.      (continuation-tn node block str)
  1653.      val
  1654.      (dsd-index
  1655.       (slot-accessor-slot
  1656.        (ref-leaf
  1657.         (continuation-use
  1658.          (combination-fun node))))))
  1659.   
  1660.     (move-continuation-result node block (list val) (node-cont node))))
  1661.  
  1662.  
  1663. ;;; IR2-Convert  --  Interface
  1664. ;;;
  1665. ;;;    Convert the code in a component into VOPs.
  1666. ;;;
  1667. (defun ir2-convert (component)
  1668.   (declare (type component component))
  1669.   (let ((*dynamic-counts-tn*
  1670.      (when *collect-dynamic-statistics*
  1671.        (let ((num 0))
  1672.          (declare (fixnum num))
  1673.          (do-blocks-backwards (block component :both)
  1674.            (setf (block-number block) (incf num))))
  1675.        (let* ((blocks
  1676.            (block-number (block-next (component-head component))))
  1677.           (counts-vector
  1678.            (make-array blocks
  1679.                    :element-type '(unsigned-byte 32)
  1680.                    :initial-element 0))
  1681.           (info (make-dyncount-info
  1682.              :for (component-name component)
  1683.              :counts counts-vector
  1684.              :vops (make-array blocks :initial-element nil))))
  1685.          (setf (ir2-component-dyncount-info (component-info component))
  1686.            info)
  1687.          (emit-constant info)
  1688.          (emit-constant counts-vector)))))
  1689.     (do-blocks (block component)
  1690.       (when *collect-dynamic-statistics*
  1691.     (let ((first-node (continuation-next (block-start block))))
  1692.       (unless (or (and (bind-p first-node)
  1693.                (external-entry-point-p (bind-lambda first-node)))
  1694.               (eq (continuation-function-name (node-cont first-node))
  1695.               '%nlx-entry))
  1696.         (vop count-me first-node (block-info block)
  1697.          *dynamic-counts-tn*
  1698.          (1- (block-number block))))))
  1699.       (ir2-convert-block block)))
  1700.   (undefined-value))
  1701.  
  1702.  
  1703. ;;; Finish-IR2-Block  --  Internal
  1704. ;;;
  1705. ;;;    If necessary, emit a terminal unconditional branch to go to the
  1706. ;;; successor block.  If the successor is the component tail, then there isn't
  1707. ;;; really any successor, but if the end is an unknown, non-tail call, then we
  1708. ;;; emit an error trap just in case the function really does return.
  1709. ;;;
  1710. (defun finish-ir2-block (block)
  1711.   (declare (type cblock block))
  1712.   (let* ((2block (block-info block))
  1713.      (last (block-last block))
  1714.      (succ (block-succ block)))
  1715.     (unless (if-p last)
  1716.       (assert (and succ (null (rest succ))))
  1717.       (let ((target (first succ)))
  1718.     (cond ((eq target (component-tail (block-component block)))
  1719.            (when (and (basic-combination-p last)
  1720.               (eq (basic-combination-kind last) :full))
  1721.          (let* ((fun (basic-combination-fun last))
  1722.             (use (continuation-use fun))
  1723.             (name (and (ref-p use) (leaf-name (ref-leaf use)))))
  1724.            (unless (or (node-tail-p last)
  1725.                    (info function info name)
  1726.                    (policy last (zerop safety)))
  1727.              (vop nil-function-returned-error last 2block
  1728.               (if name
  1729.                   (emit-constant name)
  1730.                   (function-continuation-tn last 2block fun)))))))
  1731.           ((not (eq (ir2-block-next 2block) (block-info target)))
  1732.            (vop branch last 2block (block-label target)))))))
  1733.   
  1734.   (undefined-value))
  1735.  
  1736.  
  1737. ;;; IR2-Convert-Block  --  Internal
  1738. ;;;
  1739. ;;;    Convert the code in a block into VOPs.
  1740. ;;;
  1741. (defun ir2-convert-block (block)
  1742.   (declare (type cblock block))
  1743.   (let ((2block (block-info block)))
  1744.     (do-nodes (node cont block)
  1745.       (etypecase node
  1746.     (ref
  1747.      (let ((2cont (continuation-info cont)))
  1748.        (when (and 2cont
  1749.               (not (eq (ir2-continuation-kind 2cont) :delayed)))
  1750.          (ir2-convert-ref node 2block))))
  1751.     (combination
  1752.      (let ((kind (basic-combination-kind node)))
  1753.        (case kind
  1754.          (:local
  1755.           (ir2-convert-local-call node 2block))
  1756.          (:full
  1757.           (ir2-convert-full-call node 2block))
  1758.          (t
  1759.           (let ((fun (function-info-ir2-convert kind)))
  1760.         (cond (fun
  1761.                (funcall fun node 2block))
  1762.               ((eq (basic-combination-info node) :full)
  1763.                (ir2-convert-full-call node 2block))
  1764.               (t
  1765.                (ir2-convert-template node 2block))))))))
  1766.     (cif
  1767.      (when (continuation-info (if-test node))
  1768.        (ir2-convert-if node 2block)))
  1769.     (bind
  1770.      (let ((fun (bind-lambda node)))
  1771.        (when (eq (lambda-home fun) fun)
  1772.          (ir2-convert-bind node 2block))))
  1773.     (creturn
  1774.      (ir2-convert-return node 2block))
  1775.     (cset
  1776.      (ir2-convert-set node 2block))
  1777.     (mv-combination
  1778.      (cond
  1779.       ((eq (basic-combination-kind node) :local)
  1780.        (ir2-convert-mv-bind node 2block))
  1781.       ((eq (continuation-function-name (basic-combination-fun node))
  1782.            '%throw)
  1783.        (ir2-convert-throw node 2block))
  1784.       (t
  1785.        (ir2-convert-mv-call node 2block))))
  1786.     (exit
  1787.      (when (exit-entry node)
  1788.        (ir2-convert-exit node 2block)))
  1789.     (entry
  1790.      (ir2-convert-entry node 2block)))))
  1791.  
  1792.   (finish-ir2-block block)
  1793.  
  1794.   (undefined-value))
  1795.