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

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