; X86ISA Library

; Note: The license below is based on the template at:
; http://opensource.org/licenses/BSD-3-Clause

; Copyright (C) 2015, May - August 2023, Regents of the University of Texas
; Copyright (C) 2025, Kestrel Technology, LLC
; Copyright (C) August 2023 - May 2024, Yahya Sohail
; Copyright (C) May 2024 - August 2024, Intel Corporation
; All rights reserved.

; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are
; met:

; o Redistributions of source code must retain the above copyright
;   notice, this list of conditions and the following disclaimer.

; o Redistributions in binary form must reproduce the above copyright
;   notice, this list of conditions and the following disclaimer in the
;   documentation and/or other materials provided with the distribution.

; o Neither the name of the copyright holders nor the names of its
;   contributors may be used to endorse or promote products derived
;   from this software without specific prior written permission.

; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
; HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

; Authors:
; Shilpi Goel         <shigoel@cs.utexas.edu>
; Cuong Chau          <ckcuong@cs.utexas.edu>
; Alessandro Coglio   <www.alessandrocoglio.info>
; Yahya Sohail        <yahya.sohail@intel.com>

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(in-package "X86ISA")

(include-book "../decoding-and-spec-utils")

(local (include-book "centaur/bitops/ihs-extensions" :dir :system))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; VMOVUPS, VMOVUPD, VMOVDQU

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def-inst x86-vmovups/vmovupd/vmovdqu-vex-a

  :parents (two-byte-opcodes fp-opcodes)

  :short "VMOVUPS, VMOVUPD, VMMOVDQU:
          move unaligned packed single/double-precision floating-point values
          and unaligned packed integer values
          (VEX encoding, Op/En A)."

  :long
  "<p>
   These instructions are listed under MOVUPS, MOVUPD, and MOVDQU
   in Intel Manual Volume 2 (Jun 2025).
   </p>
   <p>
   This semantic function covers the two VEX-encoded variants
   (of each of VMOVUPS, MOVUPD, and VMOVDQU)
   that move from register or memory to register (i.e. Op/En A).
   </p>
   <p>
   The three instructions behave in the same way at the ISA level,
   but they have different encodings,
   and are used with different types at the assembly and higher levels;
   there may also be performance differences at the level lower than the ISA.
   </p>
   <code>
   VMOVUPS xmm1, xmm2/m128
   VMOVUPS ymm1, ymm2/m256
   </code>
   <code>
   VMOVUPD xmm1, xmm2/m128
   VMOVUPD ymm1, ymm2/m256
   </code>
   <code>
   VMOVDQU xmm1, xmm2/m128
   VMOVDQU ymm1, ymm2/m256
   </code>"

  :vex t

  :modr/m t

  :guard (vex-prefixes-byte0-p vex-prefixes)

  :returns (x86 x86p :hyp (x86p x86))

  :body

  (b* ((p2 (prefixes->seg prefixes))
       (p4? (eql #.*addr-size-override* (prefixes->adr prefixes)))
       (seg-reg (select-segment-register proc-mode p2 p4? mod r/m sib x86))
       (rex-byte (rex-byte-from-vex-prefixes vex-prefixes))

       ;; The operand size is determined by VEX.L, regardless of processor mode.
       ((the (integer 16 32) operand-size)
        (if (equal (vex->l vex-prefixes) 1)
            32
          16))

       ;; Read the value from register or memory.
       ;; There is no alignment check, since it is an 'unaligned' move.
       ;; Also see Intel Manual Volume 1 (Jun 2025), Table 14-23.
       (inst-ac? nil)
       ((mv flg
            (the (unsigned-byte 256) reg/mem-value)
            (the (integer 0 4) increment-rip-by)
            & ; address of the operand
            x86)
        (x86-operand-from-modr/m-and-sib-bytes proc-mode
                                               (if (= operand-size 16)
                                                   #.*vex-xmm-access*
                                                 #.*ymm-access*)
                                               operand-size
                                               inst-ac?
                                               nil ; not a memory operand
                                               seg-reg
                                               p4?
                                               temp-rip
                                               rex-byte
                                               r/m
                                               mod
                                               sib
                                               0 ; no immediate operand
                                               x86))
       ((when flg)
        (!!ms-fresh :x86-operand-from-modr/m-and-sib-bytes flg))

       ;; Increment the instruction pointer in the temp-rip variable.
       ((mv flg (the (signed-byte #.*max-linear-address-size*) temp-rip))
        (add-to-*ip proc-mode temp-rip increment-rip-by x86))
       ((when flg) (!!ms-fresh :rip-increment-error flg))

       ;; Ensure the instruction is not too long.
       (badlength? (check-instruction-length start-rip temp-rip 0))
       ((when badlength?)
        (!!fault-fresh :gp 0 :instruction-length badlength?)) ;; #GP(0)

       ;; Update the destination register.
       ;; Note that this operation zeros the upper bits,
       ;; as required in the pseudocode of the instruction.
       ;; In our model, MAXVL is 512,
       ;; because our model of the x86 state has just the ZMM registers,
       ;; whose lower bits are aliased to YMM and XMM.
       (x86 (!zmmi-size operand-size
                        (reg-index reg rex-byte #.*r*)
                        reg/mem-value
                        x86
                        :regtype (if (= operand-size 16)
                                     #.*vex-xmm-access*
                                   #.*ymm-access*)))

       ;; Update the instruction pointer in the state.
       (x86 (write-*ip proc-mode temp-rip x86)))

    x86))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def-inst x86-vmovups/vmovupd/vmovdqu-vex-b

  :parents (two-byte-opcodes fp-opcodes)

  :short "VMOVUPS, VMOVUPD, VMMOVDQU:
          move unaligned packed single/double-precision floating-point values
          and unaligned packed integer values
          (VEX encoding, Op/En B)"

  :long
  "<p>
   These instructions are listed under MOVUPS, MOVUPD, and MOVDQU
   in Intel Manual Volume 2 (Jun 2025).
   </p>
   <p>
   This semantic function covers the two VEX-encoded variants
   (of each of VMOVUPS, MOVUPD, and VMOVDQU)
   that move from register to to register or memory (i.e. Op/En B).
   </p>
   <p>
   The three instructions behave in the same way at the ISA level,
   but they have different encodings,
   and are used with different types at the assembly and higher levels;
   there may also be performance differences at the level lower than the ISA.
   </p>
   <code>
   VMOVUPS xmm2/m128, xmm1
   VMOVUPS ymm2/m256, ymm1
   </code>
   <code>
   VMOVUPD xmm2/m128, xmm1
   VMOVUPD ymm2/m256, ymm1
   </code>
   <code>
   VMOVDQU xmm2/m128, xmm1
   VMOVDQU ymm2/m256, ymm1
   </code>"

  :vex t

  :modr/m t

  :guard (vex-prefixes-byte0-p vex-prefixes)

  :returns (x86 x86p :hyp (x86p x86))

  :body

  (b* ((p2 (prefixes->seg prefixes))
       (p4? (eql #.*addr-size-override* (prefixes->adr prefixes)))
       (seg-reg (select-segment-register proc-mode p2 p4? mod r/m sib x86))
       (rex-byte (rex-byte-from-vex-prefixes vex-prefixes))

       ;; The operand size is determined by VEX.L, regardless of processor mode.
       ((the (integer 16 32) operand-size)
        (if (equal (vex->l vex-prefixes) 1)
            32
          16))

       ;; Read the value from register.
       ((the (unsigned-byte 256) reg-value)
        (zmmi-size operand-size
                   (reg-index reg rex-byte #.*r*)
                   x86))

       ;; Obtain the address of the destination operand, if in memory.
       ;; Read the value from register or memory.
       ;; There is no alignment check, since it is an 'unaligned' move.
       ;; Also see Intel Manual Volume 1 (Jun 2025), Table 14-23.
       (inst-ac? nil)
       ((mv flg
            & ; old value of the operand
            (the (integer 0 4) increment-rip-by)
            (the (signed-byte 64) addr) ; 0 if destination is register
            x86)
        (x86-operand-from-modr/m-and-sib-bytes proc-mode
                                               (if (= operand-size 16)
                                                   #.*vex-xmm-access*
                                                 #.*ymm-access*)
                                               operand-size
                                               inst-ac?
                                               nil ; not a memory operand
                                               seg-reg
                                               p4?
                                               temp-rip
                                               rex-byte
                                               r/m
                                               mod
                                               sib
                                               0 ; no immediate operand
                                               x86))
       ((when flg)
        (!!ms-fresh :x86-operand-from-modr/m-and-sib-bytes flg))

       ;; Increment the instruction pointer in the temp-rip variable.
       ((mv flg (the (signed-byte #.*max-linear-address-size*) temp-rip))
        (add-to-*ip proc-mode temp-rip increment-rip-by x86))
       ((when flg) (!!ms-fresh :rip-increment-error flg))

       ;; Ensure the instruction is not too long.
       (badlength? (check-instruction-length start-rip temp-rip 0))
       ((when badlength?)
        (!!fault-fresh :gp 0 :instruction-length badlength?)) ;; #GP(0)

       ;; Update the destination operand, register or memory.
       ;; Note that this operation zeros the upper bits,
       ;; as required in the pseudocode of the instruction.
       ;; In our model, MAXVL is 512,
       ;; because our model of the x86 state has just the ZMM registers,
       ;; whose lower bits are aliased to YMM and XMM.
       ((mv flg x86)
        (x86-operand-to-zmm/mem proc-mode
                                (if (= operand-size 16)
                                    #.*vex-xmm-access*
                                  #.*ymm-access*)
                                operand-size
                                inst-ac?
                                reg-value
                                seg-reg
                                addr
                                rex-byte
                                r/m
                                mod
                                x86))
       ((when flg) (!!ms-fresh :x86-operand-to-zmm/mem flg))

       ;; Update the instruction pointer in the state.
       (x86 (write-*ip proc-mode temp-rip x86)))

    x86))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; VMOVAPS, VMOVAPD, VMOVDQA

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def-inst x86-vmovaps/vmovapd/vmovdqa-vex-a

  :parents (two-byte-opcodes fp-opcodes)

  :short "VMOVAPS, VMOVAPD, VMMOVDQA:
          move aligned packed single/double-precision floating-point values
          and aligned packed integer values
          (VEX encoding, Op/En A)."

  :long
  "<p>
   These instructions are listed under MOVAPS, MOVAPD, and MOVDQA
   in Intel Manual Volume 2 (Jun 2025).
   </p>
   <p>
   This semantic function covers the two VEX-encoded variants
   (of each of VMOVAPS, MOVAPD, and VMOVDQA)
   that move from register or memory to register (i.e. Op/En A).
   </p>
   <p>
   The three instructions behave in the same way at the ISA level,
   but they have different encodings,
   and are used with different types at the assembly and higher levels;
   there may also be performance differences at the level lower than the ISA.
   </p>
   <code>
   VMOVAPS xmm1, xmm2/m128
   VMOVAPS ymm1, ymm2/m256
   </code>
   <code>
   VMOVAPD xmm1, xmm2/m128
   VMOVAPD ymm1, ymm2/m256
   </code>
   <code>
   VMOVDQA xmm1, xmm2/m128
   VMOVDQA ymm1, ymm2/m256
   </code>"

  :vex t

  :modr/m t

  :guard (vex-prefixes-byte0-p vex-prefixes)

  :returns (x86 x86p :hyp (x86p x86))

  :body

  (b* ((p2 (prefixes->seg prefixes))
       (p4? (eql #.*addr-size-override* (prefixes->adr prefixes)))
       (seg-reg (select-segment-register proc-mode p2 p4? mod r/m sib x86))
       (rex-byte (rex-byte-from-vex-prefixes vex-prefixes))

       ;; The operand size is determined by VEX.L, regardless of processor mode.
       ((the (integer 16 32) operand-size)
        (if (equal (vex->l vex-prefixes) 1)
            32
          16))

       ;; Read the value from register or memory.
       ;; There is an alignment check, since it is an 'aligned' move.
       ;; Also see Intel Manual Volume 1 (Jun 2025), Table 14-22.
       (inst-ac? t)
       ((mv flg
            (the (unsigned-byte 256) reg/mem-value)
            (the (integer 0 4) increment-rip-by)
            & ; address of the operand
            x86)
        (x86-operand-from-modr/m-and-sib-bytes proc-mode
                                               (if (= operand-size 16)
                                                   #.*vex-xmm-access*
                                                 #.*ymm-access*)
                                               operand-size
                                               inst-ac?
                                               nil ; not a memory operand
                                               seg-reg
                                               p4?
                                               temp-rip
                                               rex-byte
                                               r/m
                                               mod
                                               sib
                                               0 ; no immediate operand
                                               x86))
       ((when flg)
        (!!ms-fresh :x86-operand-from-modr/m-and-sib-bytes flg))

       ;; Increment the instruction pointer in the temp-rip variable.
       ((mv flg (the (signed-byte #.*max-linear-address-size*) temp-rip))
        (add-to-*ip proc-mode temp-rip increment-rip-by x86))
       ((when flg) (!!ms-fresh :rip-increment-error flg))

       ;; Ensure the instruction is not too long.
       (badlength? (check-instruction-length start-rip temp-rip 0))
       ((when badlength?)
        (!!fault-fresh :gp 0 :instruction-length badlength?)) ;; #GP(0)

       ;; Update the destination register.
       ;; Note that this operation zeros the upper bits,
       ;; as required in the pseudocode of the instruction.
       ;; In our model, MAXVL is 512,
       ;; because our model of the x86 state has just the ZMM registers,
       ;; whose lower bits are aliased to YMM and XMM.
       (x86 (!zmmi-size operand-size
                        (reg-index reg rex-byte #.*r*)
                        reg/mem-value
                        x86
                        :regtype (if (= operand-size 16)
                                     #.*vex-xmm-access*
                                   #.*ymm-access*)))

       ;; Update the instruction pointer in the state.
       (x86 (write-*ip proc-mode temp-rip x86)))

    x86))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def-inst x86-vmovaps/vmovapd/vmovdqa-vex-b

  :parents (two-byte-opcodes fp-opcodes)

  :short "VMOVAPS, VMOVAPD, VMMOVDQA:
          move unaligned packed single/double-precision floating-point values
          and unaligned packed integer values
          (VEX encoding, Op/En B)"

  :long
  "<p>
   These instructions are listed under MOVAPS, MOVAPD, and MOVDQA
   in Intel Manual Volume 2 (Jun 2025).
   </p>
   <p>
   This semantic function covers the two VEX-encoded variants
   (of each of VMOVAPS, MOVAPD, and VMOVDQA)
   that move from register to to register or memory (i.e. Op/En B).
   </p>
   <p>
   The three instructions behave in the same way at the ISA level,
   but they have different encodings,
   and are used with different types at the assembly and higher levels;
   there may also be performance differences at the level lower than the ISA.
   </p>
   <code>
   VMOVAPS xmm2/m128, xmm1
   VMOVAPS ymm2/m256, ymm1
   </code>
   <code>
   VMOVAPD xmm2/m128, xmm1
   VMOVAPD ymm2/m256, ymm1
   </code>
   <code>
   VMOVDQA xmm2/m128, xmm1
   VMOVDQA ymm2/m256, ymm1
   </code>"

  :vex t

  :modr/m t

  :guard (vex-prefixes-byte0-p vex-prefixes)

  :returns (x86 x86p :hyp (x86p x86))

  :body

  (b* ((p2 (prefixes->seg prefixes))
       (p4? (eql #.*addr-size-override* (prefixes->adr prefixes)))
       (seg-reg (select-segment-register proc-mode p2 p4? mod r/m sib x86))
       (rex-byte (rex-byte-from-vex-prefixes vex-prefixes))

       ;; The operand size is determined by VEX.L, regardless of processor mode.
       ((the (integer 16 32) operand-size)
        (if (equal (vex->l vex-prefixes) 1)
            32
          16))

       ;; Read the value from register.
       ((the (unsigned-byte 256) reg-value)
        (zmmi-size operand-size
                   (reg-index reg rex-byte #.*r*)
                   x86))

       ;; Obtain the address of the destination operand, if in memory.
       ;; Read the value from register or memory.
       ;; There is an alignment check, since it is an 'aligned' move.
       ;; Also see Intel Manual Volume 1 (Jun 2025), Table 14-22.
       (inst-ac? t)
       ((mv flg
            & ; old value of the operand
            (the (integer 0 4) increment-rip-by)
            (the (signed-byte 64) addr) ; 0 if destination is register
            x86)
        (x86-operand-from-modr/m-and-sib-bytes proc-mode
                                               (if (= operand-size 16)
                                                   #.*vex-xmm-access*
                                                 #.*ymm-access*)
                                               operand-size
                                               inst-ac?
                                               nil ; not a memory operand
                                               seg-reg
                                               p4?
                                               temp-rip
                                               rex-byte
                                               r/m
                                               mod
                                               sib
                                               0 ; no immediate operand
                                               x86))
       ((when flg)
        (!!ms-fresh :x86-operand-from-modr/m-and-sib-bytes flg))

       ;; Increment the instruction pointer in the temp-rip variable.
       ((mv flg (the (signed-byte #.*max-linear-address-size*) temp-rip))
        (add-to-*ip proc-mode temp-rip increment-rip-by x86))
       ((when flg) (!!ms-fresh :rip-increment-error flg))

       ;; Ensure the instruction is not too long.
       (badlength? (check-instruction-length start-rip temp-rip 0))
       ((when badlength?)
        (!!fault-fresh :gp 0 :instruction-length badlength?)) ;; #GP(0)

       ;; Update the destination operand, register or memory.
       ;; Note that this operation zeros the upper bits,
       ;; as required in the pseudocode of the instruction.
       ;; In our model, MAXVL is 512,
       ;; because our model of the x86 state has just the ZMM registers,
       ;; whose lower bits are aliased to YMM and XMM.
       ((mv flg x86)
        (x86-operand-to-zmm/mem proc-mode
                                (if (= operand-size 16)
                                    #.*vex-xmm-access*
                                  #.*ymm-access*)
                                operand-size
                                inst-ac?
                                reg-value
                                seg-reg
                                addr
                                rex-byte
                                r/m
                                mod
                                x86))
       ((when flg) (!!ms-fresh :x86-operand-to-zmm/mem flg))

       ;; Update the instruction pointer in the state.
       (x86 (write-*ip proc-mode temp-rip x86)))

    x86))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; VMOVDDUP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(def-inst x86-vmovddup-vex

  :parents (two-byte-opcodes)

  :short "VMOVDDUP: replicate double precision floating-point values."

  :long
  "<p>
   This instruction is listed under MOVDDUP
   in Intel Manual Volume 2 (Jun 2025).
   </p>
   <p>
   When the operand size is 128 bits,
   the use of @('m64') in @('xmm2/m64') in the Intel manual
   suggests that only 64 bits are read from the source operand.
   If the access is to memory,
   reading 128 bits and ignoring the 64 high ones can make a difference
   if the additional memory accesses cause some kind of exception.
   </p>
   <p>
   When the operand size is 256 bits,
   the use of @('m256') in @('ymm2/m256') in the Intel manual
   suggests that all 256 bits are read from the source operand,
   even though the ones at positions 64-127 and 192-255 are ignored.
   In principle it could suffice to read the ones at positions 0-63 and 128-191,
   or perhaps the low 192 bits.
   But we read all 256, because of the @('m256').
   If the access is to memory,
   reading fewer bytes could make a difference
   if the additional ignored ones cause some kind of exception.
   </p>"

  :vex t

  :modr/m t

  :guard (vex-prefixes-byte0-p vex-prefixes)

  :returns (x86 x86p :hyp (x86p x86))

  :body

  (b* ((p2 (prefixes->seg prefixes))
       (p4? (eql #.*addr-size-override* (prefixes->adr prefixes)))
       (seg-reg (select-segment-register proc-mode p2 p4? mod r/m sib x86))
       (rex-byte (rex-byte-from-vex-prefixes vex-prefixes))

       ;; index of xmm1 or ymm1:
       ((the (unsigned-byte 4) xmm/ymm-index)
        (reg-index reg rex-byte #.*r*))

       ;; The operand size is determined by VEX.L, regardless of processor mode.
       ((the (integer 16 32) operand-size)
        (if (equal (vex->l vex-prefixes) 1)
            32
          16))

       ;; read xmm2/m64 or ymm2/m256:
       (inst-ac? t)
       ((mv flg
            (the (unsigned-byte 256) val)
            (the (integer 0 4) increment-RIP-by)
            & ; address of the operand
            x86)
        (x86-operand-from-modr/m-and-sib-bytes proc-mode
                                               (if (= operand-size 16)
                                                   #.*vex-xmm-access*
                                                 #.*ymm-access*)
                                               (if (= operand-size 16)
                                                   8 ; 64 bits for xmm2/m64
                                                 32) ; 256 bits for ymm2/m256
                                               inst-ac?
                                               nil ; not a memory operand
                                               seg-reg
                                               p4?
                                               temp-rip
                                               rex-byte
                                               r/m
                                               mod
                                               sib
                                               0 ; no immediate operand
                                               x86))
       ((when flg)
        (!!ms-fresh :x86-operand-from-modr/m-and-sib-bytes flg))

       ((mv flg (the (signed-byte #.*max-linear-address-size*) temp-rip))
        (add-to-*ip proc-mode temp-rip increment-RIP-by x86))
       ((when flg) (!!ms-fresh :rip-increment-error flg))

       (badlength? (check-instruction-length start-rip temp-rip 0))
       ((when badlength?)
        (!!fault-fresh :gp 0 :instruction-length badlength?)) ;; #GP(0)

       ;; value for xmm1 or ymm2:
       (dup-val (if (= operand-size 16)
                    (logior (ash val 64) val)
                  ;; Figure 4-2 in Intel manual:
                  (b* ((x0 (part-select val :low 0 :high 63))
                       (x2 (part-select val :low 128 :high 191))
                       (x0x0 (logior (ash x0 64) x0))
                       (x2x2 (logior (ash x2 64) x2)))
                    (logior (ash x2x2 128) x0x0))))

       ;; write to xmm1 or ymm2:
       (x86 (!zmmi-size operand-size
                        xmm/ymm-index
                        dup-val
                        x86
                        :regtype (if (= operand-size 16)
                                     #.*vex-xmm-access*
                                   #.*ymm-access*)))

       (x86 (write-*ip proc-mode temp-rip x86)))
    x86))
