Micro-optimize keyword argument parsing on x86 and x86-64.
* Change %MORE-ARG to take a negative offset, so we can perform
the negation once outside the parsing loop instead of twice
each time through the loop;
* Combine the retrieval of the keyword and its associated value
into a single VOP, so we can take advantage of base+index+disp
addressing.
(defknown %special-unbind (t) t)
(defknown %listify-rest-args (t index) list (flushable))
(defknown %more-arg-context (t t) (values t index) (flushable))
+#!-stack-grows-downward-not-upward
(defknown %more-arg (t index) t)
+#!+stack-grows-downward-not-upward
+(defknown %more-kw-arg (t index) (values t t))
(defknown %more-arg-values (t index index) * (flushable))
(defknown %verify-arg-count (index index) (values))
(defknown %arg-count-error (t) nil)
(arg-vals n-context)
(arg-vals n-count))
+ ;; The reason for all the noise with
+ ;; STACK-GROWS-DOWNWARD-NOT-UPWARD is to enable generation of
+ ;; slightly more efficient code on x86oid processors. (We can
+ ;; hoist the negation of the index outside the main parsing loop
+ ;; and take advantage of the base+index+displacement addressing
+ ;; mode on x86oids.)
(when (optional-dispatch-keyp res)
(let ((n-index (gensym "N-INDEX-"))
(n-key (gensym "N-KEY-"))
(policy *lexenv* (zerop safety))))
(found-allow-p nil))
- (temps `(,n-index (1- ,n-count)) n-key n-value-temp)
- (body `(declare (fixnum ,n-index) (ignorable ,n-key ,n-value-temp)))
+ (temps #!-stack-grows-downward-not-upward
+ `(,n-index (1- ,n-count))
+ #!+stack-grows-downward-not-upward
+ `(,n-index (- (1- ,n-count)))
+ #!-stack-grows-downward-not-upward n-value-temp
+ #!-stack-grows-downward-not-upward n-key)
+ (body `(declare (fixnum ,n-index)
+ #!-stack-grows-downward-not-upward
+ (ignorable ,n-value-temp ,n-key)))
(collect ((tests))
(dolist (key keys)
(%odd-key-args-error)))
(body
+ #!-stack-grows-downward-not-upward
`(locally
(declare (optimize (safety 0)))
(loop
(decf ,n-index)
(setq ,n-key (%more-arg ,n-context ,n-index))
(decf ,n-index)
- (cond ,@(tests)))))
+ (cond ,@(tests))))
+ #!+stack-grows-downward-not-upward
+ `(locally (declare (optimize (safety 0)))
+ (loop
+ (when (plusp ,n-index) (return))
+ (multiple-value-bind (,n-value-temp ,n-key)
+ (%more-kw-arg ,n-context ,n-index)
+ (declare (ignorable ,n-value-temp ,n-key))
+ (incf ,n-index 2)
+ (cond ,@(tests))))))
(unless allowp
(body `(when (and ,n-losep (not ,n-allowp))
DONE))
-;;; &MORE args are stored contiguously on the stack, starting
-;;; immediately at the context pointer. The context pointer is not
-;;; typed, so the lowtag is 0.
-(define-vop (more-arg)
- (:translate %more-arg)
+(define-vop (more-kw-arg)
+ (:translate sb!c::%more-kw-arg)
(:policy :fast-safe)
- (:args (object :scs (descriptor-reg) :to :result)
- (index :scs (any-reg) :target temp))
+ (:args (object :scs (descriptor-reg) :to (:result 1))
+ (index :scs (any-reg) :to (:result 1) :target keyword))
(:arg-types * tagged-num)
- (:temporary (:sc unsigned-reg :from (:argument 1) :to :result) temp)
- (:results (value :scs (any-reg descriptor-reg)))
- (:result-types *)
- (:generator 5
- (move temp index)
- (inst neg temp)
- (inst mov value (make-ea :qword :base object :index temp))))
-
-(define-vop (more-arg-c)
- (:translate %more-arg)
- (:policy :fast-safe)
- (:args (object :scs (descriptor-reg)))
- (:info index)
- (:arg-types * (:constant (signed-byte 30)))
- (:results (value :scs (any-reg descriptor-reg)))
- (:result-types *)
+ (:results (value :scs (descriptor-reg any-reg))
+ (keyword :scs (descriptor-reg any-reg)))
+ (:result-types * *)
(:generator 4
- (inst mov value
- (make-ea :qword :base object :disp (- (* index n-word-bytes))))))
+ (inst mov value (make-ea :qword :base object :index index))
+ (inst mov keyword (make-ea :qword :base object :index index
+ :disp n-word-bytes))))))
;;; Turn more arg (context, count) into a list.
(defoptimizer (%listify-rest-args stack-allocate-result) ((&rest args))
DONE))
-;;; &MORE args are stored contiguously on the stack, starting
-;;; immediately at the context pointer. The context pointer is not
-;;; typed, so the lowtag is 0.
-(define-vop (more-arg)
- (:translate %more-arg)
+(define-vop (more-kw-arg)
+ (:translate sb!c::%more-kw-arg)
(:policy :fast-safe)
- (:args (object :scs (descriptor-reg) :to :result)
- (index :scs (any-reg) :target temp))
+ (:args (object :scs (descriptor-reg) :to (:result 1))
+ (index :scs (any-reg immediate) :to (:result 1) :target keyword))
(:arg-types * tagged-num)
- (:temporary (:sc unsigned-reg :from (:argument 1) :to :result) temp)
- (:results (value :scs (any-reg descriptor-reg)))
- (:result-types *)
- (:generator 5
- (move temp index)
- (inst neg temp)
- (inst mov value (make-ea :dword :base object :index temp))))
-
-(define-vop (more-arg-c)
- (:translate %more-arg)
- (:policy :fast-safe)
- (:args (object :scs (descriptor-reg)))
- (:info index)
- (:arg-types * (:constant (signed-byte 30)))
- (:results (value :scs (any-reg descriptor-reg)))
- (:result-types *)
+ (:results (value :scs (descriptor-reg any-reg))
+ (keyword :scs (descriptor-reg any-reg)))
+ (:result-types * *)
(:generator 4
- (inst mov value
- (make-ea :dword :base object :disp (- (* index n-word-bytes))))))
-
+ (sc-case index
+ (immediate
+ (inst mov value (make-ea :dword :base object :disp (tn-value index)))
+ (inst mov keyword (make-ea :dword :base object
+ :disp (+ (tn-value index) n-word-bytes))))
+ (t
+ (inst mov value (make-ea :dword :base object :index index))
+ (inst mov keyword (make-ea :dword :base object :index index
+ :disp n-word-bytes))))))
;;; Turn more arg (context, count) into a list.
(defoptimizer (%listify-rest-args stack-allocate-result) ((&rest args))
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"0.9.16.32"
+"0.9.16.33"