X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcompiler%2Fx86-64%2Finsts.lisp;h=614071106707fade9d608d8cbd5b65ccdbacbb6f;hb=b66385e2031fc2cac17dd129df0af400beb48a22;hp=c1d3910c2bd622ae23c0cbc5215161d812eeaf36;hpb=842dd588e08f08677fa245734d392196e5410c24;p=sbcl.git diff --git a/src/compiler/x86-64/insts.lisp b/src/compiler/x86-64/insts.lisp index c1d3910..6140711 100644 --- a/src/compiler/x86-64/insts.lisp +++ b/src/compiler/x86-64/insts.lisp @@ -257,6 +257,14 @@ (sb!disassem:dstate-put-inst-prop dstate 'operand-size-8)) value) +;;; This prefilter is used solely for its side effect, namely to put +;;; the property OPERAND-SIZE-16 into the DSTATE. +(defun prefilter-x66 (value dstate) + (declare (type (eql #x66) value) + (ignore value) + (type sb!disassem:disassem-state dstate)) + (sb!disassem:dstate-put-inst-prop dstate 'operand-size-16)) + ;;; A register field that can be extended by REX.R. (defun prefilter-reg-r (value dstate) (declare (type reg value) @@ -360,6 +368,10 @@ (princ (schar (symbol-name (inst-operand-size dstate)) 0) stream))) +;;; Used to capture the effect of the #x66 operand size override prefix. +(sb!disassem:define-arg-type x66 + :prefilter #'prefilter-x66) + (sb!disassem:define-arg-type displacement :sign-extend t :use-label #'offset-next @@ -479,20 +491,6 @@ :printer #'print-sized-xmmreg/mem) -;;; added by jrd -(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute) -(defun print-fp-reg (value stream dstate) - (declare (ignore dstate)) - (format stream "FR~D" value)) -(defun prefilter-fp-reg (value dstate) - ;; just return it - (declare (ignore dstate)) - value) -) ; EVAL-WHEN -(sb!disassem:define-arg-type fp-reg - :prefilter #'prefilter-fp-reg - :printer #'print-fp-reg) - (eval-when (:compile-toplevel :load-toplevel :execute) (defparameter *conditions* '((:o . 0) @@ -624,18 +622,6 @@ :default-printer '(:name :tab reg)) (reg :type 'reg-b-default-qword)) -(sb!disassem:define-instruction-format (modrm-reg-no-width 24 - :default-printer '(:name :tab reg)) - (rex :field (byte 4 4) :value #b0100) - (wrxb :field (byte 4 0) :type 'wrxb) - (ff :field (byte 8 8) :value #b11111111) - (mod :field (byte 2 22)) - (modrm-reg :field (byte 3 19)) - (reg :field (byte 3 16) :type 'reg-b) - ;; optional fields - (accum :type 'accum) - (imm)) - ;;; Adds a width field to reg-no-width. Note that we can't use ;;; :INCLUDE 'REG-NO-WIDTH here to save typing because that would put ;;; the WIDTH field last, but the prefilter for WIDTH must run before @@ -707,6 +693,34 @@ (op :field (byte 6 10)) (dir :field (byte 1 9))) +(sb!disassem:define-instruction-format (x66-reg-reg/mem-dir 24 + :default-printer + `(:name + :tab + ,(swap-if 'dir 'reg/mem ", " 'reg))) + (x66 :field (byte 8 0) :type 'x66 :value #x66) + (op :field (byte 6 10)) + (dir :field (byte 1 9)) + (width :field (byte 1 8) :type 'width) + (reg/mem :fields (list (byte 2 22) (byte 3 16)) + :type 'reg/mem) + (reg :field (byte 3 19) :type 'reg)) + +(sb!disassem:define-instruction-format (x66-rex-reg-reg/mem-dir 32 + :default-printer + `(:name + :tab + ,(swap-if 'dir 'reg/mem ", " 'reg))) + (x66 :field (byte 8 0) :type 'x66 :value #x66) + (rex :field (byte 4 12) :value #b0100) + (wrxb :field (byte 4 8) :type 'wrxb) + (op :field (byte 6 18)) + (dir :field (byte 1 17)) + (width :field (byte 1 16) :type 'width) + (reg/mem :fields (list (byte 2 30) (byte 3 24)) + :type 'reg/mem) + (reg :field (byte 3 27) :type 'reg)) + ;;; Same as reg-reg/mem, but uses the reg field as a second op code. (sb!disassem:define-instruction-format (reg/mem 16 :default-printer '(:name :tab reg/mem)) @@ -953,61 +967,6 @@ :type 'sized-xmmreg/mem) (reg :field (byte 3 35) :type 'reg)) -;;;; This section was added by jrd, for fp instructions. - -;;; regular fp inst to/from registers/memory -(sb!disassem:define-instruction-format (floating-point 16 - :default-printer - `(:name :tab reg/mem)) - (prefix :field (byte 5 3) :value #b11011) - (op :fields (list (byte 3 0) (byte 3 11))) - (reg/mem :fields (list (byte 2 14) (byte 3 8)) :type 'reg/mem)) - -;;; fp insn to/from fp reg -(sb!disassem:define-instruction-format (floating-point-fp 16 - :default-printer `(:name :tab fp-reg)) - (prefix :field (byte 5 3) :value #b11011) - (suffix :field (byte 2 14) :value #b11) - (op :fields (list (byte 3 0) (byte 3 11))) - (fp-reg :field (byte 3 8) :type 'fp-reg)) - -;;; fp insn to/from fp reg, with the reversed source/destination flag. -(sb!disassem:define-instruction-format - (floating-point-fp-d 16 - :default-printer `(:name :tab ,(swap-if 'd "ST0" ", " 'fp-reg))) - (prefix :field (byte 5 3) :value #b11011) - (suffix :field (byte 2 14) :value #b11) - (op :fields (list (byte 2 0) (byte 3 11))) - (d :field (byte 1 2)) - (fp-reg :field (byte 3 8) :type 'fp-reg)) - - -;;; (added by (?) pfw) -;;; fp no operand isns -(sb!disassem:define-instruction-format (floating-point-no 16 - :default-printer '(:name)) - (prefix :field (byte 8 0) :value #b11011001) - (suffix :field (byte 3 13) :value #b111) - (op :field (byte 5 8))) - -(sb!disassem:define-instruction-format (floating-point-3 16 - :default-printer '(:name)) - (prefix :field (byte 5 3) :value #b11011) - (suffix :field (byte 2 14) :value #b11) - (op :fields (list (byte 3 0) (byte 6 8)))) - -(sb!disassem:define-instruction-format (floating-point-5 16 - :default-printer '(:name)) - (prefix :field (byte 8 0) :value #b11011011) - (suffix :field (byte 3 13) :value #b111) - (op :field (byte 5 8))) - -(sb!disassem:define-instruction-format (floating-point-st 16 - :default-printer '(:name)) - (prefix :field (byte 8 0) :value #b11011111) - (suffix :field (byte 3 13) :value #b111) - (op :field (byte 5 8))) - (sb!disassem:define-instruction-format (string-op 8 :include 'simple :default-printer '(:name width))) @@ -1264,7 +1223,7 @@ (stack ;; Convert stack tns into an index off RBP. (let ((disp (- (* (1+ (tn-offset thing)) n-word-bytes)))) - (cond ((< -128 disp 127) + (cond ((<= -128 disp 127) (emit-mod-reg-r/m-byte segment #b01 reg #b101) (emit-byte segment disp)) (t @@ -1323,14 +1282,6 @@ (emit-sib-byte segment 0 #b100 #b101) (emit-absolute-fixup segment thing)))))) -;;; like the above, but for fp-instructions--jrd -(defun emit-fp-op (segment thing op) - (if (fp-reg-tn-p thing) - (emit-byte segment (dpb op (byte 3 3) (dpb (tn-offset thing) - (byte 3 0) - #b11000000))) - (emit-ea segment thing op))) - (defun byte-reg-p (thing) (and (tn-p thing) (eq (sb-name (sc-sb (tn-sc thing))) 'registers) @@ -1592,8 +1543,9 @@ (emit-mod-reg-r/m-byte segment #b11 #b000 (reg-tn-encoding dst)) (emit-signed-dword segment src)) - ((typep src `(integer ,(- (expt 2 64) (expt 2 31)) - (,(expt 2 64)))) + ((<= (- (expt 2 64) (expt 2 31)) + src + (1- (expt 2 64))) ;; This triggers on positive integers of 64 bits length ;; with the most significant 33 bits being 1. We use the ;; same encoding as in the previous clause. @@ -1619,6 +1571,8 @@ ;; register to/from register/memory (:printer reg-reg/mem-dir ((op #b100010))) (:printer rex-reg-reg/mem-dir ((op #b100010))) + (:printer x66-reg-reg/mem-dir ((op #b100010))) + (:printer x66-rex-reg-reg/mem-dir ((op #b100010))) ;; immediate to register/memory (:printer reg/mem-imm ((op '(#b1100011 #b000)))) (:printer rex-reg/mem-imm ((op '(#b1100011 #b000)))) @@ -2014,38 +1968,27 @@ (:printer-list (arith-inst-printer-list #b111)) (:emitter (emit-random-arith-inst "CMP" segment dst src #b111 t))) +;;; The one-byte encodings for INC and DEC are used as REX prefixes +;;; in 64-bit mode so we always use the two-byte form. (define-instruction inc (segment dst) - ;; Register - (:printer modrm-reg-no-width ((modrm-reg #b000))) - ;; Register/Memory - ;; (:printer rex-reg/mem ((op '(#b11111111 #b001)))) (:printer reg/mem ((op '(#b1111111 #b000)))) + (:printer rex-reg/mem ((op '(#b1111111 #b000)))) (:emitter (let ((size (operand-size dst))) (maybe-emit-operand-size-prefix segment size) - (cond #+nil ; these opcodes become REX prefixes in x86-64 - ((and (not (eq size :byte)) (register-p dst)) - (emit-byte-with-reg segment #b01000 (reg-tn-encoding dst))) - (t - (maybe-emit-rex-for-ea segment dst nil) - (emit-byte segment (if (eq size :byte) #b11111110 #b11111111)) - (emit-ea segment dst #b000)))))) + (maybe-emit-rex-for-ea segment dst nil) + (emit-byte segment (if (eq size :byte) #b11111110 #b11111111)) + (emit-ea segment dst #b000)))) (define-instruction dec (segment dst) - ;; Register. - (:printer modrm-reg-no-width ((modrm-reg #b001))) - ;; Register/Memory (:printer reg/mem ((op '(#b1111111 #b001)))) + (:printer rex-reg/mem ((op '(#b1111111 #b001)))) (:emitter (let ((size (operand-size dst))) (maybe-emit-operand-size-prefix segment size) - (cond #+nil - ((and (not (eq size :byte)) (register-p dst)) - (emit-byte-with-reg segment #b01001 (reg-tn-encoding dst))) - (t - (maybe-emit-rex-for-ea segment dst nil) - (emit-byte segment (if (eq size :byte) #b11111110 #b11111111)) - (emit-ea segment dst #b001)))))) + (maybe-emit-rex-for-ea segment dst nil) + (emit-byte segment (if (eq size :byte) #b11111110 #b11111111)) + (emit-ea segment dst #b001)))) (define-instruction neg (segment dst) (:printer reg/mem ((op '(#b1111011 #b011)))) @@ -2766,7 +2709,11 @@ (#.halt-trap (nt "halt trap")) (#.fun-end-breakpoint-trap - (nt "function end breakpoint trap"))))) + (nt "function end breakpoint trap")) + (#.single-step-around-trap + (nt "single-step trap (around)")) + (#.single-step-before-trap + (nt "single-step trap (before)"))))) (define-instruction break (segment code) (:declare (type (unsigned-byte 8) code)) @@ -2847,700 +2794,6 @@ (:emitter (emit-header-data segment return-pc-header-widetag))) -;;;; fp instructions -;;;; -;;;; Note: We treat the single-precision and double-precision variants -;;;; as separate instructions. - -;;; Load single to st(0). -(define-instruction fld (segment source) - (:printer floating-point ((op '(#b001 #b000)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011001) - (emit-fp-op segment source #b000))) - -;;; Load double to st(0). -(define-instruction fldd (segment source) - (:printer floating-point ((op '(#b101 #b000)))) - (:printer floating-point-fp ((op '(#b001 #b000)))) - (:emitter - (if (fp-reg-tn-p source) - (emit-byte segment #b11011001) - (progn - (maybe-emit-rex-for-ea segment source nil) - (emit-byte segment #b11011101))) - (emit-fp-op segment source #b000))) - -;;; Load long to st(0). -(define-instruction fldl (segment source) - (:printer floating-point ((op '(#b011 #b101)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011011) - (emit-fp-op segment source #b101))) - -;;; Store single from st(0). -(define-instruction fst (segment dest) - (:printer floating-point ((op '(#b001 #b010)))) - (:emitter - (cond ((fp-reg-tn-p dest) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b010)) - (t - (maybe-emit-rex-for-ea segment dest nil) - (emit-byte segment #b11011001) - (emit-fp-op segment dest #b010))))) - -;;; Store double from st(0). -(define-instruction fstd (segment dest) - (:printer floating-point ((op '(#b101 #b010)))) - (:printer floating-point-fp ((op '(#b101 #b010)))) - (:emitter - (cond ((fp-reg-tn-p dest) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b010)) - (t - (maybe-emit-rex-for-ea segment dest nil) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b010))))) - -;;; Arithmetic ops are all done with at least one operand at top of -;;; stack. The other operand is is another register or a 32/64 bit -;;; memory loc. - -;;; dtc: I've tried to follow the Intel ASM386 conventions, but note -;;; that these conflict with the Gdb conventions for binops. To reduce -;;; the confusion I've added comments showing the mathamatical -;;; operation and the two syntaxes. By the ASM386 convention the -;;; instruction syntax is: -;;; -;;; Fop Source -;;; or Fop Destination, Source -;;; -;;; If only one operand is given then it is the source and the -;;; destination is ST(0). There are reversed forms of the fsub and -;;; fdiv instructions inducated by an 'R' suffix. -;;; -;;; The mathematical operation for the non-reverse form is always: -;;; destination = destination op source -;;; -;;; For the reversed form it is: -;;; destination = source op destination -;;; -;;; The instructions below only accept one operand at present which is -;;; usually the source. I've hack in extra instructions to implement -;;; the fops with a ST(i) destination, these have a -sti suffix and -;;; the operand is the destination with the source being ST(0). - -;;; Add single: -;;; st(0) = st(0) + memory or st(i). -(define-instruction fadd (segment source) - (:printer floating-point ((op '(#b000 #b000)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment source #b000))) - -;;; Add double: -;;; st(0) = st(0) + memory or st(i). -(define-instruction faddd (segment source) - (:printer floating-point ((op '(#b100 #b000)))) - (:printer floating-point-fp ((op '(#b000 #b000)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (if (fp-reg-tn-p source) - (emit-byte segment #b11011000) - (emit-byte segment #b11011100)) - (emit-fp-op segment source #b000))) - -;;; Add double destination st(i): -;;; st(i) = st(0) + st(i). -(define-instruction fadd-sti (segment destination) - (:printer floating-point-fp ((op '(#b100 #b000)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011100) - (emit-fp-op segment destination #b000))) -;;; with pop -(define-instruction faddp-sti (segment destination) - (:printer floating-point-fp ((op '(#b110 #b000)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011110) - (emit-fp-op segment destination #b000))) - -;;; Subtract single: -;;; st(0) = st(0) - memory or st(i). -(define-instruction fsub (segment source) - (:printer floating-point ((op '(#b000 #b100)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment source #b100))) - -;;; Subtract single, reverse: -;;; st(0) = memory or st(i) - st(0). -(define-instruction fsubr (segment source) - (:printer floating-point ((op '(#b000 #b101)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment source #b101))) - -;;; Subtract double: -;;; st(0) = st(0) - memory or st(i). -(define-instruction fsubd (segment source) - (:printer floating-point ((op '(#b100 #b100)))) - (:printer floating-point-fp ((op '(#b000 #b100)))) - (:emitter - (if (fp-reg-tn-p source) - (emit-byte segment #b11011000) - (progn - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011100))) - (emit-fp-op segment source #b100))) - -;;; Subtract double, reverse: -;;; st(0) = memory or st(i) - st(0). -(define-instruction fsubrd (segment source) - (:printer floating-point ((op '(#b100 #b101)))) - (:printer floating-point-fp ((op '(#b000 #b101)))) - (:emitter - (if (fp-reg-tn-p source) - (emit-byte segment #b11011000) - (progn - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011100))) - (emit-fp-op segment source #b101))) - -;;; Subtract double, destination st(i): -;;; st(i) = st(i) - st(0). -;;; -;;; ASM386 syntax: FSUB ST(i), ST -;;; Gdb syntax: fsubr %st,%st(i) -(define-instruction fsub-sti (segment destination) - (:printer floating-point-fp ((op '(#b100 #b101)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011100) - (emit-fp-op segment destination #b101))) -;;; with a pop -(define-instruction fsubp-sti (segment destination) - (:printer floating-point-fp ((op '(#b110 #b101)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011110) - (emit-fp-op segment destination #b101))) - -;;; Subtract double, reverse, destination st(i): -;;; st(i) = st(0) - st(i). -;;; -;;; ASM386 syntax: FSUBR ST(i), ST -;;; Gdb syntax: fsub %st,%st(i) -(define-instruction fsubr-sti (segment destination) - (:printer floating-point-fp ((op '(#b100 #b100)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011100) - (emit-fp-op segment destination #b100))) -;;; with a pop -(define-instruction fsubrp-sti (segment destination) - (:printer floating-point-fp ((op '(#b110 #b100)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011110) - (emit-fp-op segment destination #b100))) - -;;; Multiply single: -;;; st(0) = st(0) * memory or st(i). -(define-instruction fmul (segment source) - (:printer floating-point ((op '(#b000 #b001)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment source #b001))) - -;;; Multiply double: -;;; st(0) = st(0) * memory or st(i). -(define-instruction fmuld (segment source) - (:printer floating-point ((op '(#b100 #b001)))) - (:printer floating-point-fp ((op '(#b000 #b001)))) - (:emitter - (if (fp-reg-tn-p source) - (emit-byte segment #b11011000) - (progn - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011100))) - (emit-fp-op segment source #b001))) - -;;; Multiply double, destination st(i): -;;; st(i) = st(i) * st(0). -(define-instruction fmul-sti (segment destination) - (:printer floating-point-fp ((op '(#b100 #b001)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011100) - (emit-fp-op segment destination #b001))) - -;;; Divide single: -;;; st(0) = st(0) / memory or st(i). -(define-instruction fdiv (segment source) - (:printer floating-point ((op '(#b000 #b110)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment source #b110))) - -;;; Divide single, reverse: -;;; st(0) = memory or st(i) / st(0). -(define-instruction fdivr (segment source) - (:printer floating-point ((op '(#b000 #b111)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment source #b111))) - -;;; Divide double: -;;; st(0) = st(0) / memory or st(i). -(define-instruction fdivd (segment source) - (:printer floating-point ((op '(#b100 #b110)))) - (:printer floating-point-fp ((op '(#b000 #b110)))) - (:emitter - (if (fp-reg-tn-p source) - (emit-byte segment #b11011000) - (progn - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011100))) - (emit-fp-op segment source #b110))) - -;;; Divide double, reverse: -;;; st(0) = memory or st(i) / st(0). -(define-instruction fdivrd (segment source) - (:printer floating-point ((op '(#b100 #b111)))) - (:printer floating-point-fp ((op '(#b000 #b111)))) - (:emitter - (if (fp-reg-tn-p source) - (emit-byte segment #b11011000) - (progn - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011100))) - (emit-fp-op segment source #b111))) - -;;; Divide double, destination st(i): -;;; st(i) = st(i) / st(0). -;;; -;;; ASM386 syntax: FDIV ST(i), ST -;;; Gdb syntax: fdivr %st,%st(i) -(define-instruction fdiv-sti (segment destination) - (:printer floating-point-fp ((op '(#b100 #b111)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011100) - (emit-fp-op segment destination #b111))) - -;;; Divide double, reverse, destination st(i): -;;; st(i) = st(0) / st(i). -;;; -;;; ASM386 syntax: FDIVR ST(i), ST -;;; Gdb syntax: fdiv %st,%st(i) -(define-instruction fdivr-sti (segment destination) - (:printer floating-point-fp ((op '(#b100 #b110)))) - (:emitter - (aver (fp-reg-tn-p destination)) - (emit-byte segment #b11011100) - (emit-fp-op segment destination #b110))) - -;;; Exchange fr0 with fr(n). (There is no double precision variant.) -(define-instruction fxch (segment source) - (:printer floating-point-fp ((op '(#b001 #b001)))) - (:emitter - (unless (and (tn-p source) - (eq (sb-name (sc-sb (tn-sc source))) 'float-registers)) - (cl:break)) - (emit-byte segment #b11011001) - (emit-fp-op segment source #b001))) - -;;; Push 32-bit integer to st0. -(define-instruction fild (segment source) - (:printer floating-point ((op '(#b011 #b000)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011011) - (emit-fp-op segment source #b000))) - -;;; Push 64-bit integer to st0. -(define-instruction fildl (segment source) - (:printer floating-point ((op '(#b111 #b101)))) - (:emitter - (and (not (fp-reg-tn-p source)) - (maybe-emit-rex-for-ea segment source nil)) - (emit-byte segment #b11011111) - (emit-fp-op segment source #b101))) - -;;; Store 32-bit integer. -(define-instruction fist (segment dest) - (:printer floating-point ((op '(#b011 #b010)))) - (:emitter - (and (not (fp-reg-tn-p dest)) - (maybe-emit-rex-for-ea segment dest nil)) - (emit-byte segment #b11011011) - (emit-fp-op segment dest #b010))) - -;;; Store and pop 32-bit integer. -(define-instruction fistp (segment dest) - (:printer floating-point ((op '(#b011 #b011)))) - (:emitter - (and (not (fp-reg-tn-p dest)) - (maybe-emit-rex-for-ea segment dest nil)) - (emit-byte segment #b11011011) - (emit-fp-op segment dest #b011))) - -;;; Store and pop 64-bit integer. -(define-instruction fistpl (segment dest) - (:printer floating-point ((op '(#b111 #b111)))) - (:emitter - (and (not (fp-reg-tn-p dest)) - (maybe-emit-rex-for-ea segment dest nil)) - (emit-byte segment #b11011111) - (emit-fp-op segment dest #b111))) - -;;; Store single from st(0) and pop. -(define-instruction fstp (segment dest) - (:printer floating-point ((op '(#b001 #b011)))) - (:emitter - (cond ((fp-reg-tn-p dest) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b011)) - (t - (maybe-emit-rex-for-ea segment dest nil) - (emit-byte segment #b11011001) - (emit-fp-op segment dest #b011))))) - -;;; Store double from st(0) and pop. -(define-instruction fstpd (segment dest) - (:printer floating-point ((op '(#b101 #b011)))) - (:printer floating-point-fp ((op '(#b101 #b011)))) - (:emitter - (cond ((fp-reg-tn-p dest) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b011)) - (t - (maybe-emit-rex-for-ea segment dest nil) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b011))))) - -;;; Store long from st(0) and pop. -(define-instruction fstpl (segment dest) - (:printer floating-point ((op '(#b011 #b111)))) - (:emitter - (and (not (fp-reg-tn-p dest)) - (maybe-emit-rex-for-ea segment dest nil)) - (emit-byte segment #b11011011) - (emit-fp-op segment dest #b111))) - -;;; Decrement stack-top pointer. -(define-instruction fdecstp (segment) - (:printer floating-point-no ((op #b10110))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110110))) - -;;; Increment stack-top pointer. -(define-instruction fincstp (segment) - (:printer floating-point-no ((op #b10111))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110111))) - -;;; Free fp register. -(define-instruction ffree (segment dest) - (:printer floating-point-fp ((op '(#b101 #b000)))) - (:emitter - (and (not (fp-reg-tn-p dest)) - (maybe-emit-rex-for-ea segment dest nil)) - (emit-byte segment #b11011101) - (emit-fp-op segment dest #b000))) - -(define-instruction fabs (segment) - (:printer floating-point-no ((op #b00001))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11100001))) - -(define-instruction fchs (segment) - (:printer floating-point-no ((op #b00000))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11100000))) - -(define-instruction frndint(segment) - (:printer floating-point-no ((op #b11100))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111100))) - -;;; Initialize NPX. -(define-instruction fninit(segment) - (:printer floating-point-5 ((op #b00011))) - (:emitter - (emit-byte segment #b11011011) - (emit-byte segment #b11100011))) - -;;; Store Status Word to AX. -(define-instruction fnstsw(segment) - (:printer floating-point-st ((op #b00000))) - (:emitter - (emit-byte segment #b11011111) - (emit-byte segment #b11100000))) - -;;; Load Control Word. -;;; -;;; src must be a memory location -(define-instruction fldcw(segment src) - (:printer floating-point ((op '(#b001 #b101)))) - (:emitter - (and (not (fp-reg-tn-p src)) - (maybe-emit-rex-for-ea segment src nil)) - (emit-byte segment #b11011001) - (emit-fp-op segment src #b101))) - -;;; Store Control Word. -(define-instruction fnstcw(segment dst) - (:printer floating-point ((op '(#b001 #b111)))) - (:emitter - (and (not (fp-reg-tn-p dst)) - (maybe-emit-rex-for-ea segment dst nil)) - (emit-byte segment #b11011001) - (emit-fp-op segment dst #b111))) - -;;; Store FP Environment. -(define-instruction fstenv(segment dst) - (:printer floating-point ((op '(#b001 #b110)))) - (:emitter - (and (not (fp-reg-tn-p dst)) - (maybe-emit-rex-for-ea segment dst nil)) - (emit-byte segment #b11011001) - (emit-fp-op segment dst #b110))) - -;;; Restore FP Environment. -(define-instruction fldenv(segment src) - (:printer floating-point ((op '(#b001 #b100)))) - (:emitter - (and (not (fp-reg-tn-p src)) - (maybe-emit-rex-for-ea segment src nil)) - (emit-byte segment #b11011001) - (emit-fp-op segment src #b100))) - -;;; Save FP State. -(define-instruction fsave(segment dst) - (:printer floating-point ((op '(#b101 #b110)))) - (:emitter - (and (not (fp-reg-tn-p dst)) - (maybe-emit-rex-for-ea segment dst nil)) - (emit-byte segment #b11011101) - (emit-fp-op segment dst #b110))) - -;;; Restore FP State. -(define-instruction frstor(segment src) - (:printer floating-point ((op '(#b101 #b100)))) - (:emitter - (and (not (fp-reg-tn-p src)) - (maybe-emit-rex-for-ea segment src nil)) - (emit-byte segment #b11011101) - (emit-fp-op segment src #b100))) - -;;; Clear exceptions. -(define-instruction fnclex(segment) - (:printer floating-point-5 ((op #b00010))) - (:emitter - (emit-byte segment #b11011011) - (emit-byte segment #b11100010))) - -;;; comparison -(define-instruction fcom (segment src) - (:printer floating-point ((op '(#b000 #b010)))) - (:emitter - (and (not (fp-reg-tn-p src)) - (maybe-emit-rex-for-ea segment src nil)) - (emit-byte segment #b11011000) - (emit-fp-op segment src #b010))) - -(define-instruction fcomd (segment src) - (:printer floating-point ((op '(#b100 #b010)))) - (:printer floating-point-fp ((op '(#b000 #b010)))) - (:emitter - (if (fp-reg-tn-p src) - (emit-byte segment #b11011000) - (progn - (maybe-emit-rex-for-ea segment src nil) - (emit-byte segment #b11011100))) - (emit-fp-op segment src #b010))) - -;;; Compare ST1 to ST0, popping the stack twice. -(define-instruction fcompp (segment) - (:printer floating-point-3 ((op '(#b110 #b011001)))) - (:emitter - (emit-byte segment #b11011110) - (emit-byte segment #b11011001))) - -;;; unordered comparison -(define-instruction fucom (segment src) - (:printer floating-point-fp ((op '(#b101 #b100)))) - (:emitter - (aver (fp-reg-tn-p src)) - (emit-byte segment #b11011101) - (emit-fp-op segment src #b100))) - -(define-instruction ftst (segment) - (:printer floating-point-no ((op #b00100))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11100100))) - -;;;; 80387 specials - -(define-instruction fsqrt(segment) - (:printer floating-point-no ((op #b11010))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111010))) - -(define-instruction fscale(segment) - (:printer floating-point-no ((op #b11101))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111101))) - -(define-instruction fxtract(segment) - (:printer floating-point-no ((op #b10100))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110100))) - -(define-instruction fsin(segment) - (:printer floating-point-no ((op #b11110))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111110))) - -(define-instruction fcos(segment) - (:printer floating-point-no ((op #b11111))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111111))) - -(define-instruction fprem1(segment) - (:printer floating-point-no ((op #b10101))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110101))) - -(define-instruction fprem(segment) - (:printer floating-point-no ((op #b11000))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111000))) - -(define-instruction fxam (segment) - (:printer floating-point-no ((op #b00101))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11100101))) - -;;; These do push/pop to stack and need special handling -;;; in any VOPs that use them. See the book. - -;;; st0 <- st1*log2(st0) -(define-instruction fyl2x(segment) ; pops stack - (:printer floating-point-no ((op #b10001))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110001))) - -(define-instruction fyl2xp1(segment) - (:printer floating-point-no ((op #b11001))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11111001))) - -(define-instruction f2xm1(segment) - (:printer floating-point-no ((op #b10000))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110000))) - -(define-instruction fptan(segment) ; st(0) <- 1; st(1) <- tan - (:printer floating-point-no ((op #b10010))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110010))) - -(define-instruction fpatan(segment) ; POPS STACK - (:printer floating-point-no ((op #b10011))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11110011))) - -;;;; loading constants - -(define-instruction fldz(segment) - (:printer floating-point-no ((op #b01110))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101110))) - -(define-instruction fld1(segment) - (:printer floating-point-no ((op #b01000))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101000))) - -(define-instruction fldpi(segment) - (:printer floating-point-no ((op #b01011))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101011))) - -(define-instruction fldl2t(segment) - (:printer floating-point-no ((op #b01001))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101001))) - -(define-instruction fldl2e(segment) - (:printer floating-point-no ((op #b01010))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101010))) - -(define-instruction fldlg2(segment) - (:printer floating-point-no ((op #b01100))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101100))) - -(define-instruction fldln2(segment) - (:printer floating-point-no ((op #b01101))) - (:emitter - (emit-byte segment #b11011001) - (emit-byte segment #b11101101))) - ;;;; Instructions required to do floating point operations using SSE (defun emit-sse-inst (segment dst src prefix opcode &key operand-size)