Clean up some SSE instruction format definitions on x86-64
[sbcl.git] / src / compiler / x86-64 / insts.lisp
index 42ca8e6..83f1e8d 100644 (file)
     vec))
 ) ; EVAL-WHEN
 
+;;; SSE shuffle patterns. The names end in the number of bits of the
+;;; immediate byte that are used to encode the pattern and the radix
+;;; in which to print the value.
+(macrolet ((define-sse-shuffle-arg-type (name format-string)
+               `(sb!disassem:define-arg-type ,name
+                  :type 'imm-byte
+                  :printer (lambda (value stream dstate)
+                             (declare (type (unsigned-byte 8) value)
+                                      (type stream stream)
+                                      (ignore dstate))
+                             (format stream ,format-string value)))))
+  (define-sse-shuffle-arg-type sse-shuffle-pattern-2-2 "#b~2,'0B")
+  (define-sse-shuffle-arg-type sse-shuffle-pattern-8-4 "#4r~4,4,'0R"))
+
 ;;; Set assembler parameters. (In CMU CL, this was done with
 ;;; a call to a macro DEF-ASSEMBLER-PARAMS.)
 (eval-when (:compile-toplevel :load-toplevel :execute)
   (op      :field (byte 8 8))
   (reg/mem :fields (list (byte 2 22) (byte 3 16))
                                 :type 'xmmreg/mem)
-  (reg     :field (byte 3 19)   :type 'xmmreg))
+  (reg     :field (byte 3 19)   :type 'xmmreg)
+  ;; optional fields
+  (imm))
 
 (sb!disassem:define-instruction-format (rex-xmm-xmm/mem 32
                                         :default-printer
   (op      :field (byte 8 16))
   (reg/mem :fields (list (byte 2 30) (byte 3 24))
                                 :type 'xmmreg/mem)
-  (reg     :field (byte 3 27)   :type 'xmmreg))
+  (reg     :field (byte 3 27)   :type 'xmmreg)
+  (imm))
 
 (sb!disassem:define-instruction-format (ext-xmm-xmm/mem 32
                                         :default-printer
   (op      :field (byte 8 16))
   (reg/mem :fields (list (byte 2 30) (byte 3 24))
                                 :type 'xmmreg/mem)
-  (reg     :field (byte 3 27)   :type 'xmmreg))
+  (reg     :field (byte 3 27)   :type 'xmmreg)
+  (imm))
 
 (sb!disassem:define-instruction-format (ext-rex-xmm-xmm/mem 40
                                         :default-printer
   (op      :field (byte 8 24))
   (reg/mem :fields (list (byte 2 38) (byte 3 32))
                                 :type 'xmmreg/mem)
-  (reg     :field (byte 3 35)   :type 'xmmreg))
+  (reg     :field (byte 3 35)   :type 'xmmreg)
+  (imm))
 
 ;;; Same as xmm-xmm/mem etc., but with direction bit.
 
   :type 'imm-byte
   :printer *sse-conditions*)
 
-;;; XMM instructions with 8 bit immediate data
-
-(sb!disassem:define-instruction-format (xmm-xmm/mem-imm 24
-                                        :default-printer
-                                        '(:name
-                                          :tab reg ", " reg/mem ", " imm))
-  (x0f     :field (byte 8 0)    :value #x0f)
-  (op      :field (byte 8 8))
-  (reg/mem :fields (list (byte 2 22) (byte 3 16))
-                                :type 'xmmreg/mem)
-  (reg     :field (byte 3 19)   :type 'xmmreg)
-  (imm     :type 'imm-byte))
-
-(sb!disassem:define-instruction-format (rex-xmm-xmm/mem-imm 32
-                                        :default-printer
-                                        '(:name
-                                          :tab reg ", " reg/mem ", " imm))
-  (rex     :field (byte 4 4)    :value #b0100)
-  (wrxb    :field (byte 4 0)    :type 'wrxb)
-  (x0f     :field (byte 8 8)    :value #x0f)
-  (op      :field (byte 8 16))
-  (reg/mem :fields (list (byte 2 30) (byte 3 24))
-                                :type 'xmmreg/mem)
-  (reg     :field (byte 3 27)   :type 'xmmreg)
-  (imm     :type 'imm-byte))
-
-(sb!disassem:define-instruction-format (ext-xmm-xmm/mem-imm 32
-                                        :default-printer
-                                        '(:name
-                                          :tab reg ", " reg/mem ", " imm))
-  (prefix  :field (byte 8 0))
-  (x0f     :field (byte 8 8)    :value #x0f)
-  (op      :field (byte 8 16))
-  (reg/mem :fields (list (byte 2 30) (byte 3 24))
-                                :type 'xmmreg/mem)
-  (reg     :field (byte 3 27)   :type 'xmmreg)
-  (imm     :type 'imm-byte))
-
-(sb!disassem:define-instruction-format (ext-rex-xmm-xmm/mem-imm 40
-                                        :default-printer
-                                        '(:name
-                                          :tab reg ", " reg/mem ", " imm))
-  (prefix  :field (byte 8 0))
-  (rex     :field (byte 4 12)   :value #b0100)
-  (wrxb    :field (byte 4 8)    :type 'wrxb)
-  (x0f     :field (byte 8 16)   :value #x0f)
-  (op      :field (byte 8 24))
-  (reg/mem :fields (list (byte 2 38) (byte 3 32))
-                                :type 'xmmreg/mem)
-  (reg     :field (byte 3 35)   :type 'xmmreg)
-  (imm     :type 'imm-byte))
-
 (sb!disassem:define-instruction-format (string-op 8
                                      :include 'simple
                                      :default-printer '(:name width)))
 (macrolet
     ((define-imm-sse-instruction (name opcode /i)
          `(define-instruction ,name (segment dst/src imm)
-            (:printer ext-rex-xmm-imm ((prefix #x66) (op ,opcode) (/i ,/i)))
-            (:printer ext-xmm-imm ((prefix #x66) (op ,opcode) (/i ,/i)))
+            (:printer-list
+             ',(sse-inst-printer-list 'xmm-imm #x66 opcode
+                                      :more-fields `((/i ,/i))))
             (:emitter
              (emit-sse-inst-with-imm segment dst/src imm
                                      #x66 ,opcode ,/i
                                      :operand-size :do-not-set)))))
   (define-imm-sse-instruction pslldq #x73 7)
-  (define-imm-sse-instruction psllw #x71 6)
-  (define-imm-sse-instruction pslld #x72 6)
-  (define-imm-sse-instruction psllq #x73 6)
+  (define-imm-sse-instruction psllw-imm #x71 6)
+  (define-imm-sse-instruction pslld-imm #x72 6)
+  (define-imm-sse-instruction psllq-imm #x73 6)
 
   (define-imm-sse-instruction psraw-imm #x71 4)
   (define-imm-sse-instruction psrad-imm #x72 4)
 
   (define-imm-sse-instruction psrldq #x73 3)
-  (define-imm-sse-instruction psrlw #x71 2)
-  (define-imm-sse-instruction psrld #x72 2)
-  (define-imm-sse-instruction psrlq #x73 2))
+  (define-imm-sse-instruction psrlw-imm #x71 2)
+  (define-imm-sse-instruction psrld-imm #x72 2)
+  (define-imm-sse-instruction psrlq-imm #x73 2))
 
 ;;; Emit an SSE instruction that has an XMM register as the destination
 ;;; operand and for which the size of the operands is implicitly given
 
 (macrolet ((define-regular-sse-inst (name prefix opcode)
              `(define-instruction ,name (segment dst src)
-                ,@(if prefix
-                      `((:printer ext-xmm-xmm/mem
-                                  ((prefix ,prefix) (op ,opcode)))
-                        (:printer ext-rex-xmm-xmm/mem
-                                  ((prefix ,prefix) (op ,opcode))))
-                      `((:printer xmm-xmm/mem ((op ,opcode)))
-                        (:printer rex-xmm-xmm/mem ((op ,opcode)))))
+                (:printer-list
+                 ',(sse-inst-printer-list 'xmm-xmm/mem prefix opcode))
                 (:emitter
                  (emit-regular-sse-inst segment dst src ,prefix ,opcode)))))
   ;; logical
   (define-regular-sse-inst mulps    nil  #x59)
   (define-regular-sse-inst mulsd    #xf2 #x59)
   (define-regular-sse-inst mulss    #xf3 #x59)
-  (define-regular-sse-inst rccps    nil  #x53)
+  (define-regular-sse-inst rcpps    nil  #x53)
   (define-regular-sse-inst rcpss    #xf3 #x53)
   (define-regular-sse-inst rsqrtps  nil  #x52)
   (define-regular-sse-inst rsqrtss  #xf3 #x52)
+  (define-regular-sse-inst sqrtpd   #x66 #x51)
   (define-regular-sse-inst sqrtps   nil  #x51)
   (define-regular-sse-inst sqrtsd   #xf2 #x51)
   (define-regular-sse-inst sqrtss   #xf3 #x51)
   (define-regular-sse-inst paddsb   #x66 #xec)
   (define-regular-sse-inst paddsw   #x66 #xed)
   (define-regular-sse-inst paddusb  #x66 #xdc)
-  (define-regular-sse-inst padduwb  #x66 #xdd)
+  (define-regular-sse-inst paddusw  #x66 #xdd)
   (define-regular-sse-inst pavgb    #x66 #xe0)
   (define-regular-sse-inst pavgw    #x66 #xe3)
   (define-regular-sse-inst pmaddwd  #x66 #xf5)
   (define-regular-sse-inst pmullw   #x66 #xd5)
   (define-regular-sse-inst pmuludq  #x66 #xf4)
   (define-regular-sse-inst psadbw   #x66 #xf6)
+  (define-regular-sse-inst psllw    #x66 #xf1)
+  (define-regular-sse-inst pslld    #x66 #xf2)
+  (define-regular-sse-inst psllq    #x66 #xf3)
   (define-regular-sse-inst psraw    #x66 #xe1)
   (define-regular-sse-inst psrad    #x66 #xe2)
+  (define-regular-sse-inst psrlw    #x66 #xd1)
+  (define-regular-sse-inst psrld    #x66 #xd2)
+  (define-regular-sse-inst psrlq    #x66 #xd3)
   (define-regular-sse-inst psubb    #x66 #xf8)
   (define-regular-sse-inst psubw    #x66 #xf9)
   (define-regular-sse-inst psubd    #x66 #xfa)
   (define-regular-sse-inst psubq    #x66 #xfb)
-  (define-regular-sse-inst psubsb   #x66 #xd8)
-  (define-regular-sse-inst psubsw   #x66 #xd9)
+  (define-regular-sse-inst psubsb   #x66 #xe8)
+  (define-regular-sse-inst psubsw   #x66 #xe9)
+  (define-regular-sse-inst psubusb  #x66 #xd8)
+  (define-regular-sse-inst psubusw  #x66 #xd9)
   ;; conversion
   (define-regular-sse-inst cvtdq2pd #xf3 #xe6)
   (define-regular-sse-inst cvtdq2ps nil  #x5b)
   (define-regular-sse-inst cvtss2sd #xf3 #x5a)
   (define-regular-sse-inst cvttpd2dq #x66 #xe6)
   (define-regular-sse-inst cvttps2dq #xf3 #x5b)
-  ;; moves
-  (define-regular-sse-inst movntdq #x66 #xe7)
-  (define-regular-sse-inst movntpd #x66 #x2b)
-  (define-regular-sse-inst movntps nil #x2b)
   ;; integer
   (define-regular-sse-inst packsswb  #x66 #x63)
   (define-regular-sse-inst packssdw  #x66 #x6b)
+  (define-regular-sse-inst packuswb  #x66 #x67)
   (define-regular-sse-inst punpckhbw #x66 #x68)
   (define-regular-sse-inst punpckhwd #x66 #x69)
   (define-regular-sse-inst punpckhdq #x66 #x6a)
   (define-regular-sse-inst punpckldq #x66 #x62)
   (define-regular-sse-inst punpcklqdq #x66 #x6c))
 
-(macrolet ((define-xmm-shuffle-sse-inst (name prefix opcode)
-               `(define-instruction ,name (segment dst src pattern)
-                  ,@(if prefix
-                        `((:printer ext-xmm-xmm/mem-imm ; suboptimal
-                                    ((prefix ,prefix) (op ,opcode)))
-                          (:printer ext-rex-xmm-xmm/mem-imm
-                                    ((prefix ,prefix) (op ,opcode))))
-                        `((:printer xmm-xmm/mem-imm ((op ,opcode)))
-                          (:printer rex-xmm-xmm/mem-imm ((op ,opcode)))))
-                  (:emitter
-                   (aver (typep pattern '(unsigned-byte 8)))
-                   (emit-regular-sse-inst segment dst src ,prefix ,opcode
-                                          :remaining-bytes 1)
-                   (emit-byte segment pattern)))))
-  (define-xmm-shuffle-sse-inst pshufd  #x66 #x70)
-  (define-xmm-shuffle-sse-inst pshufhw #xf3 #x70)
-  (define-xmm-shuffle-sse-inst pshuflw #xf2 #x70)
-  (define-xmm-shuffle-sse-inst shufpd  #x66 #xc6)
-  (define-xmm-shuffle-sse-inst shufps  nil  #xc6))
+(macrolet ((define-xmm-shuffle-sse-inst (name prefix opcode n-bits radix)
+               (let ((shuffle-pattern
+                      (intern (format nil "SSE-SHUFFLE-PATTERN-~D-~D"
+                                      n-bits radix))))
+                 `(define-instruction ,name (segment dst src pattern)
+                    (:printer-list
+                     ',(sse-inst-printer-list
+                        'xmm-xmm/mem prefix opcode
+                        :more-fields `((imm nil :type ,shuffle-pattern))
+                        :printer '(:name :tab reg ", " reg/mem ", " imm)))
+
+                    (:emitter
+                     (aver (typep pattern '(unsigned-byte ,n-bits)))
+                     (emit-regular-sse-inst segment dst src ,prefix ,opcode
+                                            :remaining-bytes 1)
+                     (emit-byte segment pattern))))))
+  (define-xmm-shuffle-sse-inst pshufd  #x66 #x70 8 4)
+  (define-xmm-shuffle-sse-inst pshufhw #xf3 #x70 8 4)
+  (define-xmm-shuffle-sse-inst pshuflw #xf2 #x70 8 4)
+  (define-xmm-shuffle-sse-inst shufpd  #x66 #xc6 2 2)
+  (define-xmm-shuffle-sse-inst shufps  nil  #xc6 8 4))
 
 ;; MASKMOVDQU (dst is DS:RDI)
 (define-instruction maskmovdqu (segment src mask)
-  (:printer ext-xmm-xmm/mem
-            ((prefix #x66) (op #xf7)))
-  (:printer ext-rex-xmm-xmm/mem
-            ((prefix #x66) (op #xf7)))
+  (:printer-list
+   (sse-inst-printer-list 'xmm-xmm/mem #x66 #xf7))
   (:emitter
    (aver (xmm-register-p src))
    (aver (xmm-register-p mask))
                `(define-instruction ,name (segment op x y)
                   (:printer-list
                    ',(sse-inst-printer-list
-                      'xmm-xmm/mem-imm prefix opcode
+                      'xmm-xmm/mem prefix opcode
                       :more-fields '((imm nil :type sse-condition-code))
                       :printer `(,name-prefix imm ,name-suffix
                                  :tab reg ", " reg/mem)))
 ;;; MOVSD, MOVSS
 (macrolet ((define-movsd/ss-sse-inst (name prefix)
              `(define-instruction ,name (segment dst src)
-                (:printer ext-xmm-xmm/mem-dir ((prefix ,prefix)
-                                               (op #b0001000)))
-                (:printer ext-rex-xmm-xmm/mem-dir ((prefix ,prefix)
-                                                   (op #b0001000)))
+                (:printer-list
+                 ',(sse-inst-printer-list 'xmm-xmm/mem-dir
+                                          prefix #b0001000))
                 (:emitter
                  (cond ((xmm-register-p dst)
                         (emit-sse-inst segment dst src ,prefix #x10
                         (:emitter
                          (aver (xmm-register-p dst))
                          (aver (xmm-register-p src))
-                         (emit-regular-sse-inst segment dst src ,prefix ,opcode-from))))
+                         (emit-regular-sse-inst segment dst src
+                                                ,prefix ,opcode-from))))
                   (define-instruction ,name (segment dst src)
-                    ,@(if prefix
-                          `((:printer ext-xmm-xmm/mem
-                                      ((prefix ,prefix) (op ,opcode-from)))
-                            (:printer ext-rex-xmm-xmm/mem
-                                      ((prefix ,prefix) (op ,opcode-from)))
-                            (:printer ext-xmm-xmm/mem
-                                      ((prefix ,prefix) (op ,opcode-to))
-                                      '(:name :tab reg/mem ", " reg))
-                            (:printer ext-rex-xmm-xmm/mem
-                                      ((prefix ,prefix) (op ,opcode-to))
-                                      '(:name :tab reg/mem ", " reg)))
-                          `((:printer xmm-xmm/mem
-                                      ((op ,opcode-from)))
-                            (:printer rex-xmm-xmm/mem
-                                      ((op ,opcode-from)))
-                            (:printer xmm-xmm/mem
-                                      ((op ,opcode-to))
-                                      '(:name :tab reg/mem ", " reg))
-                            (:printer rex-xmm-xmm/mem
-                                      ((op ,opcode-to))
-                                      '(:name :tab reg/mem ", " reg))))
+                    (:printer-list
+                     '(,@(when opcode-from
+                           (sse-inst-printer-list
+                            'xmm-xmm/mem prefix opcode-from))
+                       ,@(sse-inst-printer-list
+                          'xmm-xmm/mem prefix opcode-to
+                          :printer '(:name :tab reg/mem ", " reg))))
                     (:emitter
-                     (cond ((xmm-register-p dst)
-                            ,(when force-to-mem
-                               `(aver (not (or (register-p src)
-                                               (xmm-register-p src)))))
-                            (emit-regular-sse-inst segment dst src ,prefix ,opcode-from))
+                     (cond ,@(when opcode-from
+                               `(((xmm-register-p dst)
+                                  ,(when force-to-mem
+                                     `(aver (not (or (register-p src)
+                                                     (xmm-register-p src)))))
+                                  (emit-regular-sse-inst
+                                   segment dst src ,prefix ,opcode-from))))
                            (t
                             (aver (xmm-register-p src))
                             ,(when force-to-mem
                                `(aver (not (or (register-p dst)
                                                (xmm-register-p dst)))))
-                            (emit-regular-sse-inst segment src dst ,prefix ,opcode-to))))))))
+                            (emit-regular-sse-inst segment src dst
+                                                   ,prefix ,opcode-to))))))))
   ;; direction bit?
   (define-mov-sse-inst movapd #x66 #x28 #x29)
   (define-mov-sse-inst movaps nil  #x28 #x29)
   (define-mov-sse-inst movdqa #x66 #x6f #x7f)
   (define-mov-sse-inst movdqu #xf3 #x6f #x7f)
 
+  ;; streaming
+  (define-mov-sse-inst movntdq #x66 nil #xe7 :force-to-mem t)
+  (define-mov-sse-inst movntpd #x66 nil #x2b :force-to-mem t)
+  (define-mov-sse-inst movntps nil  nil #x2b :force-to-mem t)
+
   ;; use movhps for movlhps and movlps for movhlps
   (define-mov-sse-inst movhpd #x66 #x16 #x17 :force-to-mem t)
   (define-mov-sse-inst movhps nil  #x16 #x17 :reg-reg-name movlhps)
 
 ;;; MOVQ
 (define-instruction movq (segment dst src)
-  (:printer ext-xmm-xmm/mem ((prefix #xf3) (op #x7e)))
-  (:printer ext-rex-xmm-xmm/mem ((prefix #xf3) (op #x7e)))
-  (:printer ext-xmm-xmm/mem ((prefix #x66) (op #xd6))
-            '(:name :tab reg/mem ", " reg))
-  (:printer ext-rex-xmm-xmm/mem ((prefix #x66) (op #xd6))
-            '(:name :tab reg/mem ", " reg))
+  (:printer-list
+   (append
+    (sse-inst-printer-list 'xmm-xmm/mem #xf3 #x7e)
+    (sse-inst-printer-list 'xmm-xmm/mem #x66 #xd6
+                           :printer '(:name :tab reg/mem ", " reg))))
   (:emitter
    (cond ((xmm-register-p dst)
           (emit-sse-inst segment dst src #xf3 #x7e
 ;;; with zero extension or vice versa.
 ;;; We do not support the MMX version of this instruction.
 (define-instruction movd (segment dst src)
-  (:printer ext-xmm-reg/mem ((prefix #x66) (op #x6e)))
-  (:printer ext-rex-xmm-reg/mem ((prefix #x66) (op #x6e)))
-  (:printer ext-xmm-reg/mem ((prefix #x66) (op #x7e))
-            '(:name :tab reg/mem ", " reg))
-  (:printer ext-rex-xmm-reg/mem ((prefix #x66) (op #x7e))
-            '(:name :tab reg/mem ", " reg))
+  (:printer-list
+   (append
+    (sse-inst-printer-list 'xmm-reg/mem #x66 #x6e)
+    (sse-inst-printer-list 'xmm-reg/mem #x66 #x7e
+                           :printer '(:name :tab reg/mem ", " reg))))
   (:emitter
    (cond ((xmm-register-p dst)
           (emit-sse-inst segment dst src #x66 #x6e))
           (aver (xmm-register-p src))
           (emit-sse-inst segment src dst #x66 #x7e)))))
 
+(define-instruction pinsrw (segment dst src imm)
+  (:printer-list
+   (sse-inst-printer-list
+    'xmm-reg/mem #x66 #xc4
+    :more-fields '((imm nil :type imm-byte))
+    :printer '(:name :tab reg ", " reg/mem ", " imm)))
+  (:emitter
+   (aver (xmm-register-p dst))
+   (let ((src-size (operand-size src)))
+     (aver (or (not (register-p src))
+               (eq src-size :qword) (eq src-size :dword)))
+     (emit-sse-inst segment dst src #x66 #xc4
+                    :operand-size (if (register-p src) src-size :do-not-set)
+                    :remaining-bytes 1))
+   (emit-byte segment imm)))
+
+(define-instruction pextrw (segment dst src imm)
+  (:printer-list
+   (sse-inst-printer-list
+    'reg-xmm/mem #x66 #xc5
+    :more-fields '((imm nil :type imm-byte))
+    :printer '(:name :tab reg ", " reg/mem ", " imm)))
+  (:emitter
+   (aver (xmm-register-p src))
+   (aver (register-p dst))
+   (let ((dst-size (operand-size dst)))
+     (aver (or (eq dst-size :qword) (eq dst-size :dword)))
+     (emit-sse-inst segment dst src #x66 #xc5
+                    :operand-size dst-size
+                    :remaining-bytes 1))
+   (emit-byte segment imm)))
+
 (macrolet ((define-integer-source-sse-inst (name prefix opcode &key mem-only)
              `(define-instruction ,name (segment dst src)
-                ,@(if prefix
-                      `((:printer ext-xmm-reg/mem ((prefix ,prefix) (op ,opcode)))
-                        (:printer ext-rex-xmm-reg/mem ((prefix ,prefix) (op ,opcode))))
-                      `((:printer xmm-reg/mem ((op ,opcode)))
-                        (:printer rex-xmm-reg/mem ((op ,opcode)))))
-
+                (:printer-list
+                 ',(sse-inst-printer-list 'xmm-reg/mem prefix opcode))
                 (:emitter
                  (aver (xmm-register-p dst))
                  ,(when mem-only
 
 (macrolet ((define-gpr-destination-sse-inst (name prefix opcode &key reg-only)
              `(define-instruction ,name (segment dst src)
-                ,@(if prefix
-                      `((:printer ext-reg-xmm/mem ((prefix ,prefix) (op ,opcode)))
-                        (:printer ext-rex-reg-xmm/mem ((prefix ,prefix) (op ,opcode))))
-                      `((:printer reg-xmm/mem ((op ,opcode)))
-                        (:printer rex-reg-xmm/mem ((op ,opcode)))))
+                (:printer-list
+                 ',(sse-inst-printer-list 'reg-xmm/mem prefix opcode))
                 (:emitter
                  (aver (register-p dst))
                  ,(when reg-only
    (aver (eq (operand-size src) :byte))
    (maybe-emit-rex-for-ea segment src nil)
    (emit-byte segment #x0f)
-   (emit-byte segment #x18)
+   (emit-byte segment #xae)
    (emit-ea segment src 7)))
 
 (macrolet ((define-fence-instruction (name last-byte)