UPGRADED-ARRAY-ELEMENT-TYPE: more thoroughly signal errors on unknown types.
[sbcl.git] / src / compiler / mips / macros.lisp
index 4a0efed..da719e2 100644 (file)
 (defmacro expand (expr)
   (let ((gensym (gensym)))
     `(macrolet
-        ((,gensym ()
-           ,expr))
+         ((,gensym ()
+            ,expr))
        (,gensym))))
 
 \f
 ;;; Instruction-like macros.
 
 (defmacro move (dst src &optional (always-emit-code-p nil))
+  #!+sb-doc
   "Move SRC into DST (unless they are location= and ALWAYS-EMIT-CODE-P
-  is nil)."
+is nil)."
   (once-only ((n-dst dst)
-             (n-src src))
-    (if always-emit-code-p
-       `(inst move ,n-dst ,n-src)
-       `(unless (location= ,n-dst ,n-src)
-          (inst move ,n-dst ,n-src)))))
+              (n-src src))
+    `(if (location= ,n-dst ,n-src)
+         (when ,always-emit-code-p
+           (inst nop))
+         (inst move ,n-dst ,n-src))))
 
 (defmacro def-mem-op (op inst shift load)
   `(defmacro ,op (object base &optional (offset 0) (lowtag 0))
      `(progn
-       (inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag))
-       ,,@(when load '('(inst nop))))))
-;;; 
+        (inst ,',inst ,object ,base (- (ash ,offset ,,shift) ,lowtag))
+        ,,@(when load '('(inst nop))))))
+;;;
 (def-mem-op loadw lw word-shift t)
 (def-mem-op storew sw word-shift nil)
 
 (defmacro load-symbol (reg symbol)
-  `(inst addu ,reg null-tn (static-symbol-offset ,symbol)))
+  (once-only ((reg reg) (symbol symbol))
+    `(inst addu ,reg null-tn (static-symbol-offset ,symbol))))
 
 (defmacro load-symbol-value (reg symbol)
   `(progn
      (inst lw ,reg null-tn
-          (+ (static-symbol-offset ',symbol)
-             (ash symbol-value-slot word-shift)
-             (- other-pointer-lowtag)))
+           (+ (static-symbol-offset ',symbol)
+              (ash symbol-value-slot word-shift)
+              (- other-pointer-lowtag)))
      (inst nop)))
 
 (defmacro store-symbol-value (reg symbol)
   `(inst sw ,reg null-tn
-        (+ (static-symbol-offset ',symbol)
-           (ash symbol-value-slot word-shift)
-           (- other-pointer-lowtag))))
+         (+ (static-symbol-offset ',symbol)
+            (ash symbol-value-slot word-shift)
+            (- other-pointer-lowtag))))
 
 (defmacro load-type (target source &optional (offset 0))
+  #!+sb-doc
   "Loads the type bits of a pointer into target independent of
-  byte-ordering issues."
+byte-ordering issues."
   (once-only ((n-target target)
-             (n-source source)
-             (n-offset offset))
+              (n-source source)
+              (n-offset offset))
     (ecase *backend-byte-order*
       (:little-endian
-       `(inst lbu ,n-target ,n-source ,n-offset ))
+       `(inst lbu ,n-target ,n-source ,n-offset))
       (:big-endian
-       `(inst lbu ,n-target ,n-source (+ ,n-offset 3))))))
+       `(inst lbu ,n-target ,n-source (+ ,n-offset (1- n-word-bytes)))))))
 
 
 ;;; Macros to handle the fact that we cannot use the machine native call and
-;;; return instructions. 
+;;; return instructions.
 
 (defmacro lisp-jump (function lip)
+  #!+sb-doc
   "Jump to the lisp function FUNCTION.  LIP is an interior-reg temporary."
   `(progn
      (inst addu ,lip ,function (- (ash simple-fun-code-offset word-shift)
-                                  fun-pointer-lowtag))
+                                   fun-pointer-lowtag))
      (inst j ,lip)
-     (move code-tn ,function)))
+     (move code-tn ,function t)))
 
 (defmacro lisp-return (return-pc lip &key (offset 0) (frob-code t))
+  #!+sb-doc
   "Return to RETURN-PC.  LIP is an interior-reg temporary."
   `(progn
      (inst addu ,lip ,return-pc
-          (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag))
+           (- (* (1+ ,offset) n-word-bytes) other-pointer-lowtag))
      (inst j ,lip)
      ,(if frob-code
-         `(move code-tn ,return-pc)
-         '(inst nop))))
+          `(move code-tn ,return-pc t)
+          '(inst nop))))
 
 
 (defmacro emit-return-pc (label)
+  #!+sb-doc
   "Emit a return-pc header word.  LABEL is the label to use for this return-pc."
   `(progn
-     (align n-lowtag-bits)
+     (emit-alignment n-lowtag-bits)
      (emit-label ,label)
      (inst lra-header-word)))
 
 ;;; Move a stack TN to a register and vice-versa.
 (defmacro load-stack-tn (reg stack)
   `(let ((reg ,reg)
-        (stack ,stack))
+         (stack ,stack))
      (let ((offset (tn-offset stack)))
        (sc-case stack
-        ((control-stack)
-         (loadw reg cfp-tn offset))))))
+         ((control-stack)
+          (loadw reg cfp-tn offset))))))
+
 (defmacro store-stack-tn (stack reg)
   `(let ((stack ,stack)
-        (reg ,reg))
+         (reg ,reg))
      (let ((offset (tn-offset stack)))
        (sc-case stack
-        ((control-stack)
-         (storew reg cfp-tn offset))))))
+         ((control-stack)
+          (storew reg cfp-tn offset))))))
 
 (defmacro maybe-load-stack-tn (reg reg-or-stack)
+  #!+sb-doc
   "Move the TN Reg-Or-Stack into Reg if it isn't already there."
   (once-only ((n-reg reg)
-             (n-stack reg-or-stack))
+              (n-stack reg-or-stack))
     `(sc-case ,n-reg
        ((any-reg descriptor-reg)
-       (sc-case ,n-stack
-         ((any-reg descriptor-reg)
-          (move ,n-reg ,n-stack))
-         ((control-stack)
-          (loadw ,n-reg cfp-tn (tn-offset ,n-stack))))))))
+        (sc-case ,n-stack
+          ((any-reg descriptor-reg)
+           (move ,n-reg ,n-stack))
+          ((control-stack)
+           (loadw ,n-reg cfp-tn (tn-offset ,n-stack))))))))
 
 \f
 ;;;; Storage allocation:
-(defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code size)
-                                &body body)
+(defmacro with-fixed-allocation ((result-tn flag-tn temp-tn type-code
+                                  size dynamic-extent-p
+                                  &key (lowtag other-pointer-lowtag))
+                                 &body body)
+  #!+sb-doc
   "Do stuff to allocate an other-pointer object of fixed Size with a single
-   word header having the specified Type-Code.  The result is placed in
-   Result-TN, Flag-Tn must be wired to NL3-OFFSET, and Temp-TN is a non-
-   descriptor temp (which may be randomly used by the body.)  The body is
-   placed inside the PSEUDO-ATOMIC, and presumably initializes the object."
-  `(pseudo-atomic (,flag-tn :extra (pad-data-block ,size))
-     (inst or ,result-tn alloc-tn other-pointer-lowtag)
-     (inst li ,temp-tn (logior (ash (1- ,size) n-widetag-bits) ,type-code))
-     (storew ,temp-tn ,result-tn 0 other-pointer-lowtag)
-     ,@body))
-
+word header having the specified Type-Code.  The result is placed in
+Result-TN, Flag-Tn must be wired to NL4-OFFSET, and Temp-TN is a non-
+descriptor temp (which may be randomly used by the body.)  The body is
+placed inside the PSEUDO-ATOMIC, and presumably initializes the object."
+  (unless body
+    (bug "empty &body in WITH-FIXED-ALLOCATION"))
+  (once-only ((result-tn result-tn) (flag-tn flag-tn) (temp-tn temp-tn)
+              (type-code type-code) (size size)
+              (dynamic-extent-p dynamic-extent-p)
+              (lowtag lowtag))
+    `(if ,dynamic-extent-p
+         (pseudo-atomic (,flag-tn)
+           (align-csp ,temp-tn)
+           (inst or ,result-tn csp-tn ,lowtag)
+           (inst li ,temp-tn (logior (ash (1- ,size) n-widetag-bits) ,type-code))
+           (inst addu csp-tn (pad-data-block ,size))
+           (storew ,temp-tn ,result-tn 0 ,lowtag)
+           ,@body)
+         (pseudo-atomic (,flag-tn :extra (pad-data-block ,size))
+           ;; The pseudo-atomic bit in alloc-tn is set.  If the lowtag also
+           ;; has a 1 bit in the same position, we're all set.  Otherwise,
+           ;; we need to subtract the pseudo-atomic bit.
+           (inst or ,result-tn alloc-tn ,lowtag)
+           (unless (logbitp 0 ,lowtag) (inst sub ,result-tn 1))
+           (inst li ,temp-tn (logior (ash (1- ,size) n-widetag-bits) ,type-code))
+           (storew ,temp-tn ,result-tn 0 ,lowtag)
+           ,@body))))
+
+(defun align-csp (temp)
+  ;; is used for stack allocation of dynamic-extent objects
+  (let ((aligned (gen-label)))
+    (inst and temp csp-tn lowtag-mask)
+    (inst beq temp aligned)
+    (inst nop)
+    (inst addu csp-tn n-word-bytes)
+    (storew zero-tn csp-tn -1)
+    (emit-label aligned)))
 
 \f
 ;;;; Three Way Comparison
   (ecase condition
     (:eq
      (if not-p
-        (inst bne x y target)
-        (inst beq x y target)))
+         (inst bne x y target)
+         (inst beq x y target)))
     (:lt
      (ecase flavor
        (:unsigned
-       (inst sltu temp x y))
+        (inst sltu temp x y))
        (:signed
-       (inst slt temp x y)))
+        (inst slt temp x y)))
      (if not-p
-        (inst beq temp zero-tn target)
-        (inst bne temp zero-tn target)))
+         (inst beq temp target)
+         (inst bne temp target)))
     (:gt
      (ecase flavor
        (:unsigned
-       (inst sltu temp y x))
+        (inst sltu temp y x))
        (:signed
-       (inst slt temp y x)))
+        (inst slt temp y x)))
      (if not-p
-        (inst beq temp zero-tn target)
-        (inst bne temp zero-tn target))))
+         (inst beq temp target)
+         (inst bne temp target))))
   (inst nop))
 
 
 \f
 ;;;; Error Code
-(eval-when (compile load eval)
+(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
   (defun emit-error-break (vop kind code values)
     (let ((vector (gensym)))
       `((let ((vop ,vop))
-         (when vop
-           (note-this-location vop :internal-error)))
-       (inst break ,kind)
-       (with-adjustable-vector (,vector)
-         (write-var-integer (error-number-or-lose ',code) ,vector)
-         ,@(mapcar #'(lambda (tn)
-                       `(let ((tn ,tn))
-                          (write-var-integer (make-sc-offset (sc-number
-                                                              (tn-sc tn))
-                                                             (tn-offset tn))
-                                             ,vector)))
-                   values)
-         (inst byte (length ,vector))
-         (dotimes (i (length ,vector))
-           (inst byte (aref ,vector i))))
-       (align word-shift)))))
+          (when vop
+            (note-this-location vop :internal-error)))
+        (inst break 0 ,kind)
+        (with-adjustable-vector (,vector)
+          (write-var-integer (error-number-or-lose ',code) ,vector)
+          ,@(mapcar #'(lambda (tn)
+                        `(let ((tn ,tn))
+                           (write-var-integer (make-sc-offset (sc-number
+                                                               (tn-sc tn))
+                                                              (tn-offset tn))
+                                              ,vector)))
+                    values)
+          (inst byte (length ,vector))
+          (dotimes (i (length ,vector))
+            (inst byte (aref ,vector i))))
+        (emit-alignment word-shift)))))
 
 (defmacro error-call (vop error-code &rest values)
+  #!+sb-doc
   "Cause an error.  ERROR-CODE is the error to cause."
   (cons 'progn
-       (emit-error-break vop error-trap error-code values)))
+        (emit-error-break vop error-trap error-code values)))
 
 
 (defmacro cerror-call (vop label error-code &rest values)
+  #!+sb-doc
   "Cause a continuable error.  If the error is continued, execution resumes at
   LABEL."
   `(progn
-     (inst b ,label)
-     ,@(emit-error-break vop cerror-trap error-code values)))
+     (without-scheduling ()
+       (inst b ,label)
+       ,@(emit-error-break vop cerror-trap error-code values))))
 
 (defmacro generate-error-code (vop error-code &rest values)
+  #!+sb-doc
   "Generate-Error-Code Error-code Value*
   Emit code for an error with the specified Error-Code and context Values."
   `(assemble (*elsewhere*)
        start-lab)))
 
 (defmacro generate-cerror-code (vop error-code &rest values)
+  #!+sb-doc
   "Generate-CError-Code Error-code Value*
   Emit code for a continuable error with the specified Error-Code and
   context Values.  If the error is continued, execution resumes after
     `(let ((,continue (gen-label)))
        (emit-label ,continue)
        (assemble (*elsewhere*)
-        (let ((,error (gen-label)))
-          (emit-label ,error)
-          (cerror-call ,vop ,continue ,error-code ,@values)
-          ,error)))))
+         (let ((,error (gen-label)))
+           (emit-label ,error)
+           (cerror-call ,vop ,continue ,error-code ,@values)
+           ,error)))))
 \f
 ;;;; PSEUDO-ATOMIC
 
      ,@forms
      (without-scheduling ()
        (let ((label (gen-label)))
-        (inst nop)
-        (inst nop)
-        (inst nop)
-        (inst bgez ,flag-tn label)
-        (inst addu alloc-tn (1- ,extra))
-        (inst break 16)
-        (emit-label label)))))
+         (inst bgez ,flag-tn label)
+         (inst addu alloc-tn (1- ,extra))
+         (inst break 0 16)
+         (emit-label label)))))
 \f
 ;;;; memory accessor vop generators
 
 (deftype load/store-index (scale lowtag min-offset
-                                &optional (max-offset min-offset))
+                                 &optional (max-offset min-offset))
   `(integer ,(- (truncate (+ (ash 1 16)
-                            (* min-offset n-word-bytes)
-                            (- lowtag))
-                         scale))
-           ,(truncate (- (+ (1- (ash 1 16)) lowtag)
-                         (* max-offset n-word-bytes))
-                      scale)))
+                             (* min-offset n-word-bytes)
+                             (- lowtag))
+                          scale))
+            ,(truncate (- (+ (1- (ash 1 16)) lowtag)
+                          (* max-offset n-word-bytes))
+                       scale)))
 
 (defmacro define-full-reffer (name type offset lowtag scs el-type
-                                  &optional translate)
+                                   &optional translate)
   `(progn
      (define-vop (,name)
        ,@(when translate
-          `((:translate ,translate)))
+           `((:translate ,translate)))
        (:policy :fast-safe)
        (:args (object :scs (descriptor-reg))
-             (index :scs (any-reg)))
+              (index :scs (any-reg)))
        (:arg-types ,type tagged-num)
        (:temporary (:scs (interior-reg)) lip)
        (:results (value :scs ,scs))
        (:result-types ,el-type)
        (:generator 5
-        (inst add lip object index)
-        (inst lw value lip (- (* ,offset n-word-bytes) ,lowtag))
-        (inst nop)))
+         (inst addu lip object index)
+         (loadw value lip ,offset ,lowtag)))
      (define-vop (,(symbolicate name "-C"))
        ,@(when translate
-          `((:translate ,translate)))
+           `((:translate ,translate)))
        (:policy :fast-safe)
        (:args (object :scs (descriptor-reg)))
        (:info index)
        (:arg-types ,type
-                  (:constant (load/store-index ,n-word-bytes ,(eval lowtag)
-                                               ,(eval offset))))
+                   (:constant (load/store-index ,n-word-bytes ,(eval lowtag)
+                                                ,(eval offset))))
        (:results (value :scs ,scs))
        (:result-types ,el-type)
        (:generator 4
-        (inst lw value object (- (* (+ ,offset index) n-word-bytes) ,lowtag))
-        (inst nop)))))
+         (loadw value object (+ ,offset index) ,lowtag)))))
 
 (defmacro define-full-setter (name type offset lowtag scs el-type
-                                  &optional translate)
+                                   &optional translate)
   `(progn
      (define-vop (,name)
        ,@(when translate
-          `((:translate ,translate)))
+           `((:translate ,translate)))
        (:policy :fast-safe)
        (:args (object :scs (descriptor-reg))
-             (index :scs (any-reg))
-             (value :scs ,scs :target result))
+              (index :scs (any-reg))
+              (value :scs ,scs :target result))
        (:arg-types ,type tagged-num ,el-type)
        (:temporary (:scs (interior-reg)) lip)
        (:results (result :scs ,scs))
        (:result-types ,el-type)
        (:generator 2
-        (inst add lip object index)
-        (inst sw value lip (- (* ,offset n-word-bytes) ,lowtag))
-        (move result value)))
+         (inst addu lip object index)
+         (storew value lip ,offset ,lowtag)
+         (move result value)))
      (define-vop (,(symbolicate name "-C"))
        ,@(when translate
-          `((:translate ,translate)))
+           `((:translate ,translate)))
        (:policy :fast-safe)
        (:args (object :scs (descriptor-reg))
-             (value :scs ,scs))
+              (value :scs ,scs))
        (:info index)
        (:arg-types ,type
-                  (:constant (load/store-index ,n-word-bytes ,(eval lowtag)
-                                               ,(eval offset)))
-                  ,el-type)
+                   (:constant (load/store-index ,n-word-bytes ,(eval lowtag)
+                                                ,(eval offset)))
+                   ,el-type)
        (:results (result :scs ,scs))
        (:result-types ,el-type)
        (:generator 1
-        (inst sw value object (- (* (+ ,offset index) n-word-bytes) ,lowtag))
-        (move result value)))))
+         (storew value object (+ ,offset index) ,lowtag)
+         (move result value)))))
 
 
 (defmacro define-partial-reffer (name type size signed offset lowtag scs
-                                     el-type &optional translate)
+                                      el-type &optional translate)
   (let ((scale (ecase size (:byte 1) (:short 2))))
     `(progn
        (define-vop (,name)
-        ,@(when translate
-            `((:translate ,translate)))
-        (:policy :fast-safe)
-        (:args (object :scs (descriptor-reg))
-               (index :scs (unsigned-reg)))
-        (:arg-types ,type positive-fixnum)
-        (:results (value :scs ,scs))
-        (:result-types ,el-type)
-        (:temporary (:scs (interior-reg)) lip)
-        (:generator 5
-          (inst addu lip object index)
-          ,@(when (eq size :short)
-              '((inst addu lip index)))
-          (inst ,(ecase size
-                   (:byte (if signed 'lb 'lbu))
-                   (:short (if signed 'lh 'lhu)))
-                value lip (- (* ,offset n-word-bytes) ,lowtag))
-          (inst nop)))
+         ,@(when translate
+             `((:translate ,translate)))
+         (:policy :fast-safe)
+         (:args (object :scs (descriptor-reg))
+                (index :scs (unsigned-reg)))
+         (:arg-types ,type positive-fixnum)
+         (:results (value :scs ,scs))
+         (:result-types ,el-type)
+         (:temporary (:scs (interior-reg)) lip)
+         (:generator 5
+           (inst addu lip object index)
+           ,@(when (eq size :short)
+               '((inst addu lip index)))
+           (inst ,(ecase size
+                    (:byte (if signed 'lb 'lbu))
+                    (:short (if signed 'lh 'lhu)))
+                 value lip (- (* ,offset n-word-bytes) ,lowtag))
+           (inst nop)))
        (define-vop (,(symbolicate name "-C"))
-        ,@(when translate
-            `((:translate ,translate)))
-        (:policy :fast-safe)
-        (:args (object :scs (descriptor-reg)))
-        (:info index)
-        (:arg-types ,type
-                    (:constant (load/store-index ,scale
-                                                 ,(eval lowtag)
-                                                 ,(eval offset))))
-        (:results (value :scs ,scs))
-        (:result-types ,el-type)
-        (:generator 5
-          (inst ,(ecase size
-                   (:byte (if signed 'lb 'lbu))
-                   (:short (if signed 'lh 'lhu)))
-                value object
-                (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag))
-          (inst nop))))))
+         ,@(when translate
+             `((:translate ,translate)))
+         (:policy :fast-safe)
+         (:args (object :scs (descriptor-reg)))
+         (:info index)
+         (:arg-types ,type
+                     (:constant (load/store-index ,scale
+                                                  ,(eval lowtag)
+                                                  ,(eval offset))))
+         (:results (value :scs ,scs))
+         (:result-types ,el-type)
+         (:generator 4
+           (inst ,(ecase size
+                    (:byte (if signed 'lb 'lbu))
+                    (:short (if signed 'lh 'lhu)))
+                 value object
+                 (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag))
+           (inst nop))))))
 
 (defmacro define-partial-setter (name type size offset lowtag scs el-type
-                                     &optional translate)
+                                      &optional translate)
   (let ((scale (ecase size (:byte 1) (:short 2))))
     `(progn
        (define-vop (,name)
-        ,@(when translate
-            `((:translate ,translate)))
-        (:policy :fast-safe)
-        (:args (object :scs (descriptor-reg))
-               (index :scs (unsigned-reg))
-               (value :scs ,scs :target result))
-        (:arg-types ,type positive-fixnum ,el-type)
-        (:temporary (:scs (interior-reg)) lip)
-        (:results (result :scs ,scs))
-        (:result-types ,el-type)
-        (:generator 5
-          (inst addu lip object index)
-          ,@(when (eq size :short)
-              '((inst addu lip index)))
-          (inst ,(ecase size (:byte 'sb) (:short 'sh))
-                value lip (- (* ,offset n-word-bytes) ,lowtag))
-          (move result value)))
+         ,@(when translate
+             `((:translate ,translate)))
+         (:policy :fast-safe)
+         (:args (object :scs (descriptor-reg))
+                (index :scs (unsigned-reg))
+                (value :scs ,scs :target result))
+         (:arg-types ,type positive-fixnum ,el-type)
+         (:temporary (:scs (interior-reg)) lip)
+         (:results (result :scs ,scs))
+         (:result-types ,el-type)
+         (:generator 5
+           (inst addu lip object index)
+           ,@(when (eq size :short)
+               '((inst addu lip index)))
+           (inst ,(ecase size (:byte 'sb) (:short 'sh))
+                 value lip (- (* ,offset n-word-bytes) ,lowtag))
+           (move result value)))
        (define-vop (,(symbolicate name "-C"))
-        ,@(when translate
-            `((:translate ,translate)))
-        (:policy :fast-safe)
-        (:args (object :scs (descriptor-reg))
-               (value :scs ,scs :target result))
-        (:info index)
-        (:arg-types ,type
-                    (:constant (load/store-index ,scale
-                                                 ,(eval lowtag)
-                                                 ,(eval offset)))
-                    ,el-type)
-        (:results (result :scs ,scs))
-        (:result-types ,el-type)
-        (:generator 5
-          (inst ,(ecase size (:byte 'sb) (:short 'sh))
-                value object
-                (- (* ,offset n-word-bytes) (* index ,scale) ,lowtag))
-          (move result value))))))
-
+         ,@(when translate
+             `((:translate ,translate)))
+         (:policy :fast-safe)
+         (:args (object :scs (descriptor-reg))
+                (value :scs ,scs :target result))
+         (:info index)
+         (:arg-types ,type
+                     (:constant (load/store-index ,scale
+                                                  ,(eval lowtag)
+                                                  ,(eval offset)))
+                     ,el-type)
+         (:results (result :scs ,scs))
+         (:result-types ,el-type)
+         (:generator 4
+           (inst ,(ecase size (:byte 'sb) (:short 'sh))
+                 value object
+                 (- (+ (* ,offset n-word-bytes) (* index ,scale)) ,lowtag))
+           (move result value))))))
+
+
+(def!macro with-pinned-objects ((&rest objects) &body body)
+  "Arrange with the garbage collector that the pages occupied by
+OBJECTS will not be moved in memory for the duration of BODY.
+Useful for e.g. foreign calls where another thread may trigger
+garbage collection.  This is currently implemented by disabling GC"
+  (declare (ignore objects))            ;should we eval these for side-effect?
+  `(without-gcing
+    ,@body))