home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / sparc / call.lisp < prev    next >
Encoding:
Text File  |  1992-05-19  |  39.6 KB  |  1,212 lines

  1. ;;; -*- Package: SPARC -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the Spice 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 Spice Lisp, please contact
  7. ;;; Scott Fahlman (FAHLMAN@CMUC). 
  8. ;;; **********************************************************************
  9. ;;;
  10. ;;; $Header: call.lisp,v 1.8.2.1 92/05/19 16:39:46 ram Exp $
  11. ;;;
  12. ;;; This file contains the VM definition of function call for the SPARC.
  13. ;;;
  14. ;;; Written by William Lott.
  15. ;;;
  16. (in-package "SPARC")
  17.  
  18.  
  19. ;;;; Interfaces to IR2 conversion:
  20.  
  21. ;;; Standard-Argument-Location  --  Interface
  22. ;;;
  23. ;;;    Return a wired TN describing the N'th full call argument passing
  24. ;;; location.
  25. ;;;
  26. (def-vm-support-routine standard-argument-location (n)
  27.   (declare (type unsigned-byte n))
  28.   (if (< n register-arg-count)
  29.       (make-wired-tn *any-primitive-type* register-arg-scn
  30.              (elt register-arg-offsets n))
  31.       (make-wired-tn *any-primitive-type* control-stack-arg-scn n)))
  32.  
  33.  
  34. ;;; Make-Return-PC-Passing-Location  --  Interface
  35. ;;;
  36. ;;;    Make a passing location TN for a local call return PC.  If standard is
  37. ;;; true, then use the standard (full call) location, otherwise use any legal
  38. ;;; location.  Even in the non-standard case, this may be restricted by a
  39. ;;; desire to use a subroutine call instruction.
  40. ;;;
  41. (def-vm-support-routine make-return-pc-passing-location (standard)
  42.   (if standard
  43.       (make-wired-tn *any-primitive-type* register-arg-scn lra-offset)
  44.       (make-restricted-tn *any-primitive-type* register-arg-scn)))
  45.  
  46. ;;; Make-Old-FP-Passing-Location  --  Interface
  47. ;;;
  48. ;;;    Similar to Make-Return-PC-Passing-Location, but makes a location to pass
  49. ;;; Old-FP in.  This is (obviously) wired in the standard convention, but is
  50. ;;; totally unrestricted in non-standard conventions, since we can always fetch
  51. ;;; it off of the stack using the arg pointer.
  52. ;;;
  53. (def-vm-support-routine make-old-fp-passing-location (standard)
  54.   (if standard
  55.       (make-wired-tn *fixnum-primitive-type* immediate-arg-scn ocfp-offset)
  56.       (make-normal-tn *fixnum-primitive-type*)))
  57.  
  58. ;;; Make-Old-FP-Save-Location, Make-Return-PC-Save-Location  --  Interface
  59. ;;;
  60. ;;;    Make the TNs used to hold Old-FP and Return-PC within the current
  61. ;;; function.  We treat these specially so that the debugger can find them at a
  62. ;;; known location.
  63. ;;;
  64. (def-vm-support-routine make-old-fp-save-location (env)
  65.   (specify-save-tn
  66.    (environment-debug-live-tn (make-normal-tn *fixnum-primitive-type*) env)
  67.    (make-wired-tn *fixnum-primitive-type*
  68.           control-stack-arg-scn
  69.           ocfp-save-offset)))
  70. ;;;
  71. (def-vm-support-routine make-return-pc-save-location (env)
  72.   (specify-save-tn
  73.    (environment-debug-live-tn (make-normal-tn *any-primitive-type*) env)
  74.    (make-wired-tn *any-primitive-type*
  75.           control-stack-arg-scn
  76.           lra-save-offset)))
  77.  
  78. ;;; Make-Argument-Count-Location  --  Interface
  79. ;;;
  80. ;;;    Make a TN for the standard argument count passing location.  We only
  81. ;;; need to make the standard location, since a count is never passed when we
  82. ;;; are using non-standard conventions.
  83. ;;;
  84. (def-vm-support-routine make-argument-count-location ()
  85.   (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nargs-offset))
  86.  
  87.  
  88. ;;; MAKE-NFP-TN  --  Interface
  89. ;;;
  90. ;;;    Make a TN to hold the number-stack frame pointer.  This is allocated
  91. ;;; once per component, and is component-live.
  92. ;;;
  93. (def-vm-support-routine make-nfp-tn ()
  94.   (component-live-tn
  95.    (make-wired-tn *fixnum-primitive-type* immediate-arg-scn nfp-offset)))
  96.  
  97. ;;; MAKE-STACK-POINTER-TN ()
  98. ;;; 
  99. (def-vm-support-routine make-stack-pointer-tn ()
  100.   (make-normal-tn *fixnum-primitive-type*))
  101.  
  102. ;;; MAKE-NUMBER-STACK-POINTER-TN ()
  103. ;;; 
  104. (def-vm-support-routine make-number-stack-pointer-tn ()
  105.   (make-normal-tn *fixnum-primitive-type*))
  106.  
  107. ;;; Make-Unknown-Values-Locations  --  Interface
  108. ;;;
  109. ;;;    Return a list of TNs that can be used to represent an unknown-values
  110. ;;; continuation within a function.
  111. ;;;
  112. (def-vm-support-routine make-unknown-values-locations ()
  113.   (list (make-stack-pointer-tn)
  114.     (make-normal-tn *fixnum-primitive-type*)))
  115.  
  116.  
  117. ;;; Select-Component-Format  --  Interface
  118. ;;;
  119. ;;;    This function is called by the Entry-Analyze phase, allowing
  120. ;;; VM-dependent initialization of the IR2-Component structure.  We push
  121. ;;; placeholder entries in the Constants to leave room for additional
  122. ;;; noise in the code object header.
  123. ;;;
  124. (def-vm-support-routine select-component-format (component)
  125.   (declare (type component component))
  126.   (dotimes (i code-constants-offset)
  127.     (vector-push-extend nil
  128.             (ir2-component-constants (component-info component))))
  129.   (undefined-value))
  130.  
  131.  
  132. ;;;; Frame hackery:
  133.  
  134. ;;; BYTES-NEEDED-FOR-NON-DESCRIPTOR-STACK-FRAME -- internal
  135. ;;;
  136. ;;; Return the number of bytes needed for the current non-descriptor stack
  137. ;;; frame.  Non-descriptor stack frames must be multiples of 8 bytes on
  138. ;;; the PMAX.
  139. ;;; 
  140. (defun bytes-needed-for-non-descriptor-stack-frame ()
  141.   (* (logandc2 (1+ (sb-allocated-size 'non-descriptor-stack)) 1)
  142.      vm:word-bytes))
  143.  
  144. ;;; NUMBER-STACK-DISPLACEMENT
  145. ;;;
  146. ;;; The number of bytes reserved above the number stack pointer.  These
  147. ;;; slots are required by architecture for a place to spill register windows.
  148. ;;; 
  149. (defconstant number-stack-displacement
  150.   (* 16 vm:word-bytes))
  151.  
  152. ;;; Used for setting up the Old-FP in local call.
  153. ;;;
  154. (define-vop (current-fp)
  155.   (:results (val :scs (any-reg)))
  156.   (:generator 1
  157.     (move val cfp-tn)))
  158.  
  159. ;;; Used for computing the caller's NFP for use in known-values return.  Only
  160. ;;; works assuming there is no variable size stuff on the nstack.
  161. ;;;
  162. (define-vop (compute-old-nfp)
  163.   (:results (val :scs (any-reg)))
  164.   (:vop-var vop)
  165.   (:generator 1
  166.     (let ((nfp (current-nfp-tn vop)))
  167.       (when nfp
  168.     (inst add val nfp (bytes-needed-for-non-descriptor-stack-frame))))))
  169.  
  170.  
  171. (define-vop (xep-allocate-frame)
  172.   (:info start-lab)
  173.   (:vop-var vop)
  174.   (:temporary (:scs (non-descriptor-reg)) temp)
  175.   (:generator 1
  176.     ;; Make sure the function is aligned, and drop a label pointing to this
  177.     ;; function header.
  178.     (align vm:lowtag-bits)
  179.     (trace-table-entry trace-table-function-prologue)
  180.     (emit-label start-lab)
  181.     ;; Allocate function header.
  182.     (inst function-header-word)
  183.     (dotimes (i (1- vm:function-header-code-offset))
  184.       (inst word 0))
  185.     ;; The start of the actual code.
  186.     ;; Fix CODE, cause the function object was passed in.
  187.     (inst compute-code-from-fn code-tn code-tn start-lab temp)
  188.     ;; Build our stack frames.
  189.     (inst add csp-tn cfp-tn
  190.       (* vm:word-bytes (sb-allocated-size 'control-stack)))
  191.     (let ((nfp-tn (current-nfp-tn vop)))
  192.       (when nfp-tn
  193.     (inst sub nsp-tn (bytes-needed-for-non-descriptor-stack-frame))
  194.     (inst add nfp-tn nsp-tn number-stack-displacement)))
  195.     (trace-table-entry trace-table-normal)))
  196.  
  197. (define-vop (allocate-frame)
  198.   (:results (res :scs (any-reg))
  199.         (nfp :scs (any-reg)))
  200.   (:info callee)
  201.   (:generator 2
  202.     (trace-table-entry trace-table-function-prologue)
  203.     (move res csp-tn)
  204.     (inst add csp-tn csp-tn
  205.       (* vm:word-bytes (sb-allocated-size 'control-stack)))
  206.     (when (ir2-environment-number-stack-p callee)
  207.       (inst sub nsp-tn (bytes-needed-for-non-descriptor-stack-frame))
  208.       (inst add nfp nsp-tn number-stack-displacement))
  209.     (trace-table-entry trace-table-normal)))
  210.  
  211. ;;; Allocate a partial frame for passing stack arguments in a full call.  Nargs
  212. ;;; is the number of arguments passed.  If no stack arguments are passed, then
  213. ;;; we don't have to do anything.
  214. ;;;
  215. (define-vop (allocate-full-call-frame)
  216.   (:info nargs)
  217.   (:results (res :scs (any-reg)))
  218.   (:generator 2
  219.     (when (> nargs register-arg-count)
  220.       (move res csp-tn)
  221.       (inst add csp-tn csp-tn (* nargs vm:word-bytes)))))
  222.  
  223.  
  224.  
  225.  
  226. ;;; Default-Unknown-Values  --  Internal
  227. ;;;
  228. ;;;    Emit code needed at the return-point from an unknown-values call for a
  229. ;;; fixed number of values.  Values is the head of the TN-Ref list for the
  230. ;;; locations that the values are to be received into.  Nvals is the number of
  231. ;;; values that are to be received (should equal the length of Values).
  232. ;;;
  233. ;;;    Move-Temp is a Descriptor-Reg TN used as a temporary.
  234. ;;;
  235. ;;;    This code exploits the fact that in the unknown-values convention, a
  236. ;;; single value return returns at the return PC + 8, whereas a return of other
  237. ;;; than one value returns directly at the return PC.
  238. ;;;
  239. ;;;    If 0 or 1 values are expected, then we just emit an instruction to reset
  240. ;;; the SP (which will only be executed when other than 1 value is returned.)
  241. ;;;
  242. ;;; In the general case, we have to do three things:
  243. ;;;  -- Default unsupplied register values.  This need only be done when a
  244. ;;;     single value is returned, since register values are defaulted by the
  245. ;;;     called in the non-single case.
  246. ;;;  -- Default unsupplied stack values.  This needs to be done whenever there
  247. ;;;     are stack values.
  248. ;;;  -- Reset SP.  This must be done whenever other than 1 value is returned,
  249. ;;;     regardless of the number of values desired.
  250. ;;;
  251. ;;; The general-case code looks like this:
  252. #|
  253.     b regs-defaulted        ; Skip if MVs
  254.     nop
  255.  
  256.     move a1 null-tn            ; Default register values
  257.     ...
  258.     loadi nargs 1            ; Force defaulting of stack values
  259.     move old-fp csp            ; Set up args for SP resetting
  260.  
  261. regs-defaulted
  262.     subcc temp nargs register-arg-count
  263.  
  264.     b :lt default-value-7    ; jump to default code
  265.     loadw move-temp ocfp-tn 6    ; Move value to correct location.
  266.         subcc temp 1
  267.     store-stack-tn val4-tn move-temp
  268.  
  269.     b :lt default-value-8
  270.     loadw move-temp ocfp-tn 7
  271.         subcc temp 1
  272.     store-stack-tn val5-tn move-temp
  273.  
  274.     ...
  275.  
  276. defaulting-done
  277.     move csp ocfp            ; Reset SP.
  278. <end of code>
  279.  
  280. <elsewhere>
  281. default-value-7
  282.     store-stack-tn val4-tn null-tn    ; Nil out 7'th value. (first on stack)
  283.  
  284. default-value-8
  285.     store-stack-tn val5-tn null-tn    ; Nil out 8'th value.
  286.  
  287.     ...
  288.  
  289.     br defaulting-done
  290.         nop
  291. |#
  292. ;;;
  293. (defun default-unknown-values (values nvals move-temp temp lra-label)
  294.   (declare (type (or tn-ref null) values)
  295.        (type unsigned-byte nvals) (type tn move-temp temp))
  296.   (if (<= nvals 1)
  297.       (progn
  298.     (move csp-tn ocfp-tn)
  299.     (inst nop)
  300.     (inst compute-code-from-lra code-tn code-tn lra-label temp))
  301.       (let ((regs-defaulted (gen-label))
  302.         (defaulting-done (gen-label))
  303.         (default-stack-vals (gen-label)))
  304.     ;; Branch off to the MV case.
  305.     (inst b regs-defaulted)
  306.     (if (> nvals register-arg-count)
  307.         (inst subcc temp nargs-tn (fixnum register-arg-count))
  308.         (move csp-tn ocfp-tn))
  309.     
  310.     ;; Do the single value calse.
  311.     (do ((i 1 (1+ i))
  312.          (val (tn-ref-across values) (tn-ref-across val)))
  313.         ((= i (min nvals register-arg-count)))
  314.       (move (tn-ref-tn val) null-tn))
  315.     (when (> nvals register-arg-count)
  316.       (inst b default-stack-vals)
  317.       (move ocfp-tn csp-tn))
  318.     
  319.     (emit-label regs-defaulted)
  320.     (when (> nvals register-arg-count)
  321.       (collect ((defaults))
  322.         (do ((i register-arg-count (1+ i))
  323.          (val (do ((i 0 (1+ i))
  324.                (val values (tn-ref-across val)))
  325.               ((= i register-arg-count) val))
  326.               (tn-ref-across val)))
  327.         ((null val))
  328.           
  329.           (let ((default-lab (gen-label))
  330.             (tn (tn-ref-tn val)))
  331.         (defaults (cons default-lab tn))
  332.         
  333.         (inst b :lt default-lab)
  334.         (inst ld move-temp ocfp-tn (* i vm:word-bytes))
  335.         (inst subcc temp (fixnum 1))
  336.         (store-stack-tn tn move-temp)))
  337.         
  338.         (emit-label defaulting-done)
  339.         (move csp-tn ocfp-tn)
  340.         
  341.         (let ((defaults (defaults)))
  342.           (when defaults
  343.         (assemble (*elsewhere*)
  344.           (emit-label default-stack-vals)
  345.           (trace-table-entry trace-table-function-prologue)
  346.           (do ((remaining defaults (cdr remaining)))
  347.               ((null remaining))
  348.             (let ((def (car remaining)))
  349.               (emit-label (car def))
  350.               (when (null (cdr remaining))
  351.             (inst b defaulting-done))
  352.               (store-stack-tn (cdr def) null-tn)))
  353.           (trace-table-entry trace-table-normal))))))
  354.  
  355.     (inst compute-code-from-lra code-tn code-tn lra-label temp)))
  356.   (undefined-value))
  357.  
  358.  
  359. ;;;; Unknown values receiving:
  360.  
  361. ;;; Receive-Unknown-Values  --  Internal
  362. ;;;
  363. ;;;    Emit code needed at the return point for an unknown-values call for an
  364. ;;; arbitrary number of values.
  365. ;;;
  366. ;;;    We do the single and non-single cases with no shared code: there doesn't
  367. ;;; seem to be any potential overlap, and receiving a single value is more
  368. ;;; important efficiency-wise.
  369. ;;;
  370. ;;;    When there is a single value, we just push it on the stack, returning
  371. ;;; the old SP and 1.
  372. ;;;
  373. ;;;    When there is a variable number of values, we move all of the argument
  374. ;;; registers onto the stack, and return Args and Nargs.
  375. ;;;
  376. ;;;    Args and Nargs are TNs wired to the named locations.  We must
  377. ;;; explicitly allocate these TNs, since their lifetimes overlap with the
  378. ;;; results Start and Count (also, it's nice to be able to target them).
  379. ;;;
  380. (defun receive-unknown-values (args nargs start count lra-label temp)
  381.   (declare (type tn args nargs start count temp))
  382.   (let ((variable-values (gen-label))
  383.     (done (gen-label)))
  384.     (inst b variable-values)
  385.     (inst nop)
  386.     
  387.     (inst compute-code-from-lra code-tn code-tn lra-label temp)
  388.     (inst add csp-tn 4)
  389.     (storew (first register-arg-tns) csp-tn -1)
  390.     (inst sub start csp-tn 4)
  391.     (inst li count (fixnum 1))
  392.     
  393.     (emit-label done)
  394.     
  395.     (assemble (*elsewhere*)
  396.       (trace-table-entry trace-table-function-prologue)
  397.       (emit-label variable-values)
  398.       (inst compute-code-from-lra code-tn code-tn lra-label temp)
  399.       (do ((arg register-arg-tns (rest arg))
  400.        (i 0 (1+ i)))
  401.       ((null arg))
  402.     (storew (first arg) args i))
  403.       (move start args)
  404.       (move count nargs)
  405.       (inst b done)
  406.       (inst nop)
  407.       (trace-table-entry trace-table-normal)))
  408.   (undefined-value))
  409.  
  410.  
  411. ;;; VOP that can be inherited by unknown values receivers.  The main thing this
  412. ;;; handles is allocation of the result temporaries.
  413. ;;;
  414. (define-vop (unknown-values-receiver)
  415.   (:results
  416.    (start :scs (any-reg))
  417.    (count :scs (any-reg)))
  418.   (:temporary (:sc descriptor-reg :offset ocfp-offset
  419.            :from :eval :to (:result 0))
  420.           values-start)
  421.   (:temporary (:sc any-reg :offset nargs-offset
  422.            :from :eval :to (:result 1))
  423.           nvals)
  424.   (:temporary (:scs (non-descriptor-reg)) temp))
  425.  
  426.  
  427.  
  428. ;;;; Local call with unknown values convention return:
  429.  
  430. ;;; Non-TR local call for a fixed number of values passed according to the
  431. ;;; unknown values convention.
  432. ;;;
  433. ;;; Args are the argument passing locations, which are specified only to
  434. ;;; terminate their lifetimes in the caller.
  435. ;;;
  436. ;;; Values are the return value locations (wired to the standard passing
  437. ;;; locations).
  438. ;;;
  439. ;;; Save is the save info, which we can ignore since saving has been done.
  440. ;;; Return-PC is the TN that the return PC should be passed in.
  441. ;;; Target is a continuation pointing to the start of the called function.
  442. ;;; Nvals is the number of values received.
  443. ;;;
  444. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  445. ;;; registers may be tied up by the more operand.  Instead, we use
  446. ;;; MAYBE-LOAD-STACK-TN.
  447. ;;;
  448. (define-vop (call-local)
  449.   (:args (fp)
  450.      (nfp)
  451.      (args :more t))
  452.   (:results (values :more t))
  453.   (:save-p t)
  454.   (:move-args :local-call)
  455.   (:info arg-locs callee target nvals)
  456.   (:vop-var vop)
  457.   (:temporary (:scs (descriptor-reg) :from (:eval 0)) move-temp)
  458.   (:temporary (:scs (non-descriptor-reg)) temp)
  459.   (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
  460.   (:temporary (:sc any-reg :offset ocfp-offset :from (:eval 0)) ocfp)
  461.   (:ignore arg-locs args ocfp)
  462.   (:generator 5
  463.     (trace-table-entry trace-table-call-site)
  464.     (let ((label (gen-label))
  465.       (cur-nfp (current-nfp-tn vop)))
  466.       (when cur-nfp
  467.     (store-stack-tn nfp-save cur-nfp))
  468.       (let ((callee-nfp (callee-nfp-tn callee)))
  469.     (when callee-nfp
  470.       (move callee-nfp nfp)))
  471.       (maybe-load-stack-tn cfp-tn fp)
  472.       (inst compute-lra-from-code
  473.         (callee-return-pc-tn callee) code-tn label temp)
  474.       (inst b target)
  475.       (inst nop)
  476.       (emit-return-pc label)
  477.       (note-this-location vop :unknown-return)
  478.       (default-unknown-values values nvals move-temp temp label)
  479.       (when cur-nfp
  480.     (load-stack-tn cur-nfp nfp-save)))
  481.     (trace-table-entry trace-table-normal)))
  482.  
  483.  
  484. ;;; Non-TR local call for a variable number of return values passed according
  485. ;;; to the unknown values convention.  The results are the start of the values
  486. ;;; glob and the number of values received.
  487. ;;;
  488. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  489. ;;; registers may be tied up by the more operand.  Instead, we use
  490. ;;; MAYBE-LOAD-STACK-TN.
  491. ;;;
  492. (define-vop (multiple-call-local unknown-values-receiver)
  493.   (:args (fp)
  494.      (nfp)
  495.      (args :more t))
  496.   (:save-p t)
  497.   (:move-args :local-call)
  498.   (:info save callee target)
  499.   (:ignore args save)
  500.   (:vop-var vop)
  501.   (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
  502.   (:generator 20
  503.     (trace-table-entry trace-table-call-site)
  504.     (let ((label (gen-label))
  505.       (cur-nfp (current-nfp-tn vop)))
  506.       (when cur-nfp
  507.     (store-stack-tn nfp-save cur-nfp))
  508.       (let ((callee-nfp (callee-nfp-tn callee)))
  509.     (when callee-nfp
  510.       (move callee-nfp nfp)))
  511.       (maybe-load-stack-tn cfp-tn fp)
  512.       (inst compute-lra-from-code
  513.         (callee-return-pc-tn callee) code-tn label temp)
  514.       (inst b target)
  515.       (inst nop)
  516.       (emit-return-pc label)
  517.       (note-this-location vop :unknown-return)
  518.       (receive-unknown-values values-start nvals start count label temp)
  519.       (when cur-nfp
  520.     (load-stack-tn cur-nfp nfp-save)))
  521.     (trace-table-entry trace-table-normal)))
  522.  
  523.  
  524. ;;;; Local call with known values return:
  525.  
  526. ;;; Non-TR local call with known return locations.  Known-value return works
  527. ;;; just like argument passing in local call.
  528. ;;;
  529. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  530. ;;; registers may be tied up by the more operand.  Instead, we use
  531. ;;; MAYBE-LOAD-STACK-TN.
  532. ;;;
  533. (define-vop (known-call-local)
  534.   (:args (fp)
  535.      (nfp)
  536.      (args :more t))
  537.   (:results (res :more t))
  538.   (:move-args :local-call)
  539.   (:save-p t)
  540.   (:info save callee target)
  541.   (:ignore args res save)
  542.   (:vop-var vop)
  543.   (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)
  544.   (:temporary (:scs (non-descriptor-reg)) temp)
  545.   (:generator 5
  546.     (trace-table-entry trace-table-call-site)
  547.     (let ((label (gen-label))
  548.       (cur-nfp (current-nfp-tn vop)))
  549.       (when cur-nfp
  550.     (store-stack-tn nfp-save cur-nfp))
  551.       (let ((callee-nfp (callee-nfp-tn callee)))
  552.     (when callee-nfp
  553.       (move callee-nfp nfp)))
  554.       (maybe-load-stack-tn cfp-tn fp)
  555.       (inst compute-lra-from-code
  556.         (callee-return-pc-tn callee) code-tn label temp)
  557.       (inst b target)
  558.       (inst nop)
  559.       (emit-return-pc label)
  560.       (note-this-location vop :known-return)
  561.       (when cur-nfp
  562.     (load-stack-tn cur-nfp nfp-save)))
  563.     (trace-table-entry trace-table-normal)))
  564.  
  565. ;;; Return from known values call.  We receive the return locations as
  566. ;;; arguments to terminate their lifetimes in the returning function.  We
  567. ;;; restore FP and CSP and jump to the Return-PC.
  568. ;;;
  569. ;;; Note: we can't use normal load-tn allocation for the fixed args, since all
  570. ;;; registers may be tied up by the more operand.  Instead, we use
  571. ;;; MAYBE-LOAD-STACK-TN.
  572. ;;;
  573. (define-vop (known-return)
  574.   (:args (old-fp :target old-fp-temp)
  575.      (return-pc :target return-pc-temp)
  576.      (vals :more t))
  577.   (:temporary (:sc any-reg :from (:argument 0)) old-fp-temp)
  578.   (:temporary (:sc descriptor-reg :from (:argument 1)) return-pc-temp)
  579.   (:move-args :known-return)
  580.   (:info val-locs)
  581.   (:ignore val-locs vals)
  582.   (:vop-var vop)
  583.   (:generator 6
  584.     (trace-table-entry trace-table-function-epilogue)
  585.     (maybe-load-stack-tn old-fp-temp old-fp)
  586.     (maybe-load-stack-tn return-pc-temp return-pc)
  587.     (move csp-tn cfp-tn)
  588.     (let ((cur-nfp (current-nfp-tn vop)))
  589.       (when cur-nfp
  590.     (inst add nsp-tn cur-nfp 
  591.           (- (bytes-needed-for-non-descriptor-stack-frame)
  592.          number-stack-displacement))))
  593.     (inst j return-pc-temp (- vm:word-bytes vm:other-pointer-type))
  594.     (move cfp-tn old-fp-temp)
  595.     (trace-table-entry trace-table-normal)))
  596.  
  597.  
  598. ;;;; Full call:
  599. ;;;
  600. ;;;    There is something of a cross-product effect with full calls.  Different
  601. ;;; versions are used depending on whether we know the number of arguments or
  602. ;;; the name of the called function, and whether we want fixed values, unknown
  603. ;;; values, or a tail call.
  604. ;;;
  605. ;;; In full call, the arguments are passed creating a partial frame on the
  606. ;;; stack top and storing stack arguments into that frame.  On entry to the
  607. ;;; callee, this partial frame is pointed to by FP.  If there are no stack
  608. ;;; arguments, we don't bother allocating a partial frame, and instead set FP
  609. ;;; to SP just before the call.
  610.  
  611. ;;; Define-Full-Call  --  Internal
  612. ;;;
  613. ;;;    This macro helps in the definition of full call VOPs by avoiding code
  614. ;;; replication in defining the cross-product VOPs.
  615. ;;;
  616. ;;; Name is the name of the VOP to define.
  617. ;;; 
  618. ;;; Named is true if the first argument is a symbol whose global function
  619. ;;; definition is to be called.
  620. ;;;
  621. ;;; Return is either :Fixed, :Unknown or :Tail:
  622. ;;; -- If :Fixed, then the call is for a fixed number of values, returned in
  623. ;;;    the standard passing locations (passed as result operands).
  624. ;;; -- If :Unknown, then the result values are pushed on the stack, and the
  625. ;;;    result values are specified by the Start and Count as in the
  626. ;;;    unknown-values continuation representation.
  627. ;;; -- If :Tail, then do a tail-recursive call.  No values are returned.
  628. ;;;    The Old-Fp and Return-PC are passed as the second and third arguments.
  629. ;;;
  630. ;;; In non-tail calls, the pointer to the stack arguments is passed as the last
  631. ;;; fixed argument.  If Variable is false, then the passing locations are
  632. ;;; passed as a more arg.  Variable is true if there are a variable number of
  633. ;;; arguments passed on the stack.  Variable cannot be specified with :Tail
  634. ;;; return.  TR variable argument call is implemented separately.
  635. ;;;
  636. ;;; In tail call with fixed arguments, the passing locations are passed as a
  637. ;;; more arg, but there is no new-FP, since the arguments have been set up in
  638. ;;; the current frame.
  639. ;;;
  640. (defmacro define-full-call (name named return variable)
  641.   (assert (not (and variable (eq return :tail))))
  642.   `(define-vop (,name
  643.         ,@(when (eq return :unknown)
  644.             '(unknown-values-receiver)))
  645.      (:args
  646.       ,@(unless (eq return :tail)
  647.       '((new-fp :scs (any-reg) :to :eval)))
  648.  
  649.       ,(if named
  650.        '(name :target name-pass)
  651.        '(arg-fun :target lexenv))
  652.       
  653.       ,@(when (eq return :tail)
  654.       '((old-fp :target old-fp-pass)
  655.         (return-pc :target return-pc-pass)))
  656.       
  657.       ,@(unless variable '((args :more t :scs (descriptor-reg)))))
  658.  
  659.      ,@(when (eq return :fixed)
  660.      '((:results (values :more t))))
  661.    
  662.      ,@(unless (eq return :tail)
  663.      `((:save-p t)
  664.        ,@(unless variable
  665.            '((:move-args :full-call)))))
  666.  
  667.      (:vop-var vop)
  668.      (:info ,@(unless (or variable (eq return :tail)) '(arg-locs))
  669.         ,@(unless variable '(nargs))
  670.         ,@(when (eq return :fixed) '(nvals)))
  671.  
  672.      (:ignore
  673.       ,@(unless (or variable (eq return :tail)) '(arg-locs))
  674.       ,@(unless variable '(args)))
  675.  
  676.      (:temporary (:sc descriptor-reg
  677.           :offset ocfp-offset
  678.           :from (:argument 1)
  679.           ,@(unless (eq return :fixed)
  680.               '(:to :eval)))
  681.          old-fp-pass)
  682.  
  683.      (:temporary (:sc descriptor-reg
  684.           :offset lra-offset
  685.           :from (:argument ,(if (eq return :tail) 2 1))
  686.           :to :eval)
  687.          return-pc-pass)
  688.  
  689.      ,(if named
  690.       `(:temporary (:sc descriptor-reg :offset cname-offset
  691.                 :from (:argument ,(if (eq return :tail) 0 1))
  692.                 :to :eval)
  693.                name-pass)
  694.       `(:temporary (:sc descriptor-reg :offset lexenv-offset
  695.                 :from (:argument ,(if (eq return :tail) 0 1))
  696.                 :to :eval)
  697.                lexenv))
  698.  
  699.      (:temporary (:scs (descriptor-reg) :from (:argument 0) :to :eval)
  700.          function)
  701.      (:temporary (:sc any-reg :offset nargs-offset :to :eval)
  702.          nargs-pass)
  703.  
  704.      ,@(when variable
  705.      (mapcar #'(lambda (name offset)
  706.              `(:temporary (:sc descriptor-reg
  707.                    :offset ,offset
  708.                    :to :eval)
  709.              ,name))
  710.          register-arg-names register-arg-offsets))
  711.      ,@(when (eq return :fixed)
  712.      '((:temporary (:scs (descriptor-reg) :from :eval) move-temp)))
  713.  
  714.      ,@(unless (eq return :tail)
  715.      '((:temporary (:scs (non-descriptor-reg)) temp)
  716.        (:temporary (:sc control-stack :offset nfp-save-offset) nfp-save)))
  717.  
  718.      (:generator ,(+ (if named 5 0)
  719.              (if variable 19 1)
  720.              (if (eq return :tail) 0 10)
  721.              15
  722.              (if (eq return :unknown) 25 0))
  723.        (trace-table-entry trace-table-call-site)
  724.        (let* ((cur-nfp (current-nfp-tn vop))
  725.           ,@(unless (eq return :tail)
  726.           '((lra-label (gen-label))))
  727.           (filler
  728.            (remove nil
  729.                (list :load-nargs
  730.                  ,@(if (eq return :tail)
  731.                    '((unless (location= old-fp old-fp-pass)
  732.                        :load-old-fp)
  733.                      (unless (location= return-pc
  734.                             return-pc-pass)
  735.                        :load-return-pc)
  736.                      (when cur-nfp
  737.                        :frob-nfp))
  738.                    '(:comp-lra
  739.                      (when cur-nfp
  740.                        :frob-nfp)
  741.                      :save-fp
  742.                      :load-fp))))))
  743.      (flet ((do-next-filler ()
  744.           (let* ((next (pop filler))
  745.              (what (if (consp next) (car next) next)))
  746.             (ecase what
  747.               (:load-nargs
  748.                ,@(if variable
  749.                  `((inst sub nargs-pass csp-tn new-fp)
  750.                    ,@(let ((index -1))
  751.                    (mapcar #'(lambda (name)
  752.                            `(loadw ,name new-fp
  753.                                ,(incf index)))
  754.                        register-arg-names)))
  755.                  '((inst li nargs-pass (fixnum nargs)))))
  756.               ,@(if (eq return :tail)
  757.                 '((:load-old-fp
  758.                    (sc-case old-fp
  759.                  (any-reg
  760.                   (inst move old-fp-pass old-fp))
  761.                  (control-stack
  762.                   (loadw old-fp-pass cfp-tn
  763.                      (tn-offset old-fp)))))
  764.                   (:load-return-pc
  765.                    (sc-case return-pc
  766.                  (descriptor-reg
  767.                   (inst move return-pc-pass return-pc))
  768.                  (control-stack
  769.                   (loadw return-pc-pass cfp-tn
  770.                      (tn-offset return-pc)))))
  771.                   (:frob-nfp
  772.                    (inst add nsp-tn cur-nfp
  773.                      (- (bytes-needed-for-non-descriptor-stack-frame)
  774.                     number-stack-displacement))))
  775.                 `((:comp-lra
  776.                    (inst compute-lra-from-code
  777.                      return-pc-pass code-tn lra-label temp))
  778.                   (:frob-nfp
  779.                    (store-stack-tn nfp-save cur-nfp))
  780.                   (:save-fp
  781.                    (inst move old-fp-pass cfp-tn))
  782.                   (:load-fp
  783.                    ,(if variable
  784.                     '(move cfp-tn new-fp)
  785.                     '(if (> nargs register-arg-count)
  786.                      (move cfp-tn new-fp)
  787.                      (move cfp-tn csp-tn))))))
  788.               ((nil))))))
  789.  
  790.        ,@(if named
  791.          `((sc-case name
  792.              (descriptor-reg (move name-pass name))
  793.              (control-stack
  794.               (loadw name-pass cfp-tn (tn-offset name))
  795.               (do-next-filler))
  796.              (immediate
  797.               (load-symbol name-pass (tn-value name)))
  798.              (constant
  799.               (loadw name-pass code-tn (tn-offset name)
  800.                  vm:other-pointer-type)
  801.               (do-next-filler)))
  802.            (loadw function name-pass vm:symbol-raw-function-addr-slot
  803.               vm:other-pointer-type)
  804.            (do-next-filler))
  805.          `((sc-case arg-fun
  806.              (descriptor-reg (move lexenv arg-fun))
  807.              (control-stack
  808.               (loadw lexenv cfp-tn (tn-offset arg-fun))
  809.               (do-next-filler))
  810.              (constant
  811.               (loadw lexenv code-tn (tn-offset arg-fun)
  812.                  vm:other-pointer-type)
  813.               (do-next-filler)))
  814.            (loadw function lexenv vm:closure-function-slot
  815.               vm:function-pointer-type)
  816.            (do-next-filler)))
  817.        (loop
  818.          (if filler
  819.          (do-next-filler)
  820.          (return)))
  821.        
  822.        (inst j function
  823.          (- (ash vm:function-header-code-offset vm:word-shift)
  824.             vm:function-pointer-type))
  825.        (inst move code-tn function))
  826.  
  827.      ,@(ecase return
  828.          (:fixed
  829.           '((emit-return-pc lra-label)
  830.         (note-this-location vop :unknown-return)
  831.         (default-unknown-values values nvals move-temp temp lra-label)
  832.         (when cur-nfp
  833.           (load-stack-tn cur-nfp nfp-save))))
  834.          (:unknown
  835.           '((emit-return-pc lra-label)
  836.         (note-this-location vop :unknown-return)
  837.         (receive-unknown-values values-start nvals start count
  838.                     lra-label temp)
  839.         (when cur-nfp
  840.           (load-stack-tn cur-nfp nfp-save))))
  841.          (:tail)))
  842.        (trace-table-entry trace-table-normal))))
  843.  
  844.  
  845. (define-full-call call nil :fixed nil)
  846. (define-full-call call-named t :fixed nil)
  847. (define-full-call multiple-call nil :unknown nil)
  848. (define-full-call multiple-call-named t :unknown nil)
  849. (define-full-call tail-call nil :tail nil)
  850. (define-full-call tail-call-named t :tail nil)
  851.  
  852. (define-full-call call-variable nil :fixed t)
  853. (define-full-call multiple-call-variable nil :unknown t)
  854.  
  855.  
  856. ;;; Defined separately, since needs special code that BLT's the arguments
  857. ;;; down.
  858. ;;;
  859. (define-vop (tail-call-variable)
  860.   (:args
  861.    (args-arg :scs (any-reg) :target args)
  862.    (function-arg :scs (descriptor-reg) :target lexenv)
  863.    (old-fp-arg :scs (any-reg) :target old-fp)
  864.    (lra-arg :scs (descriptor-reg) :target lra))
  865.  
  866.   (:temporary (:sc any-reg :offset nl0-offset :from (:argument 0)) args)
  867.   (:temporary (:sc any-reg :offset lexenv-offset :from (:argument 1)) lexenv)
  868.   (:temporary (:sc any-reg :offset ocfp-offset :from (:argument 2)) old-fp)
  869.   (:temporary (:sc any-reg :offset lra-offset :from (:argument 3)) lra)
  870.  
  871.   (:temporary (:scs (any-reg) :from :eval) temp)
  872.  
  873.   (:vop-var vop)
  874.  
  875.   (:generator 75
  876.  
  877.     ;; Move these into the passing locations if they are not already there.
  878.     (move args args-arg)
  879.     (move lexenv function-arg)
  880.     (move old-fp old-fp-arg)
  881.     (move lra lra-arg)
  882.  
  883.     ;; Clear the number stack if anything is there.
  884.     (let ((cur-nfp (current-nfp-tn vop)))
  885.       (when cur-nfp
  886.     (inst add nsp-tn cur-nfp
  887.           (- (bytes-needed-for-non-descriptor-stack-frame)
  888.          number-stack-displacement))))
  889.  
  890.     ;; And jump to the assembly-routine that does the bliting.
  891.     (inst ji temp (make-fixup 'tail-call-variable :assembly-routine))
  892.     (inst nop)))
  893.  
  894.  
  895. ;;;; Unknown values return:
  896.  
  897.  
  898. ;;; Do unknown-values return of a fixed number of values.  The Values are
  899. ;;; required to be set up in the standard passing locations.  Nvals is the
  900. ;;; number of values returned.
  901. ;;;
  902. ;;; If returning a single value, then deallocate the current frame, restore
  903. ;;; FP and jump to the single-value entry at Return-PC + 8.
  904. ;;;
  905. ;;; If returning other than one value, then load the number of values returned,
  906. ;;; NIL out unsupplied values registers, restore FP and return at Return-PC.
  907. ;;; When there are stack values, we must initialize the argument pointer to
  908. ;;; point to the beginning of the values block (which is the beginning of the
  909. ;;; current frame.)
  910. ;;;
  911. (define-vop (return)
  912.   (:args
  913.    (old-fp :scs (any-reg))
  914.    (return-pc :scs (descriptor-reg) :to (:eval 1))
  915.    (values :more t))
  916.   (:ignore values)
  917.   (:info nvals)
  918.   (:temporary (:sc descriptor-reg :offset a0-offset :from (:eval 0)) a0)
  919.   (:temporary (:sc descriptor-reg :offset a1-offset :from (:eval 0)) a1)
  920.   (:temporary (:sc descriptor-reg :offset a2-offset :from (:eval 0)) a2)
  921.   (:temporary (:sc descriptor-reg :offset a3-offset :from (:eval 0)) a3)
  922.   (:temporary (:sc descriptor-reg :offset a4-offset :from (:eval 0)) a4)
  923.   (:temporary (:sc descriptor-reg :offset a5-offset :from (:eval 0)) a5)
  924.   (:temporary (:sc any-reg :offset nargs-offset) nargs)
  925.   (:temporary (:sc any-reg :offset ocfp-offset) val-ptr)
  926.   (:vop-var vop)
  927.   (:generator 6
  928.     (trace-table-entry trace-table-function-epilogue)
  929.     ;; Clear the number stack.
  930.     (let ((cur-nfp (current-nfp-tn vop)))
  931.       (when cur-nfp
  932.     (inst add nsp-tn cur-nfp
  933.           (- (bytes-needed-for-non-descriptor-stack-frame)
  934.          number-stack-displacement))))
  935.     (cond ((= nvals 1)
  936.        ;; Clear the control stack, and restore the frame pointer.
  937.        (move csp-tn cfp-tn)
  938.        (move cfp-tn old-fp)
  939.        ;; Out of here.
  940.        (lisp-return return-pc :offset 2))
  941.       (t
  942.        ;; Establish the values pointer and values count.
  943.        (move val-ptr cfp-tn)
  944.        (inst li nargs (fixnum nvals))
  945.        ;; restore the frame pointer and clear as much of the control
  946.        ;; stack as possible.
  947.        (move cfp-tn old-fp)
  948.        (inst add csp-tn val-ptr (* nvals word-bytes))
  949.        ;; pre-default any argument register that need it.
  950.        (when (< nvals register-arg-count)
  951.          (dolist (reg (subseq (list a0 a1 a2 a3 a4 a5) nvals))
  952.            (move reg null-tn)))
  953.        ;; And away we go.
  954.        (lisp-return return-pc)))
  955.     (trace-table-entry trace-table-normal)))
  956.  
  957. ;;; Do unknown-values return of an arbitrary number of values (passed on the
  958. ;;; stack.)  We check for the common case of a single return value, and do that
  959. ;;; inline using the normal single value return convention.  Otherwise, we
  960. ;;; branch off to code that calls an assembly-routine.
  961. ;;;
  962. (define-vop (return-multiple)
  963.   (:args
  964.    (old-fp-arg :scs (any-reg) :to (:eval 1))
  965.    (lra-arg :scs (descriptor-reg) :to (:eval 1))
  966.    (vals-arg :scs (any-reg) :target vals)
  967.    (nvals-arg :scs (any-reg) :target nvals))
  968.  
  969.   (:temporary (:sc any-reg :offset nl1-offset :from (:argument 0)) old-fp)
  970.   (:temporary (:sc descriptor-reg :offset lra-offset :from (:argument 1)) lra)
  971.   (:temporary (:sc any-reg :offset nl0-offset :from (:argument 2)) vals)
  972.   (:temporary (:sc any-reg :offset nargs-offset :from (:argument 3)) nvals)
  973.   (:temporary (:sc descriptor-reg :offset a0-offset) a0)
  974.  
  975.   (:temporary (:scs (any-reg) :from (:eval 1)) temp)
  976.  
  977.   (:vop-var vop)
  978.  
  979.   (:generator 13
  980.     (trace-table-entry trace-table-function-epilogue)
  981.     (let ((not-single (gen-label)))
  982.       ;; Clear the number stack.
  983.       (let ((cur-nfp (current-nfp-tn vop)))
  984.     (when cur-nfp
  985.       (inst add nsp-tn cur-nfp
  986.         (- (bytes-needed-for-non-descriptor-stack-frame)
  987.            number-stack-displacement))))
  988.  
  989.       ;; Check for the single case.
  990.       (inst cmp nvals-arg (fixnum 1))
  991.       (inst b :ne not-single)
  992.       (inst ld a0 vals-arg)
  993.  
  994.       ;; Return with one value.
  995.       (move csp-tn cfp-tn)
  996.       (move cfp-tn old-fp-arg)
  997.       (lisp-return lra-arg :offset 2)
  998.         
  999.       ;; Nope, not the single case.
  1000.       (emit-label not-single)
  1001.       (move old-fp old-fp-arg)
  1002.       (move lra lra-arg)
  1003.       (move vals vals-arg)
  1004.       (move nvals nvals-arg)
  1005.       (inst ji temp (make-fixup 'return-multiple :assembly-routine))
  1006.       (inst nop))
  1007.     (trace-table-entry trace-table-normal)))
  1008.  
  1009.  
  1010.  
  1011. ;;;; XEP hackery:
  1012.  
  1013.  
  1014. ;;; We don't need to do anything special for regular functions.
  1015. ;;;
  1016. (define-vop (setup-environment)
  1017.   (:info label)
  1018.   (:ignore label)
  1019.   (:generator 0
  1020.     ;; Don't bother doing anything.
  1021.     ))
  1022.  
  1023. ;;; Get the lexical environment from it's passing location.
  1024. ;;;
  1025. (define-vop (setup-closure-environment)
  1026.   (:temporary (:sc descriptor-reg :offset lexenv-offset :target closure
  1027.            :to (:result 0))
  1028.           lexenv)
  1029.   (:results (closure :scs (descriptor-reg)))
  1030.   (:info label)
  1031.   (:ignore label)
  1032.   (:generator 6
  1033.     ;; Get result.
  1034.     (move closure lexenv)))
  1035.  
  1036. ;;; Copy a more arg from the argument area to the end of the current frame.
  1037. ;;; Fixed is the number of non-more arguments. 
  1038. ;;;
  1039. (define-vop (copy-more-arg)
  1040.   (:temporary (:sc any-reg :offset nl0-offset) result)
  1041.   (:temporary (:sc any-reg :offset nl1-offset) count)
  1042.   (:temporary (:sc any-reg :offset nl2-offset) src)
  1043.   (:temporary (:sc any-reg :offset nl3-offset) dst)
  1044.   (:temporary (:sc descriptor-reg :offset l0-offset) temp)
  1045.   (:info fixed)
  1046.   (:generator 20
  1047.     (let ((loop (gen-label))
  1048.       (do-regs (gen-label))
  1049.       (done (gen-label)))
  1050.       (when (< fixed register-arg-count)
  1051.     ;; Save a pointer to the results so we can fill in register args.
  1052.     ;; We don't need this if there are more fixed args than reg args.
  1053.     (move result csp-tn))
  1054.       ;; Allocate the space on the stack.
  1055.       (cond ((zerop fixed)
  1056.          (inst cmp nargs-tn)
  1057.          (inst b :eq done)
  1058.          (inst add csp-tn csp-tn nargs-tn))
  1059.         (t
  1060.          (inst subcc count nargs-tn (fixnum fixed))
  1061.          (inst b :le done)
  1062.          (inst nop)
  1063.          (inst add csp-tn csp-tn count)))
  1064.       (when (< fixed register-arg-count)
  1065.     ;; We must stop when we run out of stack args, not when we run out of
  1066.     ;; more args.
  1067.     (inst subcc count nargs-tn (fixnum register-arg-count))
  1068.     ;; Everything of interest in registers.
  1069.     (inst b :le do-regs))
  1070.       ;; Initialize dst to be end of stack.
  1071.       (move dst csp-tn)
  1072.       ;; Initialize src to be end of args.
  1073.       (inst add src cfp-tn nargs-tn)
  1074.  
  1075.       (emit-label loop)
  1076.       ;; *--dst = *--src, --count
  1077.       (inst add src src (- vm:word-bytes))
  1078.       (inst subcc count count (fixnum 1))
  1079.       (loadw temp src)
  1080.       (inst add dst dst (- vm:word-bytes))
  1081.       (inst b :gt loop)
  1082.       (storew temp dst)
  1083.  
  1084.       (emit-label do-regs)
  1085.       (when (< fixed register-arg-count)
  1086.     ;; Now we have to deposit any more args that showed up in registers.
  1087.     (inst subcc count nargs-tn (fixnum fixed))
  1088.     (do ((i fixed (1+ i)))
  1089.         ((>= i register-arg-count))
  1090.       ;; Don't deposit any more than there are.
  1091.       (inst b :eq done)
  1092.       (inst subcc count (fixnum 1))
  1093.       ;; Store it relative to the pointer saved at the start.
  1094.       (storew (nth i register-arg-tns) result (- i fixed))))
  1095.       (emit-label done))))
  1096.  
  1097.  
  1098. ;;; More args are stored consequtively on the stack, starting immediately at
  1099. ;;; the context pointer.  The context pointer is not typed, so the lowtag is 0.
  1100. ;;;
  1101. (define-vop (more-arg word-index-ref)
  1102.   (:variant 0 0)
  1103.   (:translate %more-arg))
  1104.  
  1105.  
  1106. ;;; Turn more arg (context, count) into a list.
  1107. ;;;
  1108. (define-vop (listify-rest-args)
  1109.   (:args (context-arg :target context :scs (descriptor-reg))
  1110.      (count-arg :target count :scs (any-reg)))
  1111.   (:arg-types * tagged-num)
  1112.   (:temporary (:scs (any-reg) :from (:argument 0)) context)
  1113.   (:temporary (:scs (any-reg) :from (:argument 1)) count)
  1114.   (:temporary (:scs (descriptor-reg) :from :eval) temp)
  1115.   (:temporary (:scs (non-descriptor-reg) :from :eval) ndescr dst)
  1116.   (:results (result :scs (descriptor-reg)))
  1117.   (:translate %listify-rest-args)
  1118.   (:policy :safe)
  1119.   (:generator 20
  1120.     (let ((enter (gen-label))
  1121.       (loop (gen-label))
  1122.       (done (gen-label)))
  1123.       (move context context-arg)
  1124.       (move count count-arg)
  1125.       ;; Check to see if there are any arguments.
  1126.       (inst cmp count)
  1127.       (inst b :eq done)
  1128.       (move result null-tn)
  1129.  
  1130.       ;; We need to do this atomically.
  1131.       (pseudo-atomic (ndescr)
  1132.     ;; Allocate a cons (2 words) for each item.
  1133.     (inst add result alloc-tn vm:list-pointer-type)
  1134.     (move dst result)
  1135.     (inst add alloc-tn alloc-tn count)
  1136.     (inst b enter)
  1137.     (inst add alloc-tn alloc-tn count)
  1138.  
  1139.     ;; Store the current cons in the cdr of the previous cons.
  1140.     (emit-label loop)
  1141.     (storew dst dst -1 vm:list-pointer-type)
  1142.  
  1143.     ;; Grab one value and stash it in the car of this cons.
  1144.     (emit-label enter)
  1145.     (loadw temp context)
  1146.     (inst add context context vm:word-bytes)
  1147.     (storew temp dst 0 vm:list-pointer-type)
  1148.  
  1149.     ;; Dec count, and if != zero, go back for more.
  1150.     (inst subcc count (fixnum 1))
  1151.     (inst b :gt loop)
  1152.     (inst add dst dst (* 2 vm:word-bytes))
  1153.  
  1154.     ;; NIL out the last cons.
  1155.     (storew null-tn dst -1 vm:list-pointer-type))
  1156.       (emit-label done))))
  1157.  
  1158.  
  1159. ;;; Return the location and size of the more arg glob created by Copy-More-Arg.
  1160. ;;; Supplied is the total number of arguments supplied (originally passed in
  1161. ;;; NARGS.)  Fixed is the number of non-rest arguments.
  1162. ;;;
  1163. ;;; We must duplicate some of the work done by Copy-More-Arg, since at that
  1164. ;;; time the environment is in a pretty brain-damaged state, preventing this
  1165. ;;; info from being returned as values.  What we do is compute
  1166. ;;; supplied - fixed, and return a pointer that many words below the current
  1167. ;;; stack top.
  1168. ;;;
  1169. (define-vop (more-arg-context)
  1170.   (:args (supplied :scs (any-reg)))
  1171.   (:arg-types positive-fixnum)
  1172.   (:info fixed)
  1173.   (:results
  1174.    (context :scs (descriptor-reg))
  1175.    (count :scs (any-reg)))
  1176.   (:generator 5
  1177.     (inst sub count supplied (fixnum fixed))
  1178.     (inst sub context csp-tn count)))
  1179.  
  1180.  
  1181. ;;; Signal wrong argument count error if Nargs isn't = to Count.
  1182. ;;;
  1183. (define-vop (verify-argument-count)
  1184.   (:args (nargs :scs (any-reg)))
  1185.   (:arg-types positive-fixnum)
  1186.   (:info count)
  1187.   (:vop-var vop)
  1188.   (:save-p :compute-only)
  1189.   (:generator 3
  1190.     (let ((err-lab
  1191.        (generate-error-code vop invalid-argument-count-error nargs)))
  1192.       (inst cmp nargs (fixnum count))
  1193.       (inst b :ne err-lab)
  1194.       (inst nop))))
  1195.  
  1196. ;;; Signal various errors.
  1197. ;;;
  1198. (macrolet ((frob (name error &rest args)
  1199.          `(define-vop (,name)
  1200.         (:args ,@(mapcar #'(lambda (arg)
  1201.                      `(,arg :scs (any-reg descriptor-reg)))
  1202.                  args))
  1203.         (:vop-var vop)
  1204.         (:save-p :compute-only)
  1205.         (:generator 1000
  1206.           (error-call vop ,error ,@args)))))
  1207.   (frob argument-count-error invalid-argument-count-error nargs)
  1208.   (frob type-check-error object-not-type-error object type)
  1209.   (frob odd-keyword-arguments-error odd-keyword-arguments-error)
  1210.   (frob unknown-keyword-argument-error unknown-keyword-argument-error key)
  1211.   (frob nil-function-returned-error nil-function-returned-error fun))
  1212.