1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- begin                                     guest_amd64_toIR.c ---*/
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This file is part of Valgrind, a dynamic binary instrumentation
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   framework.
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   Copyright (C) 2004-2011 OpenWorks LLP
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      info@open-works.net
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is free software; you can redistribute it and/or
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modify it under the terms of the GNU General Public License as
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   published by the Free Software Foundation; either version 2 of the
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   License, or (at your option) any later version.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This program is distributed in the hope that it will be useful, but
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   WITHOUT ANY WARRANTY; without even the implied warranty of
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   General Public License for more details.
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   You should have received a copy of the GNU General Public License
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   along with this program; if not, write to the Free Software
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   02110-1301, USA.
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The GNU General Public License is contained in the file COPYING.
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Neither the names of the U.S. Department of Energy nor the
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   University of California nor the names of its contributors may be
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   used to endorse or promote products derived from this software
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   without prior written permission.
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Translates AMD64 code to IR. */
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* TODO:
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   All Puts to CC_OP/CC_DEP1/CC_DEP2/CC_NDEP should really be checked
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to ensure a 64-bit value is being written.
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x87 FP Limitations:
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * all arithmetic done at 64 bits
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * no FP exceptions, except for handling stack over/underflow
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP rounding mode observed only for float->int conversions and
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     int->float conversions which could lose accuracy, and for
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     float-to-float rounding.  For all other operations,
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     round-to-nearest is used, regardless.
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP sin/cos/tan/sincos: C2 flag is always cleared.  IOW the
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     simulation claims the argument is in-range (-2^63 <= arg <= 2^63)
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     even when it isn't.
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * some of the FCOM cases could do with testing -- not convinced
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     that the args are the right way round.
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FSAVE does not re-initialise the FPU; it should do
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FINIT not only initialises the FPU environment, it also zeroes
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     all the FP registers.  It should leave the registers unchanged.
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    RDTSC returns zero, always.
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    SAHF should cause eflags[1] == 1, and in fact it produces 0.  As
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    per Intel docs this bit has no meaning anyway.  Since PUSHF is the
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    only way to observe eflags[1], a proper fix would be to make that
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    bit be set by PUSHF.
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    This module uses global variables and so is not MT-safe (if that
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    should ever become relevant).
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Notes re address size overrides (0x67).
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   According to the AMD documentation (24594 Rev 3.09, Sept 2003,
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   "AMD64 Architecture Programmer's Manual Volume 3: General-Purpose
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and System Instructions"), Section 1.2.3 ("Address-Size Override
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Prefix"):
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0x67 applies to all explicit memory references, causing the top
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   32 bits of the effective address to become zero.
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0x67 has no effect on stack references (push/pop); these always
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   use a 64-bit address.
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0x67 changes the interpretation of instructions which implicitly
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reference RCX/RSI/RDI, so that in fact ECX/ESI/EDI are used
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instead.  These are:
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmp{s,sb,sw,sd,sq}
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      in{s,sb,sw,sd}
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jcxz, jecxz, jrcxz
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lod{s,sb,sw,sd,sq}
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      loop{,e,bz,be,z}
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov{s,sb,sw,sd,sq}
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      out{s,sb,sw,sd}
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rep{,e,ne,nz}
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sca{s,sb,sw,sd,sq}
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sto{s,sb,sw,sd,sq}
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xlat{,b} */
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* "Special" instructions.
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This instruction decoder can decode three special instructions
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which mean nothing natively (are no-ops as far as regs/mem are
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   concerned) but have meaning for supporting Valgrind.  A special
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   48C1C73D 48C1C733 (in the standard interpretation, that means: rolq
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   $3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi).
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Following that, one of the following 3 are allowed (standard
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   interpretation in parentheses):
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4887DB (xchgq %rbx,%rbx)   %RDX = client_request ( %RAX )
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4887C9 (xchgq %rcx,%rcx)   %RAX = guest_NRADDR
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      4887D2 (xchgq %rdx,%rdx)   call-noredir *%RAX
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Any other bytes following the 16-byte preamble are illegal and
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   constitute a failure in instruction decoding.  This all assumes
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that the preamble will never occur except in specific code
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fragments designed for Valgrind to catch.
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   No prefixes may precede a "Special" instruction.
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* casLE (implementation of lock-prefixed insns) and rep-prefixed
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insns: the side-exit back to the start of the insn is done with
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ijk_Boring.  This is quite wrong, it should be done with
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ijk_NoRedir, since otherwise the side exit, which is intended to
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   restart the instruction for whatever reason, could go somewhere
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   entirely else.  Doing it right (with Ijk_NoRedir jumps) would make
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no-redir jumps performance critical, at least for rep-prefixed
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions, since all iterations thereof would involve such a
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jump.  It's not such a big deal with casLE since the side exit is
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   only taken if the CAS fails, that is, the location is contended,
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which is relatively unlikely.
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note also, the test for CAS success vs failure is done using
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Iop_Cmp{EQ,NE} equivalents.  This is so as to tell Memcheck that it
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shouldn't definedness-check these comparisons.  See
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   COMMENT_ON_CasCmpEQ in memcheck/mc_translate.c for
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   background/rationale.
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* LOCK prefixed instructions.  These are translated using IR-level
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CAS statements (IRCAS) and are believed to preserve atomicity, even
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from the point of view of some other process racing against a
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   simulated one (presumably they communicate via a shared memory
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   segment).
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handlers which are aware of LOCK prefixes are:
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_op2_G_E      (add, or, adc, sbb, and, sub, xor)
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_cmpxchg_G_E  (cmpxchg)
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp1         (add, or, adc, sbb, and, sub, xor)
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp3         (not, neg)
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp4         (inc, dec)
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp5         (inc, dec)
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_Grp8_Imm     (bts, btc, btr)
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_bt_G_E       (bts, btc, btr)
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_xadd_G_E     (xadd)
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_basictypes.h"
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_ir.h"
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex.h"
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "libvex_guest_amd64.h"
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_util.h"
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "main_globals.h"
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_bb_to_IR.h"
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_generic_x87.h"
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "guest_amd64_defs.h"
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Globals                                              ---*/
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are set at the start of the translation of an insn, right
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   down in disInstr_AMD64, so that we don't have to pass them around
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   endlessly.  They are all constant during the translation of any
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   given insn. */
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* These are set at the start of the translation of a BB, so
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that we don't have to pass them around endlessly. */
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* We need to know this to do sub-register accesses correctly. */
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool host_is_bigendian;
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Pointer to the guest code area (points to start of BB, not to the
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn being processed). */
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar* guest_code;
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The guest address corresponding to guest_code[0]. */
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr64 guest_RIP_bbstart;
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The guest address for the instruction currently being
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   translated. */
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr64 guest_RIP_curr_instr;
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The IRSB* into which we're generating code. */
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRSB* irsb;
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For ensuring that %rip-relative addressing is done right.  A read
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of %rip generates the address of the next instruction.  It may be
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   that we don't conveniently know that inside disAMode().  For sanity
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   checking, if the next insn %rip is needed, we make a guess at what
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   it is, record that guess here, and set the accompanying Bool to
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   indicate that -- after this insn's decode is finished -- that guess
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   needs to be checked.  */
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* At the start of each insn decode, is set to (0, False).
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   After the decode, if _mustcheck is now True, _assumed is
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   checked. */
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Addr64 guest_RIP_next_assumed;
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool   guest_RIP_next_mustcheck;
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for constructing IR.                         ---*/
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a new temporary of the given type. */
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp newTemp ( IRType ty )
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(isPlausibleIRType(ty));
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return newIRTemp( irsb->tyenv, ty );
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Add a statement to the list held by "irsb". */
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void stmt ( IRStmt* st )
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addStmtToIRSB( irsb, st );
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a statement "dst := e". */
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void assign ( IRTemp dst, IRExpr* e )
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_WrTmp(dst, e) );
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* unop ( IROp op, IRExpr* a )
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Unop(op, a);
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Binop(op, a1, a2);
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Triop(op, a1, a2, a3);
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkexpr ( IRTemp tmp )
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_RdTmp(tmp);
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU8 ( ULong i )
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 256);
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U8( (UChar)i ));
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU16 ( ULong i )
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 0x10000ULL);
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U16( (UShort)i ));
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU32 ( ULong i )
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(i < 0x100000000ULL);
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U32( (UInt)i ));
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU64 ( ULong i )
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_U64(i));
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkU ( IRType ty, ULong i )
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return mkU8(i);
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return mkU16(i);
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return mkU32(i);
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: return mkU64(i);
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("mkU(amd64)");
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void storeLE ( IRExpr* addr, IRExpr* data )
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Store(Iend_LE, addr, data) );
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* loadLE ( IRType ty, IRExpr* addr )
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Load(Iend_LE, ty, addr);
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IROp mkSizedOp ( IRType ty, IROp op8 )
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(op8 == Iop_Add8 || op8 == Iop_Sub8
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Mul8
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_CasCmpNE8
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || op8 == Iop_Not8 );
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return 0 +op8;
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return 1 +op8;
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return 2 +op8;
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: return 3 +op8;
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("mkSizedOp(amd64)");
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* doScalarWidening ( Int szSmall, Int szBig, Bool signd, IRExpr* src )
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 4) {
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(signd ? Iop_8Sto32 : Iop_8Uto32, src);
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 2) {
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(signd ? Iop_8Sto16 : Iop_8Uto16, src);
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 2 && szBig == 4) {
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(signd ? Iop_16Sto32 : Iop_16Uto32, src);
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 8 && !signd) {
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_8Uto64, src);
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 1 && szBig == 8 && signd) {
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_8Sto64, src);
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 2 && szBig == 8 && !signd) {
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_16Uto64, src);
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szSmall == 2 && szBig == 8 && signd) {
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_16Sto64, src);
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("doScalarWidening(amd64)");
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Debugging output                                     ---*/
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Bomb out if we can't handle something. */
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown__attribute__ ((noreturn))
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void unimplemented ( HChar* str )
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("amd64toIR: unimplemented feature\n");
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic(str);
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIP(format, args...)           \
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf(format, ## args)
374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define DIS(buf, format, args...)      \
376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (vex_traceflags & VEX_TRACE_FE)  \
377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_sprintf(buf, format, ## args)
378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Offsets of various parts of the amd64 guest state.   ---*/
382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RAX       offsetof(VexGuestAMD64State,guest_RAX)
385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RBX       offsetof(VexGuestAMD64State,guest_RBX)
386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RCX       offsetof(VexGuestAMD64State,guest_RCX)
387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RDX       offsetof(VexGuestAMD64State,guest_RDX)
388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RSP       offsetof(VexGuestAMD64State,guest_RSP)
389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RBP       offsetof(VexGuestAMD64State,guest_RBP)
390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RSI       offsetof(VexGuestAMD64State,guest_RSI)
391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RDI       offsetof(VexGuestAMD64State,guest_RDI)
392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R8        offsetof(VexGuestAMD64State,guest_R8)
393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R9        offsetof(VexGuestAMD64State,guest_R9)
394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R10       offsetof(VexGuestAMD64State,guest_R10)
395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R11       offsetof(VexGuestAMD64State,guest_R11)
396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R12       offsetof(VexGuestAMD64State,guest_R12)
397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R13       offsetof(VexGuestAMD64State,guest_R13)
398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R14       offsetof(VexGuestAMD64State,guest_R14)
399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_R15       offsetof(VexGuestAMD64State,guest_R15)
400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_RIP       offsetof(VexGuestAMD64State,guest_RIP)
402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FS_ZERO   offsetof(VexGuestAMD64State,guest_FS_ZERO)
404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_GS_0x60   offsetof(VexGuestAMD64State,guest_GS_0x60)
405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_OP     offsetof(VexGuestAMD64State,guest_CC_OP)
407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP1   offsetof(VexGuestAMD64State,guest_CC_DEP1)
408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_DEP2   offsetof(VexGuestAMD64State,guest_CC_DEP2)
409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_CC_NDEP   offsetof(VexGuestAMD64State,guest_CC_NDEP)
410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPREGS    offsetof(VexGuestAMD64State,guest_FPREG[0])
412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPTAGS    offsetof(VexGuestAMD64State,guest_FPTAG[0])
413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_DFLAG     offsetof(VexGuestAMD64State,guest_DFLAG)
414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_ACFLAG    offsetof(VexGuestAMD64State,guest_ACFLAG)
415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_IDFLAG    offsetof(VexGuestAMD64State,guest_IDFLAG)
416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FTOP      offsetof(VexGuestAMD64State,guest_FTOP)
417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FC3210    offsetof(VexGuestAMD64State,guest_FC3210)
418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_FPROUND   offsetof(VexGuestAMD64State,guest_FPROUND)
419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_CS        offsetof(VexGuestX86State,guest_CS)
421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_DS        offsetof(VexGuestX86State,guest_DS)
422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_ES        offsetof(VexGuestX86State,guest_ES)
423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_FS        offsetof(VexGuestX86State,guest_FS)
424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_GS        offsetof(VexGuestX86State,guest_GS)
425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_SS        offsetof(VexGuestX86State,guest_SS)
426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_LDT       offsetof(VexGuestX86State,guest_LDT)
427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define OFFB_GDT       offsetof(VexGuestX86State,guest_GDT)
428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_SSEROUND  offsetof(VexGuestAMD64State,guest_SSEROUND)
430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM0      offsetof(VexGuestAMD64State,guest_XMM0)
431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM1      offsetof(VexGuestAMD64State,guest_XMM1)
432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM2      offsetof(VexGuestAMD64State,guest_XMM2)
433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM3      offsetof(VexGuestAMD64State,guest_XMM3)
434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM4      offsetof(VexGuestAMD64State,guest_XMM4)
435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM5      offsetof(VexGuestAMD64State,guest_XMM5)
436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM6      offsetof(VexGuestAMD64State,guest_XMM6)
437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM7      offsetof(VexGuestAMD64State,guest_XMM7)
438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM8      offsetof(VexGuestAMD64State,guest_XMM8)
439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM9      offsetof(VexGuestAMD64State,guest_XMM9)
440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM10     offsetof(VexGuestAMD64State,guest_XMM10)
441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM11     offsetof(VexGuestAMD64State,guest_XMM11)
442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM12     offsetof(VexGuestAMD64State,guest_XMM12)
443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM13     offsetof(VexGuestAMD64State,guest_XMM13)
444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM14     offsetof(VexGuestAMD64State,guest_XMM14)
445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM15     offsetof(VexGuestAMD64State,guest_XMM15)
446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_XMM16     offsetof(VexGuestAMD64State,guest_XMM16)
447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_EMWARN    offsetof(VexGuestAMD64State,guest_EMWARN)
449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_TISTART   offsetof(VexGuestAMD64State,guest_TISTART)
450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_TILEN     offsetof(VexGuestAMD64State,guest_TILEN)
451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define OFFB_NRADDR    offsetof(VexGuestAMD64State,guest_NRADDR)
453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helper bits and pieces for deconstructing the        ---*/
457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- amd64 insn stream.                                   ---*/
458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the AMD64 register encoding -- integer regs. */
461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RAX 0
462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RCX 1
463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RDX 2
464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RBX 3
465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RSP 4
466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RBP 5
467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RSI 6
468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_RDI 7
469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R8  8
470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R9  9
471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R10 10
472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R11 11
473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R12 12
474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R13 13
475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R14 14
476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_R15 15
477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define R_AL (0+R_EAX)
479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. #define R_AH (4+R_EAX)
480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is the Intel register encoding -- segment regs. */
482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_ES 0
483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_CS 1
484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_SS 2
485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_DS 3
486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_FS 4
487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define R_GS 5
488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Various simple conversions */
491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong extend_s_8to64 ( UChar x )
493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (ULong)((((Long)x) << 56) >> 56);
495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong extend_s_16to64 ( UShort x )
498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (ULong)((((Long)x) << 48) >> 48);
500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong extend_s_32to64 ( UInt x )
503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (ULong)((((Long)x) << 32) >> 32);
505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out whether the mod and rm parts of a modRM byte refer to a
508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register or memory.  If so, the byte will have the form 11XXXYYY,
509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   where YYY is the register number. */
510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline
511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool epartIsReg ( UChar mod_reg_rm )
512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(0xC0 == (mod_reg_rm & 0xC0));
514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extract the 'g' field from a modRM byte.  This only produces 3
517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits, which is not a complete register number.  You should avoid
518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this function if at all possible. */
519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline
520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int gregLO3ofRM ( UChar mod_reg_rm )
521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Int)( (mod_reg_rm >> 3) & 7 );
523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Ditto the 'e' field of a modRM byte. */
526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browninline
527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int eregLO3ofRM ( UChar mod_reg_rm )
528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (Int)(mod_reg_rm & 0x7);
530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a 8/16/32-bit unsigned value out of the insn stream. */
533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UChar getUChar ( Long delta )
535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar v = guest_code[delta+0];
537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v;
538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt getUDisp16 ( Long delta )
541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+1]; v <<= 8;
543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v & 0xFFFF;
545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static UInt getUDisp ( Int size, Long delta )
548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    switch (size) {
550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 4: return getUDisp32(delta);
551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 2: return getUDisp16(delta);
552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 1: return getUChar(delta);
553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       default: vpanic("getUDisp(x86)");
554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return 0; /*notreached*/
556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a byte value out of the insn stream and sign-extend to 64
560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits. */
561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Long getSDisp8 ( Long delta )
562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_8to64( guest_code[delta] );
564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a 16-bit value out of the insn stream and sign-extend to 64
567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits. */
568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Long getSDisp16 ( Long delta )
569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+1]; v <<= 8;
571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_16to64( (UShort)v );
573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a 32-bit value out of the insn stream and sign-extend to 64
576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bits. */
577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Long getSDisp32 ( Long delta )
578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt v = guest_code[delta+3]; v <<= 8;
580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+2]; v <<= 8;
581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+1]; v <<= 8;
582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return extend_s_32to64( v );
584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get a 64-bit value out of the insn stream. */
587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Long getDisp64 ( Long delta )
588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong v = 0;
590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+7]; v <<= 8;
591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+6]; v <<= 8;
592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+5]; v <<= 8;
593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+4]; v <<= 8;
594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+3]; v <<= 8;
595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+2]; v <<= 8;
596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+1]; v <<= 8;
597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v |= guest_code[delta+0];
598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return v;
599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Note: because AMD64 doesn't allow 64-bit literals, it is an error
602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if this is called with size==8.  Should not happen. */
603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Long getSDisp ( Int size, Long delta )
604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return getSDisp32(delta);
607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return getSDisp16(delta);
608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return getSDisp8(delta);
609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getSDisp(amd64)");
610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong mkSizeMask ( Int sz )
614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return 0x00000000000000FFULL;
617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return 0x000000000000FFFFULL;
618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return 0x00000000FFFFFFFFULL;
619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return 0xFFFFFFFFFFFFFFFFULL;
620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("mkSzMask(amd64)");
621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int imin ( Int a, Int b )
625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (a < b) ? a : b;
627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRType szToITy ( Int n )
630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (n) {
632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return Ity_I8;
633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return Ity_I16;
634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return Ity_I32;
635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return Ity_I64;
636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vex_printf("\nszToITy(%d)\n", n);
637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vpanic("szToITy(amd64)");
638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- For dealing with prefixes.                           ---*/
644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The idea is to pass around an int holding a bitmask summarising
647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   info from the prefixes seen on the current instruction, including
648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   info from the REX byte.  This info is used in various places, but
649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   most especially when making sense of register fields in
650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instructions.
651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The top 16 bits of the prefix are 0x3141, just as a hacky way
653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to ensure it really is a valid prefix.
654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Things you can safely assume about a well-formed prefix:
656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * at most one segment-override bit (CS,DS,ES,FS,GS,SS) is set.
657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * if REX is not present then REXW,REXR,REXX,REXB will read
658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     as zero.
659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * F2 and F3 will not both be 1.
660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef UInt  Prefix;
663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_ASO   (1<<0)     /* address-size override present (0x67) */
665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_66    (1<<1)     /* operand-size override-to-16 present (0x66) */
666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_REX   (1<<2)     /* REX byte present (0x40 to 0x4F) */
667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_REXW  (1<<3)     /* REX W bit, if REX present, else 0 */
668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_REXR  (1<<4)     /* REX R bit, if REX present, else 0 */
669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_REXX  (1<<5)     /* REX X bit, if REX present, else 0 */
670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_REXB  (1<<6)     /* REX B bit, if REX present, else 0 */
671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_LOCK  (1<<7)     /* bus LOCK prefix present (0xF0) */
672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_F2    (1<<8)     /* REP/REPE/REPZ prefix present (0xF2) */
673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_F3    (1<<9)     /* REPNE/REPNZ prefix present (0xF3) */
674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_CS    (1<<10)    /* CS segment prefix present (0x2E) */
675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_DS    (1<<11)    /* DS segment prefix present (0x3E) */
676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_ES    (1<<12)    /* ES segment prefix present (0x26) */
677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_FS    (1<<13)    /* FS segment prefix present (0x64) */
678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_GS    (1<<14)    /* GS segment prefix present (0x65) */
679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_SS    (1<<15)    /* SS segment prefix present (0x36) */
680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define PFX_EMPTY 0x31410000
682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool IS_VALID_PFX ( Prefix pfx ) {
684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & 0xFFFF0000) == PFX_EMPTY);
685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveREX ( Prefix pfx ) {
688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(pfx & PFX_REX);
689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int getRexW ( Prefix pfx ) {
692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (pfx & PFX_REXW) ? 1 : 0;
693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Apparently unused.
695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int getRexR ( Prefix pfx ) {
696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (pfx & PFX_REXR) ? 1 : 0;
697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int getRexX ( Prefix pfx ) {
700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (pfx & PFX_REXX) ? 1 : 0;
701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int getRexB ( Prefix pfx ) {
703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return (pfx & PFX_REXB) ? 1 : 0;
704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Check a prefix doesn't have F2 or F3 set in it, since usually that
707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   completely changes what instruction it really is. */
708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveF2orF3 ( Prefix pfx ) {
709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & (PFX_F2|PFX_F3)) > 0);
710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveF2 ( Prefix pfx ) {
712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & PFX_F2) > 0);
713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveF3 ( Prefix pfx ) {
715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & PFX_F3) > 0);
716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool have66 ( Prefix pfx ) {
719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & PFX_66) > 0);
720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveASO ( Prefix pfx ) {
722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & PFX_ASO) > 0);
723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has 66 set and F2 and F3 clear */
726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool have66noF2noF3 ( Prefix pfx )
727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return
729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_66);
730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has F2 set and 66 and F3 clear */
733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveF2no66noF3 ( Prefix pfx )
734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return
736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F2);
737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has F3 set and 66 and F2 clear */
740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveF3no66noF2 ( Prefix pfx )
741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return
743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == PFX_F3);
744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has F3 set and F2 clear */
747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveF3noF2 ( Prefix pfx )
748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return
750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     toBool((pfx & (PFX_F2|PFX_F3)) == PFX_F3);
751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
753f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root/* Return True iff pfx has F2 set and F3 clear */
754f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Rootstatic Bool haveF2noF3 ( Prefix pfx )
755f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root{
756f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root  return
757f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root     toBool((pfx & (PFX_F2|PFX_F3)) == PFX_F2);
758f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root}
759f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has 66, F2 and F3 clear */
761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool haveNo66noF2noF3 ( Prefix pfx )
762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return
764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     toBool((pfx & (PFX_66|PFX_F2|PFX_F3)) == 0);
765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has any of 66, F2 and F3 set */
768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool have66orF2orF3 ( Prefix pfx )
769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return toBool( ! haveNo66noF2noF3(pfx) );
771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Return True iff pfx has 66 or F2 set */
774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool have66orF2 ( Prefix pfx )
775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool((pfx & (PFX_66|PFX_F2)) > 0);
777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Clear all the segment-override bits in a prefix. */
780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Prefix clearSegBits ( Prefix p )
781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      p & ~(PFX_CS | PFX_DS | PFX_ES | PFX_FS | PFX_GS | PFX_SS);
784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- For dealing with integer registers                   ---*/
789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* This is somewhat complex.  The rules are:
792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For 64, 32 and 16 bit register references, the e or g fields in the
794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm bytes supply the low 3 bits of the register number.  The
795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   fourth (most-significant) bit of the register number is supplied by
796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the REX byte, if it is present; else that bit is taken to be zero.
797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The REX.R bit supplies the high bit corresponding to the g register
799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   field, and the REX.B bit supplies the high bit corresponding to the
800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   e register field (when the mod part of modrm indicates that modrm's
801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   e component refers to a register and not to memory).
802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The REX.X bit supplies a high register bit for certain registers
804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in SIB address modes, and is generally rarely used.
805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   For 8 bit register references, the presence of the REX byte itself
807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   has significance.  If there is no REX present, then the 3-bit
808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   number extracted from the modrm e or g field is treated as an index
809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   into the sequence %al %cl %dl %bl %ah %ch %dh %bh -- that is, the
810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   old x86 encoding scheme.
811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   But if there is a REX present, the register reference is
813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   interpreted in the same way as for 64/32/16-bit references: a high
814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   bit is extracted from REX, giving a 4-bit number, and the denoted
815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register is the lowest 8 bits of the 16 integer registers denoted
816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by the number.  In particular, values 3 through 7 of this sequence
817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do not refer to %ah %ch %dh %bh but instead to the lowest 8 bits of
818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   %rsp %rbp %rsi %rdi.
819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The REX.W bit has no bearing at all on register numbers.  Instead
821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   its presence indicates that the operand size is to be overridden
822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from its default value (32 bits) to 64 bits instead.  This is in
823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the same fashion that an 0x66 prefix indicates the operand size is
824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   to be overridden from 32 bits down to 16 bits.  When both REX.W and
825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0x66 are present there is a conflict, and REX.W takes precedence.
826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Rather than try to handle this complexity using a single huge
828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   function, several smaller ones are provided.  The aim is to make it
829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   as difficult as possible to screw up register decoding in a subtle
830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and hard-to-track-down way.
831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Because these routines fish around in the host's memory (that is,
833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in the guest state area) for sub-parts of guest registers, their
834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   correctness depends on the host's endianness.  So far these
835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   routines only work for little-endian hosts.  Those for which
836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   endianness is important have assertions to ensure sanity.
837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* About the simplest question you can ask: where do the 64-bit
841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   integer registers live (in the guest state) ? */
842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int integerGuestReg64Offset ( UInt reg )
844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (reg) {
846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RAX: return OFFB_RAX;
847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RCX: return OFFB_RCX;
848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RDX: return OFFB_RDX;
849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RBX: return OFFB_RBX;
850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RSP: return OFFB_RSP;
851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RBP: return OFFB_RBP;
852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RSI: return OFFB_RSI;
853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_RDI: return OFFB_RDI;
854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R8:  return OFFB_R8;
855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R9:  return OFFB_R9;
856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R10: return OFFB_R10;
857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R11: return OFFB_R11;
858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R12: return OFFB_R12;
859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R13: return OFFB_R13;
860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R14: return OFFB_R14;
861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case R_R15: return OFFB_R15;
862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("integerGuestReg64Offset(amd64)");
863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produce the name of an integer register, for printing purposes.
868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reg is a number in the range 0 .. 15 that has been generated from a
869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   3-bit reg-field number and a REX extension bit.  irregular denotes
870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the case where sz==1 and no REX byte is present. */
871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* nameIReg ( Int sz, UInt reg, Bool irregular )
874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg64_names[16]
876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%rax", "%rcx", "%rdx", "%rbx", "%rsp", "%rbp", "%rsi", "%rdi",
877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%r8",  "%r9",  "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" };
878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg32_names[16]
879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%eax", "%ecx", "%edx", "%ebx", "%esp", "%ebp", "%esi", "%edi",
880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%r8d", "%r9d", "%r10d","%r11d","%r12d","%r13d","%r14d","%r15d" };
881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg16_names[16]
882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%ax",  "%cx",  "%dx",  "%bx",  "%sp",  "%bp",  "%si",  "%di",
883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%r8w", "%r9w", "%r10w","%r11w","%r12w","%r13w","%r14w","%r15w" };
884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg8_names[16]
885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%al",  "%cl",  "%dl",  "%bl",  "%spl", "%bpl", "%sil", "%dil",
886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%r8b", "%r9b", "%r10b","%r11b","%r12b","%r13b","%r14b","%r15b" };
887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* ireg8_irregular[8]
888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%al", "%cl", "%dl", "%bl", "%ah", "%ch", "%dh", "%bh" };
889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(reg < 16);
891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 1) {
892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (irregular)
893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(reg < 8);
894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(irregular == False);
896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return ireg64_names[reg];
900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return ireg32_names[reg];
901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return ireg16_names[reg];
902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: if (irregular) {
903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 return ireg8_irregular[reg];
904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              } else {
905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 return ireg8_names[reg];
906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              }
907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameIReg(amd64)");
908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Using the same argument conventions as nameIReg, produce the
912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest state offset of an integer register. */
913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownInt offsetIReg ( Int sz, UInt reg, Bool irregular )
916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(reg < 16);
918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 1) {
919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (irregular)
920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(reg < 8);
921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(irregular == False);
923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Deal with irregular case -- sz==1 and no REX present */
926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 1 && irregular) {
927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (reg) {
928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_RSP: return 1+ OFFB_RAX;
929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_RBP: return 1+ OFFB_RCX;
930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_RSI: return 1+ OFFB_RDX;
931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case R_RDI: return 1+ OFFB_RBX;
932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:    break; /* use the normal case */
933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Normal case */
937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return integerGuestReg64Offset(reg);
938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Read the %CL register :: Ity_I8, for shift/rotate operations. */
942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIRegCL ( void )
944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_RCX, Ity_I8 );
947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Write to the %AH register. */
951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIRegAH ( IRExpr* e )
953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I8);
956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_RAX+1, e ) );
957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Read/write various widths of %RAX, as it has various
961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   special-purpose uses. */
962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIRegRAX ( Int sz )
964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return "%al";
967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return "%ax";
968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return "%eax";
969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return "%rax";
970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameIRegRAX(amd64)");
971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIRegRAX ( Int sz )
975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return IRExpr_Get( OFFB_RAX, Ity_I8 );
979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return IRExpr_Get( OFFB_RAX, Ity_I16 );
980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RAX, Ity_I64 ));
981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return IRExpr_Get( OFFB_RAX, Ity_I64 );
982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getIRegRAX(amd64)");
983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIRegRAX ( Int sz, IRExpr* e )
987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = typeOfIRExpr(irsb->tyenv, e);
989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: vassert(ty == Ity_I64);
992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              stmt( IRStmt_Put( OFFB_RAX, e ));
993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: vassert(ty == Ity_I32);
995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              stmt( IRStmt_Put( OFFB_RAX, unop(Iop_32Uto64,e) ));
996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: vassert(ty == Ity_I16);
998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              stmt( IRStmt_Put( OFFB_RAX, e ));
999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
1000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: vassert(ty == Ity_I8);
1001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              stmt( IRStmt_Put( OFFB_RAX, e ));
1002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
1003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("putIRegRAX(amd64)");
1004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Read/write various widths of %RDX, as it has various
1009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   special-purpose uses. */
1010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIRegRDX ( Int sz )
1012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
1014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return "%dl";
1015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return "%dx";
1016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return "%edx";
1017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return "%rdx";
1018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameIRegRDX(amd64)");
1019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIRegRDX ( Int sz )
1023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
1026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return IRExpr_Get( OFFB_RDX, Ity_I8 );
1027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return IRExpr_Get( OFFB_RDX, Ity_I16 );
1028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return unop(Iop_64to32, IRExpr_Get( OFFB_RDX, Ity_I64 ));
1029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return IRExpr_Get( OFFB_RDX, Ity_I64 );
1030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("getIRegRDX(amd64)");
1031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIRegRDX ( Int sz, IRExpr* e )
1035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
1038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
1039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: stmt( IRStmt_Put( OFFB_RDX, e ));
1040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
1041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: stmt( IRStmt_Put( OFFB_RDX, unop(Iop_32Uto64,e) ));
1042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
1043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: stmt( IRStmt_Put( OFFB_RDX, e ));
1044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
1045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: stmt( IRStmt_Put( OFFB_RDX, e ));
1046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              break;
1047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("putIRegRDX(amd64)");
1048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Simplistic functions to deal with the integer registers as a
1053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   straightforward bank of 16 64-bit regs. */
1054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIReg64 ( UInt regno )
1056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( integerGuestReg64Offset(regno),
1058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64 );
1059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIReg64 ( UInt regno, IRExpr* e )
1062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
1064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( integerGuestReg64Offset(regno), e ) );
1065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIReg64 ( UInt regno )
1068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( 8, regno, False );
1070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Simplistic functions to deal with the lower halves of integer
1074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   registers as a straightforward bank of 16 32-bit regs. */
1075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIReg32 ( UInt regno )
1077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_64to32,
1080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Get( integerGuestReg64Offset(regno),
1081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Ity_I64 ));
1082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIReg32 ( UInt regno, IRExpr* e )
1085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
1087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_32Uto64,e) ) );
1089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIReg32 ( UInt regno )
1092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( 4, regno, False );
1094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Simplistic functions to deal with the lower quarters of integer
1098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   registers as a straightforward bank of 16 16-bit regs. */
1099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIReg16 ( UInt regno )
1101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( integerGuestReg64Offset(regno),
1104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I16 );
1105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovstatic void putIReg16 ( UInt regno, IRExpr* e )
1108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov{
1109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
1110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   stmt( IRStmt_Put( integerGuestReg64Offset(regno),
1111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                     unop(Iop_16Uto64,e) ) );
1112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov}
1113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
1114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIReg16 ( UInt regno )
1115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( 2, regno, False );
1117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sometimes what we know is a 3-bit register number, a REX byte, and
1121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   which field of the REX byte is to be used to extend to a 4-bit
1122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   number.  These functions cater for that situation.
1123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIReg64rexX ( Prefix pfx, UInt lo3bits )
1125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(lo3bits < 8);
1127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return getIReg64( lo3bits | (getRexX(pfx) << 3) );
1129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIReg64rexX ( Prefix pfx, UInt lo3bits )
1132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(lo3bits < 8);
1134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( 8, lo3bits | (getRexX(pfx) << 3), False );
1136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(lo3bits < 8);
1141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( sz, lo3bits | (getRexB(pfx) << 3),
1144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        toBool(sz==1 && !haveREX(pfx)) );
1145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getIRegRexB ( Int sz, Prefix pfx, UInt lo3bits )
1148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(lo3bits < 8);
1150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
1153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 8;
1154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_64to32,
1155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Get(
1156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     toBool(sz==1 && !haveREX(pfx)) ),
1158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     szToITy(sz)
1159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 )
1160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
1161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return IRExpr_Get(
1163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                toBool(sz==1 && !haveREX(pfx)) ),
1165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                szToITy(sz)
1166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
1167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putIRegRexB ( Int sz, Prefix pfx, UInt lo3bits, IRExpr* e )
1171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(lo3bits < 8);
1173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == szToITy(sz));
1176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
1177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            offsetIReg( sz, lo3bits | (getRexB(pfx) << 3),
1178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            toBool(sz==1 && !haveREX(pfx)) ),
1179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz==4 ? unop(Iop_32Uto64,e) : e
1180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
1181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Functions for getting register numbers from modrm bytes and REX
1185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   when we don't have to consider the complexities of integer subreg
1186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   accesses.
1187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extract the g reg field from a modRM byte, and augment it using the
1189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   REX.R bit from the supplied REX byte.  The R bit usually is
1190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   associated with the g register field.
1191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt gregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int reg = (Int)( (mod_reg_rm >> 3) & 7 );
1195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reg += (pfx & PFX_REXR) ? 8 : 0;
1196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return reg;
1197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Extract the e reg field from a modRM byte, and augment it using the
1200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   REX.B bit from the supplied REX byte.  The B bit usually is
1201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   associated with the e register field (when modrm indicates e is a
1202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register, that is).
1203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt eregOfRexRM ( Prefix pfx, UChar mod_reg_rm )
1205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int rm;
1207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(mod_reg_rm));
1208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   rm = (Int)(mod_reg_rm & 0x7);
1209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   rm += (pfx & PFX_REXB) ? 8 : 0;
1210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return rm;
1211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* General functions for dealing with integer register access. */
1215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produce the guest state offset for a reference to the 'g' register
1217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   field in a modrm byte, taking into account REX (or its absence),
1218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and the size of the access.
1219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt offsetIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt reg;
1223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reg = gregOfRexRM( pfx, mod_reg_rm );
1227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
1228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* getIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
1234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 8;
1235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_64to32,
1236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              szToITy(sz) ));
1238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return IRExpr_Get( offsetIRegG( sz, pfx, mod_reg_rm ),
1240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         szToITy(sz) );
1241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid putIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
1248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
1249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = unop(Iop_32Uto64,e);
1250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( offsetIRegG( sz, pfx, mod_reg_rm ), e ) );
1252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* nameIRegG ( Int sz, Prefix pfx, UChar mod_reg_rm )
1256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( sz, gregOfRexRM(pfx,mod_reg_rm),
1258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        toBool(sz==1 && !haveREX(pfx)) );
1259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produce the guest state offset for a reference to the 'e' register
1263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   field in a modrm byte, taking into account REX (or its absence),
1264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and the size of the access.  eregOfRexRM will assert if mod_reg_rm
1265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   denotes a memory access rather than a register access.
1266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt offsetIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt reg;
1270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(IS_VALID_PFX(pfx));
1272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 8 || sz == 4 || sz == 2 || sz == 1);
1273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   reg = eregOfRexRM( pfx, mod_reg_rm );
1274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return offsetIReg( sz, reg, toBool(sz == 1 && !haveREX(pfx)) );
1275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* getIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
1281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 8;
1282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_64to32,
1283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              szToITy(sz) ));
1285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return IRExpr_Get( offsetIRegE( sz, pfx, mod_reg_rm ),
1287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         szToITy(sz) );
1288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid putIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm, IRExpr* e )
1293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == szToITy(sz));
1295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4) {
1296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e = unop(Iop_32Uto64,e);
1297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( offsetIRegE( sz, pfx, mod_reg_rm ), e ) );
1299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* nameIRegE ( Int sz, Prefix pfx, UChar mod_reg_rm )
1303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return nameIReg( sz, eregOfRexRM(pfx,mod_reg_rm),
1305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        toBool(sz==1 && !haveREX(pfx)) );
1306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- For dealing with XMM registers                       ---*/
1311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static Int segmentGuestRegOffset ( UInt sreg )
1314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
1315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    switch (sreg) {
1316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_ES: return OFFB_ES;
1317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_CS: return OFFB_CS;
1318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_SS: return OFFB_SS;
1319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_DS: return OFFB_DS;
1320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_FS: return OFFB_FS;
1321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_GS: return OFFB_GS;
1322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       default: vpanic("segmentGuestRegOffset(x86)");
1323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
1324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
1325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegOffset ( UInt xmmreg )
1327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (xmmreg) {
1329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0:  return OFFB_XMM0;
1330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:  return OFFB_XMM1;
1331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  return OFFB_XMM2;
1332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3:  return OFFB_XMM3;
1333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  return OFFB_XMM4;
1334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5:  return OFFB_XMM5;
1335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6:  return OFFB_XMM6;
1336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7:  return OFFB_XMM7;
1337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  return OFFB_XMM8;
1338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 9:  return OFFB_XMM9;
1339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 10: return OFFB_XMM10;
1340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 11: return OFFB_XMM11;
1341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 12: return OFFB_XMM12;
1342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 13: return OFFB_XMM13;
1343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 14: return OFFB_XMM14;
1344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 15: return OFFB_XMM15;
1345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("xmmGuestRegOffset(amd64)");
1346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lanes of vector registers are always numbered from zero being the
1350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   least significant lane (rightmost in the register).  */
1351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane16offset ( UInt xmmreg, Int laneno )
1353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
1355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 8);
1357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 2 * laneno;
1358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane32offset ( UInt xmmreg, Int laneno )
1361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
1363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 4);
1365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 4 * laneno;
1366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Int xmmGuestRegLane64offset ( UInt xmmreg, Int laneno )
1369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Correct for little-endian host only. */
1371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(!host_is_bigendian);
1372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(laneno >= 0 && laneno < 2);
1373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmmGuestRegOffset( xmmreg ) + 8 * laneno;
1374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static IRExpr* getSReg ( UInt sreg )
1377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
1378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return IRExpr_Get( segmentGuestRegOffset(sreg), Ity_I16 );
1379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
1380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
1381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static void putSReg ( UInt sreg, IRExpr* e )
1382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
1383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
1384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    stmt( IRStmt_Put( segmentGuestRegOffset(sreg), e ) );
1385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
1386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMReg ( UInt xmmreg )
1388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegOffset(xmmreg), Ity_V128 );
1390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
1393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
1395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
1398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
1400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
1403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
1405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
1408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
1410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getXMMRegLane16 ( UInt xmmreg, Int laneno )
1413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return IRExpr_Get( xmmGuestRegLane16offset(xmmreg,laneno), Ity_I16 );
1415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMReg ( UInt xmmreg, IRExpr* e )
1418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_V128);
1420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegOffset(xmmreg), e ) );
1421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
1424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
1426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
1430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F64);
1432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
1433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
1436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_F32);
1438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane32 ( UInt xmmreg, Int laneno, IRExpr* e )
1442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I32);
1444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane32offset(xmmreg,laneno), e ) );
1445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putXMMRegLane16 ( UInt xmmreg, Int laneno, IRExpr* e )
1448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I16);
1450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( xmmGuestRegLane16offset(xmmreg,laneno), e ) );
1451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkV128 ( UShort mask )
1454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_V128(mask));
1456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkAnd1 ( IRExpr* x, IRExpr* y )
1459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,x) == Ity_I1);
1461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,y) == Ity_I1);
1462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_64to1,
1463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64,
1464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto64,x),
1465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto64,y)));
1466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a compare-and-swap operation, operating on memory at
1469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'addr'.  The expected value is 'expVal' and the new value is
1470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'newVal'.  If the operation fails, then transfer control (with a
1471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   no-redir jump (XXX no -- see comment at top of this file)) to
1472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'restart_point', which is presumably the address of the guest
1473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction again -- retrying, essentially. */
1474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void casLE ( IRExpr* addr, IRExpr* expVal, IRExpr* newVal,
1475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Addr64 restart_point )
1476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRCAS* cas;
1478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType tyE    = typeOfIRExpr(irsb->tyenv, expVal);
1479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType tyN    = typeOfIRExpr(irsb->tyenv, newVal);
1480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldTmp = newTemp(tyE);
1481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp expTmp = newTemp(tyE);
1482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(tyE == tyN);
1483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(tyE == Ity_I64 || tyE == Ity_I32
1484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || tyE == Ity_I16 || tyE == Ity_I8);
1485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(expTmp, expVal);
1486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   cas = mkIRCAS( IRTemp_INVALID, oldTmp, Iend_LE, addr,
1487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  NULL, mkexpr(expTmp), NULL, newVal );
1488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_CAS(cas) );
1489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Exit(
1490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(tyE,Iop_CasCmpNE8),
1491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkexpr(oldTmp), mkexpr(expTmp) ),
1492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_Boring, /*Ijk_NoRedir*/
1493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRConst_U64( restart_point )
1494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
1495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Helpers for %rflags.                                 ---*/
1500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
1501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Evaluating the flags-thunk. -------------- */
1503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate all the eflags from stored
1505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
1506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I64. */
1507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_amd64g_calculate_rflags_all ( void )
1508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I64),
1511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I64,
1517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "amd64g_calculate_rflags_all", &amd64g_calculate_rflags_all,
1519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
1522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
1523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
1525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate some particular condition from stored
1528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
1529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_Bit. */
1530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_amd64g_calculate_condition ( AMD64Condcode cond )
1531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_5( mkU64(cond),
1534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_OP,   Ity_I64),
1535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I64,
1541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "amd64g_calculate_condition", &amd64g_calculate_condition,
1543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude the requested condition, OP and NDEP from definedness
1546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      checking.  We're only interested in DEP1 and DEP2. */
1547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1) | (1<<4);
1548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_64to1, call);
1549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Build IR to calculate just the carry flag from stored
1552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression :: Ity_I64. */
1553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk_amd64g_calculate_rflags_c ( void )
1554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr** args
1556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I64),
1557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP1, Ity_I64),
1558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_DEP2, Ity_I64),
1559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       IRExpr_Get(OFFB_CC_NDEP, Ity_I64) );
1560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* call
1561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = mkIRExprCCall(
1562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Ity_I64,
1563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           0/*regparm*/,
1564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           "amd64g_calculate_rflags_c", &amd64g_calculate_rflags_c,
1565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           args
1566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        );
1567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Exclude OP and NDEP from definedness checking.  We're only
1568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      interested in DEP1 and DEP2. */
1569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
1570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return call;
1571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Building the flags-thunk. -------------- */
1575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* The machinery in this section builds the flag-thunk following a
1577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   flag-setting operation.  Hence the various setFlags_* functions.
1578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isAddSub ( IROp op8 )
1581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(op8 == Iop_Add8 || op8 == Iop_Sub8);
1583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool isLogic ( IROp op8 )
1586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return toBool(op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8);
1588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* U-widen 8/16/32/64 bit int expr to 64. */
1591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* widenUto64 ( IRExpr* e )
1592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (typeOfIRExpr(irsb->tyenv,e)) {
1594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: return e;
1595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return unop(Iop_32Uto64, e);
1596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return unop(Iop_16Uto64, e);
1597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return unop(Iop_8Uto64, e);
1598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("widenUto64");
1599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* S-widen 8/16/32/64 bit int expr to 32. */
1603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* widenSto64 ( IRExpr* e )
1604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (typeOfIRExpr(irsb->tyenv,e)) {
1606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: return e;
1607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: return unop(Iop_32Sto64, e);
1608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: return unop(Iop_16Sto64, e);
1609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  return unop(Iop_8Sto64, e);
1610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("widenSto64");
1611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Narrow 8/16/32/64 bit int expr to 8/16/32/64.  Clearly only some
1615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of these combinations make sense. */
1616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* narrowTo ( IRType dst_ty, IRExpr* e )
1617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType src_ty = typeOfIRExpr(irsb->tyenv,e);
1619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == dst_ty)
1620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return e;
1621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I32 && dst_ty == Ity_I16)
1622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_32to16, e);
1623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I32 && dst_ty == Ity_I8)
1624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_32to8, e);
1625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I64 && dst_ty == Ity_I32)
1626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_64to32, e);
1627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I64 && dst_ty == Ity_I16)
1628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_64to16, e);
1629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (src_ty == Ity_I64 && dst_ty == Ity_I8)
1630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return unop(Iop_64to8, e);
1631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("\nsrc, dst tys are: ");
1633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ppIRType(src_ty);
1634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf(", ");
1635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ppIRType(dst_ty);
1636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("\n");
1637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("narrowTo(amd64)");
1638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the flags thunk OP, DEP1 and DEP2 fields.  The supplied op is
1642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   auto-sized up to the real op. */
1643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_DEP1_DEP2 ( IROp op8, IRTemp dep1, IRTemp dep2, IRType ty )
1646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = 0;
1648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  ccOp = 0; break;
1650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: ccOp = 1; break;
1651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: ccOp = 2; break;
1652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: ccOp = 3; break;
1653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
1654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op8) {
1656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Add8: ccOp += AMD64G_CC_OP_ADDB;   break;
1657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Sub8: ccOp += AMD64G_CC_OP_SUBB;   break;
1658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:       ppIROp(op8);
1659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vpanic("setFlags_DEP1_DEP2(amd64)");
1660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(ccOp)) );
1662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(dep2))) );
1664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Set the OP and DEP1 fields only, and write zero to DEP2. */
1668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_DEP1 ( IROp op8, IRTemp dep1, IRType ty )
1671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = 0;
1673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  ccOp = 0; break;
1675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: ccOp = 1; break;
1676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: ccOp = 2; break;
1677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: ccOp = 3; break;
1678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
1679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op8) {
1681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Or8:
1682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_And8:
1683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Xor8: ccOp += AMD64G_CC_OP_LOGICB; break;
1684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:       ppIROp(op8);
1685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     vpanic("setFlags_DEP1(amd64)");
1686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(ccOp)) );
1688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(dep1))) );
1689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For shift operations, we put in the result and the undershifted
1694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   result.  Except if the shift amount is zero, the thunk is left
1695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   unchanged. */
1696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_DEP1_DEP2_shift ( IROp    op64,
1698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  res,
1699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  resUS,
1700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRType  ty,
1701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       IRTemp  guard )
1702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = 0;
1704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  ccOp = 0; break;
1706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: ccOp = 1; break;
1707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: ccOp = 2; break;
1708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: ccOp = 3; break;
1709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
1710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guard);
1713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Both kinds of right shifts are handled by the same thunk
1715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      operation. */
1716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op64) {
1717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:
1718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Sar64: ccOp += AMD64G_CC_OP_SHRB; break;
1719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64: ccOp += AMD64G_CC_OP_SHLB; break;
1720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:        ppIROp(op64);
1721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      vpanic("setFlags_DEP1_DEP2_shift(amd64)");
1722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* DEP1 contains the result, DEP2 contains the undershifted value. */
1725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,
1726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( mkexpr(guard),
1727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   IRExpr_Get(OFFB_CC_OP,Ity_I64),
1728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU64(ccOp))) );
1729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
1730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( mkexpr(guard),
1731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
1732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   widenUto64(mkexpr(res)))) );
1733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2,
1734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( mkexpr(guard),
1735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
1736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   widenUto64(mkexpr(resUS)))) );
1737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* For the inc/dec case, we store in DEP1 the result value and in NDEP
1741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the former value of the carry flag, which unfortunately we have to
1742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   compute. */
1743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void setFlags_INC_DEC ( Bool inc, IRTemp res, IRType ty )
1745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int ccOp = inc ? AMD64G_CC_OP_INCB : AMD64G_CC_OP_DECB;
1747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:  ccOp += 0; break;
1750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: ccOp += 1; break;
1751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: ccOp += 2; break;
1752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: ccOp += 3; break;
1753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
1754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This has to come first, because calculating the C flag
1757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      may require reading all four thunk fields. */
1758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mk_amd64g_calculate_rflags_c()) );
1759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(ccOp)) );
1760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(res))) );
1761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0)) );
1762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
1766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   two arguments. */
1767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid setFlags_MUL ( IRType ty, IRTemp arg1, IRTemp arg2, ULong base_op )
1770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
1772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8:
1773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+0) ) );
1774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16:
1776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+1) ) );
1777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32:
1779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+2) ) );
1780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64:
1782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP, mkU64(base_op+3) ) );
1783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
1784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
1785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("setFlags_MUL(amd64)");
1786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(arg1)) ));
1788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(mkexpr(arg2)) ));
1789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Condition codes. -------------- */
1793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Condition codes, using the AMD encoding.  */
1795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* name_AMD64Condcode ( AMD64Condcode cond )
1797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (cond) {
1799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondO:      return "o";
1800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNO:     return "no";
1801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondB:      return "b";
1802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNB:     return "ae"; /*"nb";*/
1803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondZ:      return "e"; /*"z";*/
1804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNZ:     return "ne"; /*"nz";*/
1805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondBE:     return "be";
1806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNBE:    return "a"; /*"nbe";*/
1807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondS:      return "s";
1808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNS:     return "ns";
1809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondP:      return "p";
1810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNP:     return "np";
1811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondL:      return "l";
1812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNL:     return "ge"; /*"nl";*/
1813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondLE:     return "le";
1814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondNLE:    return "g"; /*"nle";*/
1815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case AMD64CondAlways: return "ALWAYS";
1816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("name_AMD64Condcode");
1817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
1821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownAMD64Condcode positiveIse_AMD64Condcode ( AMD64Condcode  cond,
1822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          /*OUT*/Bool*   needInvert )
1823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(cond >= AMD64CondO && cond <= AMD64CondNLE);
1825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cond & 1) {
1826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needInvert = True;
1827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cond-1;
1828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
1829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needInvert = False;
1830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return cond;
1831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Helpers for ADD/SUB with carry. -------------- */
1836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given ta1, ta2 and tres, compute tres = ADC(ta1,ta2) and set flags
1838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appropriately.
1839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Optionally, generate a store for the 'tres' value.  This can either
1841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   be a normal store, or it can be a cas-with-possible-failure style
1842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   store:
1843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if taddr is IRTemp_INVALID, then no store is generated.
1845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if taddr is not IRTemp_INVALID, then a store (using taddr as
1847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address) is generated:
1848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if texpVal is IRTemp_INVALID then a normal store is
1850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generated, and restart_point must be zero (it is irrelevant).
1851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if texpVal is not IRTemp_INVALID then a cas-style store is
1853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     generated.  texpVal is the expected value, restart_point
1854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     is the restart point if the store fails, and texpVal must
1855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     have the same type as tres.
1856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void helper_ADC ( Int sz,
1859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /* info about optional store: */
1861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    thunkOp;
1864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty    = szToITy(sz);
1865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldc  = newTemp(Ity_I64);
1866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldcn = newTemp(ty);
1867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    plus  = mkSizedOp(ty, Iop_Add8);
1868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
1869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
1873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  thunkOp = AMD64G_CC_OP_ADCQ; break;
1874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  thunkOp = AMD64G_CC_OP_ADCL; break;
1875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  thunkOp = AMD64G_CC_OP_ADCW; break;
1876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:  thunkOp = AMD64G_CC_OP_ADCB; break;
1877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
1878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* oldc = old carry flag, 0 or 1 */
1881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldc,  binop(Iop_And64,
1882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mk_amd64g_calculate_rflags_c(),
1883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU64(1)) );
1884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tres, binop(plus,
1888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(plus,mkexpr(ta1),mkexpr(ta2)),
1889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(oldcn)) );
1890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start of this function. */
1893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (taddr != IRTemp_INVALID) {
1894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (texpVal == IRTemp_INVALID) {
1895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(restart_point == 0);
1896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(taddr), mkexpr(tres) );
1897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and hence 'texpVal' has the same type as 'tres'. */
1900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(taddr),
1901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(texpVal), mkexpr(tres), restart_point );
1902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(thunkOp) ) );
1906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1))  ));
1907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(oldcn)) )) );
1909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given ta1, ta2 and tres, compute tres = SBB(ta1,ta2) and set flags
1914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   appropriately.  As with helper_ADC, possibly generate a store of
1915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the result -- see comments on helper_ADC for details.
1916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
1917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void helper_SBB ( Int sz,
1918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp tres, IRTemp ta1, IRTemp ta2,
1919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         /* info about optional store: */
1920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRTemp taddr, IRTemp texpVal, Addr32 restart_point )
1921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt    thunkOp;
1923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty    = szToITy(sz);
1924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldc  = newTemp(Ity_I64);
1925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldcn = newTemp(ty);
1926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    minus = mkSizedOp(ty, Iop_Sub8);
1927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    xor   = mkSizedOp(ty, Iop_Xor8);
1928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, tres) == ty);
1930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
1932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  thunkOp = AMD64G_CC_OP_SBBQ; break;
1933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  thunkOp = AMD64G_CC_OP_SBBL; break;
1934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  thunkOp = AMD64G_CC_OP_SBBW; break;
1935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1:  thunkOp = AMD64G_CC_OP_SBBB; break;
1936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
1937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* oldc = old carry flag, 0 or 1 */
1940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldc, binop(Iop_And64,
1941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mk_amd64g_calculate_rflags_c(),
1942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU64(1)) );
1943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldcn, narrowTo(ty, mkexpr(oldc)) );
1945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tres, binop(minus,
1947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(minus,mkexpr(ta1),mkexpr(ta2)),
1948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(oldcn)) );
1949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Possibly generate a store of 'tres' to 'taddr'.  See comment at
1951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      start of this function. */
1952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (taddr != IRTemp_INVALID) {
1953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (texpVal == IRTemp_INVALID) {
1954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(restart_point == 0);
1955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(taddr), mkexpr(tres) );
1956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
1957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(typeOfIRTemp(irsb->tyenv, texpVal) == ty);
1958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* .. and hence 'texpVal' has the same type as 'tres'. */
1959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(taddr),
1960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(texpVal), mkexpr(tres), restart_point );
1961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
1962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
1963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(thunkOp) ) );
1965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto64(mkexpr(ta1) )) );
1966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto64(binop(xor, mkexpr(ta2),
1967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                         mkexpr(oldcn)) )) );
1968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(oldc) ) );
1969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* -------------- Helpers for disassembly printing. -------------- */
1973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp1 ( Int opc_aux )
1975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp1_names[8]
1977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" };
1978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp1(amd64)");
1979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp1_names[opc_aux];
1980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp2 ( Int opc_aux )
1983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp2_names[8]
1985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "rol", "ror", "rcl", "rcr", "shl", "shr", "shl", "sar" };
1986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 7) vpanic("nameGrp2(amd64)");
1987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp2_names[opc_aux];
1988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp4 ( Int opc_aux )
1991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
1992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp4_names[8]
1993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "inc", "dec", "???", "???", "???", "???", "???", "???" };
1994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 1) vpanic("nameGrp4(amd64)");
1995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp4_names[opc_aux];
1996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
1997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
1998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp5 ( Int opc_aux )
1999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp5_names[8]
2001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "inc", "dec", "call*", "call*", "jmp*", "jmp*", "push", "???" };
2002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 0 || opc_aux > 6) vpanic("nameGrp5(amd64)");
2003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp5_names[opc_aux];
2004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameGrp8 ( Int opc_aux )
2007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* grp8_names[8]
2009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = { "???", "???", "???", "???", "bt", "bts", "btr", "btc" };
2010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (opc_aux < 4 || opc_aux > 7) vpanic("nameGrp8(amd64)");
2011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return grp8_names[opc_aux];
2012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static HChar* nameSReg ( UInt sreg )
2015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
2016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    switch (sreg) {
2017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_ES: return "%es";
2018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_CS: return "%cs";
2019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_SS: return "%ss";
2020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_DS: return "%ds";
2021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_FS: return "%fs";
2022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case R_GS: return "%gs";
2023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       default: vpanic("nameSReg(x86)");
2024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
2025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
2026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameMMXReg ( Int mmxreg )
2028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* mmx_names[8]
2030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%mm0", "%mm1", "%mm2", "%mm3", "%mm4", "%mm5", "%mm6", "%mm7" };
2031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (mmxreg < 0 || mmxreg > 7) vpanic("nameMMXReg(amd64,guest)");
2032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mmx_names[mmxreg];
2033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameXMMReg ( Int xmmreg )
2036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   static HChar* xmm_names[16]
2038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     = { "%xmm0",  "%xmm1",  "%xmm2",  "%xmm3",
2039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%xmm4",  "%xmm5",  "%xmm6",  "%xmm7",
2040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%xmm8",  "%xmm9",  "%xmm10", "%xmm11",
2041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         "%xmm12", "%xmm13", "%xmm14", "%xmm15" };
2042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (xmmreg < 0 || xmmreg > 15) vpanic("nameXMMReg(amd64)");
2043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return xmm_names[xmmreg];
2044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameMMXGran ( Int gran )
2047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gran) {
2049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: return "b";
2050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return "w";
2051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return "d";
2052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: return "q";
2053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameMMXGran(amd64,guest)");
2054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar nameISize ( Int size )
2058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (size) {
2060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8: return 'q';
2061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: return 'l';
2062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: return 'w';
2063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: return 'b';
2064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameISize(amd64)");
2065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- JMP helpers                                          ---*/
2071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void jmp_lit( IRJumpKind kind, Addr64 d64 )
2074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->next     = mkU64(d64);
2076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->jumpkind = kind;
2077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void jmp_treg( IRJumpKind kind, IRTemp t )
2080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->next     = mkexpr(t);
2082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb->jumpkind = kind;
2083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid jcc_01 ( AMD64Condcode cond, Addr64 d64_false, Addr64 d64_true )
2087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool          invert;
2089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AMD64Condcode condPos;
2090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   condPos = positiveIse_AMD64Condcode ( cond, &invert );
2091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (invert) {
2092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
2094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRConst_U64(d64_false) ) );
2095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = mkU64(d64_true);
2096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = Ijk_Boring;
2097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_amd64g_calculate_condition(condPos),
2099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
2100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRConst_U64(d64_true) ) );
2101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = mkU64(d64_false);
2102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = Ijk_Boring;
2103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Let new_rsp be the %rsp value after a call/return.  Let nia be the
2107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest address of the next instruction to be executed.
2108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This function generates an AbiHint to say that -128(%rsp)
2110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   .. -1(%rsp) should now be regarded as uninitialised.
2111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid make_redzone_AbiHint ( VexAbiInfo* vbi,
2114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            IRTemp new_rsp, IRTemp nia, HChar* who )
2115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int szB = vbi->guest_stack_redzone_size;
2117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(szB >= 0);
2118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* A bit of a kludge.  Currently the only AbI we've guested AMD64
2120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for is ELF.  So just check it's the expected 128 value
2121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (paranoia). */
2122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(szB == 128);
2123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (0) vex_printf("AbiHint: %s\n", who);
2125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, new_rsp) == Ity_I64);
2126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRTemp(irsb->tyenv, nia) == Ity_I64);
2127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (szB > 0)
2128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_AbiHint(
2129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Sub64, mkexpr(new_rsp), mkU64(szB)),
2130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               szB,
2131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(nia)
2132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ));
2133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling addressing modes                       ---*/
2138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownHChar* segRegTxt ( Prefix pfx )
2142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_CS) return "%cs:";
2144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_DS) return "%ds:";
2145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_ES) return "%es:";
2146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_FS) return "%fs:";
2147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_GS) return "%gs:";
2148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_SS) return "%ss:";
2149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return ""; /* no override */
2150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* 'virtual' is an IRExpr* holding a virtual address.  Convert it to a
2154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   linear address by adding any required segment override as indicated
2155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by sorb, and also dealing with any address size override
2156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   present. */
2157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* handleAddrOverrides ( VexAbiInfo* vbi,
2159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              Prefix pfx, IRExpr* virtual )
2160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- segment overrides --- */
2162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_FS) {
2163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vbi->guest_amd64_assume_fs_is_zero) {
2164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Note that this is a linux-kernel specific hack that relies
2165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            on the assumption that %fs is always zero. */
2166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* return virtual + guest_FS_ZERO. */
2167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         virtual = binop(Iop_Add64, virtual,
2168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    IRExpr_Get(OFFB_FS_ZERO, Ity_I64));
2169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unimplemented("amd64 %fs segment override");
2171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_GS) {
2175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vbi->guest_amd64_assume_gs_is_0x60) {
2176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Note that this is a darwin-kernel specific hack that relies
2177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            on the assumption that %gs is always 0x60. */
2178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* return virtual + guest_GS_0x60. */
2179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         virtual = binop(Iop_Add64, virtual,
2180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    IRExpr_Get(OFFB_GS_0x60, Ity_I64));
2181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unimplemented("amd64 %gs segment override");
2183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* cs, ds, es and ss are simply ignored in 64-bit mode. */
2187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- address size override --- */
2189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveASO(pfx))
2190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      virtual = unop(Iop_32Uto64, unop(Iop_64to32, virtual));
2191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return virtual;
2193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
2196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Int    sreg;
2197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    IRType hWordTy;
2198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    IRTemp ldt_ptr, gdt_ptr, seg_selector, r64;
2199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (sorb == 0)
2201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* the common case - no override */
2202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return virtual;
2203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    switch (sorb) {
2205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0x3E: sreg = R_DS; break;
2206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0x26: sreg = R_ES; break;
2207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0x64: sreg = R_FS; break;
2208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0x65: sreg = R_GS; break;
2209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       default: vpanic("handleAddrOverrides(x86,guest)");
2210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
2211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    hWordTy = sizeof(HWord)==4 ? Ity_I32 : Ity_I64;
2213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    seg_selector = newTemp(Ity_I32);
2215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    ldt_ptr      = newTemp(hWordTy);
2216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    gdt_ptr      = newTemp(hWordTy);
2217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    r64          = newTemp(Ity_I64);
2218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    assign( seg_selector, unop(Iop_16Uto32, getSReg(sreg)) );
2220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    assign( ldt_ptr, IRExpr_Get( OFFB_LDT, hWordTy ));
2221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    assign( gdt_ptr, IRExpr_Get( OFFB_GDT, hWordTy ));
2222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /*
2224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Call this to do the translation and limit checks:
2225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    ULong x86g_use_seg_selector ( HWord ldt, HWord gdt,
2226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                  UInt seg_selector, UInt virtual_addr )
2227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    */
2228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    assign(
2229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       r64,
2230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       mkIRExprCCall(
2231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          Ity_I64,
2232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          0/*regparms*/,
2233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          "x86g_use_seg_selector",
2234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          &x86g_use_seg_selector,
2235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          mkIRExprVec_4( mkexpr(ldt_ptr), mkexpr(gdt_ptr),
2236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                         mkexpr(seg_selector), virtual)
2237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       )
2238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    );
2239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* If the high 32 of the result are non-zero, there was a
2241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       failure in address translation.  In which case, make a
2242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       quick exit.
2243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    */
2244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    stmt(
2245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       IRStmt_Exit(
2246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
2247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          Ijk_MapFail,
2248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          IRConst_U32( guest_eip_curr_instr )
2249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       )
2250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    );
2251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
2252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* otherwise, here's the translated result. */
2253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    return unop(Iop_64to32, mkexpr(r64));
2254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
2255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate IR to calculate an address indicated by a ModRM and
2258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   following SIB bytes.  The expression, and the number of bytes in
2259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address mode, are returned (the latter in *len).  Note that
2260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   this fn should not be called if the R/M part of the address denotes
2261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   a register instead of memory.  If print_codegen is true, text of
2262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the addressing mode is placed in buf.
2263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   The computed address is stored in a new tempreg, and the
2265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   identity of the tempreg is returned.
2266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   extra_bytes holds the number of bytes after the amode, as supplied
2268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   by the caller.  This is needed to make sense of %rip-relative
2269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addresses.  Note that the value that *len is set to is only the
2270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   length of the amode itself and does not include the value supplied
2271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   in extra_bytes.
2272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
2273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp disAMode_copy2tmp ( IRExpr* addr64 )
2275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmp = newTemp(Ity_I64);
2277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmp, addr64 );
2278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return tmp;
2279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRTemp disAMode ( /*OUT*/Int* len,
2283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  VexAbiInfo* vbi, Prefix pfx, Long delta,
2284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*OUT*/HChar* buf, Int extra_bytes )
2285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar mod_reg_rm = getUChar(delta);
2287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
2288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   buf[0] = (UChar)0;
2290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(extra_bytes >= 0 && extra_bytes < 10);
2291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jump table seems a bit excessive.
2294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
2295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0xC7;                         /* is now XX000YYY */
2296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* is now XX0XXYYY */
2298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0x1F;                         /* is now 000XXYYY */
2299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (mod_reg_rm) {
2300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         REX.B==1: (%r8)  .. (%r15), not including (%r12) or (%r13).
2303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x02: case 0x03:
2305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
2306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
2307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
2308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 1;
2309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
2310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleAddrOverrides(vbi, pfx, getIRegRexB(8,pfx,rm)));
2311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         REX.B==1: d8(%r8)  ... d8(%r15), not including d8(%r12)
2315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x08: case 0x09: case 0x0A: case 0x0B:
2317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
2318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
2319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Long d   = getSDisp8(delta);
2320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           if (d == 0) {
2321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,rm));
2322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           } else {
2323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
2324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           }
2325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 2;
2326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
2327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleAddrOverrides(vbi, pfx,
2328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
2329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         REX.B==1: d32(%r8)  ... d32(%r15), not including d32(%r12)
2333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x12: case 0x13:
2335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 14 */ case 0x15: case 0x16: case 0x17:
2336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { UChar rm = toUChar(mod_reg_rm & 7);
2337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           Long  d  = getSDisp32(delta);
2338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s%lld(%s)", segRegTxt(pfx), d, nameIRegRexB(8,pfx,rm));
2339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 5;
2340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
2341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  handleAddrOverrides(vbi, pfx,
2342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Add64,getIRegRexB(8,pfx,rm),mkU64(d))));
2343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: a register, %rax .. %rdi.  This shouldn't happen. */
2346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==1: a register, %r8  .. %r16.  This shouldn't happen. */
2347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x18: case 0x19: case 0x1A: case 0x1B:
2348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("disAMode(amd64): not an addr!");
2350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* RIP + disp32.  This assumes that guest_RIP_curr_instr is set
2352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         correctly at the start of handling each instruction. */
2353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05:
2354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         { Long d = getSDisp32(delta);
2355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           *len = 5;
2356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           DIS(buf, "%s%lld(%%rip)", segRegTxt(pfx), d);
2357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           /* We need to know the next instruction's start address.
2358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              Try and figure out what it is, record the guess, and ask
2359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              the top-level driver logic (bbToIR_AMD64) to check we
2360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              guessed right, after the instruction is completely
2361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              decoded. */
2362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           guest_RIP_next_mustcheck = True;
2363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           guest_RIP_next_assumed = guest_RIP_bbstart
2364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    + delta+4 + extra_bytes;
2365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           return disAMode_copy2tmp(
2366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     handleAddrOverrides(vbi, pfx,
2367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add64, mkU64(guest_RIP_next_assumed),
2368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU64(d))));
2369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x04: {
2372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* SIB, with no displacement.  Special cases:
2373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            -- %rsp cannot act as an index value.
2374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               If index_r indicates %rsp, zero is used for the index.
2375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            -- when mod is zero and base indicates RBP or R13, base is
2376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               instead a 32-bit sign-extended literal.
2377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            It's all madness, I tell you.  Extract %index, %base and
2378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            scale from the SIB byte.  The value denoted is then:
2379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index == %RSP && (%base == %RBP || %base == %R13)
2380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = d32 following SIB byte
2381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index == %RSP && !(%base == %RBP || %base == %R13)
2382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = %base
2383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index != %RSP && (%base == %RBP || %base == %R13)
2384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = d32 following SIB byte + (%index << scale)
2385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               | %index != %RSP && !(%base == %RBP || %base == %R13)
2386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               = %base + (%index << scale)
2387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
2388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getUChar(delta);
2389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
2390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
2391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
2392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* correct since #(R13) == 8 + #(RBP) */
2393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool  base_is_BPor13 = toBool(base_r == R_RBP);
2394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool  index_is_SP    = toBool(index_r == R_RSP && 0==getRexX(pfx));
2395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
2396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((!index_is_SP) && (!base_is_BPor13)) {
2398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (scale == 0) {
2399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIS(buf, "%s(%s,%s)", segRegTxt(pfx),
2400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIRegRexB(8,pfx,base_r),
2401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIReg64rexX(pfx,index_r));
2402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIS(buf, "%s(%s,%s,%d)", segRegTxt(pfx),
2404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIRegRexB(8,pfx,base_r),
2405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIReg64rexX(pfx,index_r), 1<<scale);
2406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 2;
2408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
2409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               disAMode_copy2tmp(
2410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               handleAddrOverrides(vbi, pfx,
2411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add64,
2412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIRegRexB(8,pfx,base_r),
2413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
2414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU8(scale)))));
2415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if ((!index_is_SP) && base_is_BPor13) {
2418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Long d = getSDisp32(delta);
2419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%lld(,%s,%d)", segRegTxt(pfx), d,
2420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIReg64rexX(pfx,index_r), 1<<scale);
2421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
2422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
2423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               disAMode_copy2tmp(
2424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               handleAddrOverrides(vbi, pfx,
2425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add64,
2426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, getIReg64rexX(pfx,index_r),
2427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(scale)),
2428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU64(d))));
2429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_is_SP && (!base_is_BPor13)) {
2432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s(%s)", segRegTxt(pfx), nameIRegRexB(8,pfx,base_r));
2433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 2;
2434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
2435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleAddrOverrides(vbi, pfx, getIRegRexB(8,pfx,base_r)));
2436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_is_SP && base_is_BPor13) {
2439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Long d = getSDisp32(delta);
2440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%lld", segRegTxt(pfx), d);
2441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
2442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
2443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleAddrOverrides(vbi, pfx, mkU64(d)));
2444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
2447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 8-bit displacement.  Special cases:
2450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         -- %esp cannot act as an index value.
2451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If index_r indicates %esp, zero is used for the index.
2452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Denoted value is:
2453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index == %ESP
2454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d8 + %base
2455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index != %ESP
2456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d8 + %base + (%index << scale)
2457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0C: {
2459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getUChar(delta);
2460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
2461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
2462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
2463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Long d        = getSDisp8(delta+1);
2464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_RSP && 0==getRexX(pfx)) {
2466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
2467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   d, nameIRegRexB(8,pfx,base_r));
2468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 3;
2469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
2470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleAddrOverrides(vbi, pfx,
2471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
2472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (scale == 0) {
2474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
2475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIRegRexB(8,pfx,base_r),
2476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIReg64rexX(pfx,index_r));
2477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
2479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIRegRexB(8,pfx,base_r),
2480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIReg64rexX(pfx,index_r), 1<<scale);
2481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 3;
2483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
2484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                disAMode_copy2tmp(
2485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleAddrOverrides(vbi, pfx,
2486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add64,
2487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add64,
2488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIRegRexB(8,pfx,base_r),
2489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl64,
2490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getIReg64rexX(pfx,index_r), mkU8(scale))),
2491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU64(d))));
2492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0); /*NOTREACHED*/
2494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 32-bit displacement.  Special cases:
2497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         -- %rsp cannot act as an index value.
2498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            If index_r indicates %rsp, zero is used for the index.
2499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Denoted value is:
2500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index == %RSP
2501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d32 + %base
2502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            | %index != %RSP
2503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            = d32 + %base + (%index << scale)
2504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x14: {
2506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getUChar(delta);
2507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar scale   = toUChar((sib >> 6) & 3);
2508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar index_r = toUChar((sib >> 3) & 7);
2509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
2510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Long d        = getSDisp32(delta+1);
2511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (index_r == R_RSP && 0==getRexX(pfx)) {
2513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIS(buf, "%s%lld(%s)", segRegTxt(pfx),
2514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   d, nameIRegRexB(8,pfx,base_r));
2515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
2516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return disAMode_copy2tmp(
2517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   handleAddrOverrides(vbi, pfx,
2518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Add64, getIRegRexB(8,pfx,base_r), mkU64(d)) ));
2519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (scale == 0) {
2521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIS(buf, "%s%lld(%s,%s)", segRegTxt(pfx), d,
2522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIRegRexB(8,pfx,base_r),
2523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIReg64rexX(pfx,index_r));
2524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIS(buf, "%s%lld(%s,%s,%d)", segRegTxt(pfx), d,
2526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIRegRexB(8,pfx,base_r),
2527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         nameIReg64rexX(pfx,index_r), 1<<scale);
2528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *len = 6;
2530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return
2531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                disAMode_copy2tmp(
2532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                handleAddrOverrides(vbi, pfx,
2533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Add64,
2534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Add64,
2535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              getIRegRexB(8,pfx,base_r),
2536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl64,
2537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    getIReg64rexX(pfx,index_r), mkU8(scale))),
2538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU64(d))));
2539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0); /*NOTREACHED*/
2541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("disAMode(amd64)");
2545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0; /*notreached*/
2546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Figure out the number of (insn-stream) bytes constituting the amode
2551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   beginning at delta.  Is useful for getting hold of literals beyond
2552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the end of the amode before it has been disassembled.  */
2553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic UInt lengthAMode ( Prefix pfx, Long delta )
2555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar mod_reg_rm = getUChar(delta);
2557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
2558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* squeeze out the reg field from mod_reg_rm, since a 256-entry
2560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jump table seems a bit excessive.
2561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
2562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0xC7;                         /* is now XX000YYY */
2563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm  = toUChar(mod_reg_rm | (mod_reg_rm >> 3));
2564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               /* is now XX0XXYYY */
2565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   mod_reg_rm &= 0x1F;                         /* is now 000XXYYY */
2566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (mod_reg_rm) {
2567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: (%rax) .. (%rdi), not including (%rsp) or (%rbp).
2569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         REX.B==1: (%r8)  .. (%r15), not including (%r12) or (%r13).
2570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x02: case 0x03:
2572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 04 */ /* ! 05 */ case 0x06: case 0x07:
2573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 1;
2574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: d8(%rax) ... d8(%rdi), not including d8(%rsp)
2576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         REX.B==1: d8(%r8)  ... d8(%r15), not including d8(%r12)
2577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x08: case 0x09: case 0x0A: case 0x0B:
2579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 0C */ case 0x0D: case 0x0E: case 0x0F:
2580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 2;
2581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: d32(%rax) ... d32(%rdi), not including d32(%rsp)
2583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         REX.B==1: d32(%r8)  ... d32(%r15), not including d32(%r12)
2584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
2585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x12: case 0x13:
2586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ! 14 */ case 0x15: case 0x16: case 0x17:
2587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 5;
2588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==0: a register, %rax .. %rdi.  This shouldn't happen. */
2590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* REX.B==1: a register, %r8  .. %r16.  This shouldn't happen. */
2591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Not an address, but still handled. */
2592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x18: case 0x19: case 0x1A: case 0x1B:
2593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1C: case 0x1D: case 0x1E: case 0x1F:
2594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 1;
2595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* RIP + disp32. */
2597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05:
2598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 5;
2599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x04: {
2601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* SIB, with no displacement. */
2602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar sib     = getUChar(delta);
2603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar base_r  = toUChar(sib & 7);
2604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* correct since #(R13) == 8 + #(RBP) */
2605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool  base_is_BPor13 = toBool(base_r == R_RBP);
2606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (base_is_BPor13) {
2608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return 6;
2609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return 2;
2611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 8-bit displacement. */
2615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0C:
2616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 3;
2617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* SIB, with 32-bit displacement. */
2619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x14:
2620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 6;
2621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
2623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("lengthAMode(amd64)");
2624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return 0; /*notreached*/
2625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling common idioms                          ---*/
2631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
2632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle binary integer instructions of the form
2634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op E, G  meaning
2635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op reg-or-mem, reg
2636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, the actual operation, and the
2637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   data size.  Returns the address advanced completely over this
2638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction.
2639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
2641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
2642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %G,  tmp
2644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %E,   tmp
2645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %G
2646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem and OP is not reversible,
2648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                -->    (getAddr E) -> tmpa
2649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpa
2650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmp2
2651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP tmpa, tmp2
2652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp2, %G
2653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem and OP is reversible
2655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                -->    (getAddr E) -> tmpa
2656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpa
2657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G, tmpa
2658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpa, %G
2659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_op2_E_G ( VexAbiInfo* vbi,
2662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Prefix      pfx,
2663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool        addSubCarry,
2664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IROp        op8,
2665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool        keep,
2666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         size,
2667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Long        delta0,
2668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    HChar*      t_amd64opc )
2669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
2671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
2672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(size);
2673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
2674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
2675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
2676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta0);
2677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
2678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* addSubCarry == True indicates the intended operation is
2680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add-with-carry or subtract-with-borrow. */
2681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addSubCarry) {
2682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(keep);
2684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Specially handle XOR reg,reg, because that doesn't really
2688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depend on reg, and doing the obvious thing potentially
2689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates a spurious value check failure due to the bogus
2690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dependency. */
2691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (False && op8 == Iop_Sub8)
2694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
2695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 putIRegG(size,pfx,rm, mkU(ty,0));
2696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst0, getIRegG(size,pfx,rm) );
2699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src,  getIRegE(size,pfx,rm) );
2700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
2702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
2703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegG(size, pfx, rm, mkexpr(dst1));
2705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
2707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
2708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegG(size, pfx, rm, mkexpr(dst1));
2710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
2717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegG(size, pfx, rm, mkexpr(dst1));
2718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
2721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIRegE(size,pfx,rm),
2722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIRegG(size,pfx,rm));
2723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
2725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* E refers to memory */
2726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
2727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst0, getIRegG(size,pfx,rm) );
2728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src,  loadLE(szToITy(size), mkexpr(addr)) );
2729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
2731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
2732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegG(size, pfx, rm, mkexpr(dst1));
2734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
2736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
2737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegG(size, pfx, rm, mkexpr(dst1));
2739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
2741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
2746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegG(size, pfx, rm, mkexpr(dst1));
2747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
2750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          dis_buf, nameIRegG(size, pfx, rm));
2751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle binary integer instructions of the form
2758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op G, E  meaning
2759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      op reg, reg-or-mem
2760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, the actual operation, and the
2761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   data size.  Returns the address advanced completely over this
2762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   instruction.
2763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(src) is reg.
2765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(dst) is reg-or-mem
2766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E,  tmp
2768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G,   tmp
2769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %E
2770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem, -->    (getAddr E) -> tmpa
2772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpv
2773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       OP %G, tmpv
2774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ST tmpv, (tmpa)
2775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_op2_G_E ( VexAbiInfo* vbi,
2778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Prefix      pfx,
2779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool        addSubCarry,
2780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    IROp        op8,
2781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Bool        keep,
2782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         size,
2783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Long        delta0,
2784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    HChar*      t_amd64opc )
2785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
2787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
2788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(size);
2789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
2790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
2791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
2792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta0);
2793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
2794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* addSubCarry == True indicates the intended operation is
2796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      add-with-carry or subtract-with-borrow. */
2797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (addSubCarry) {
2798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(op8 == Iop_Add8 || op8 == Iop_Sub8);
2799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(keep);
2800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Specially handle XOR reg,reg, because that doesn't really
2804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         depend on reg, and doing the obvious thing potentially
2805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         generates a spurious value check failure due to the bogus
2806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dependency.  Ditto SBB reg,reg. */
2807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
2808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
2809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(size,pfx,rm, mkU(ty,0));
2810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIRegE(size,pfx,rm));
2813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  getIRegG(size,pfx,rm));
2814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
2816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( size, dst1, dst0, src,
2817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(size, pfx, rm, mkexpr(dst1));
2819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
2821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( size, dst1, dst0, src,
2822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
2823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(size, pfx, rm, mkexpr(dst1));
2824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep)
2831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(size, pfx, rm, mkexpr(dst1));
2832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
2835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIRegG(size,pfx,rm),
2836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIRegE(size,pfx,rm));
2837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
2843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
2844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  getIRegG(size,pfx,rm));
2845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Add8) {
2847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pfx & PFX_LOCK) {
2848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( size, dst1, dst0, src,
2850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
2851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( size, dst1, dst0, src,
2854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
2857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (addSubCarry && op8 == Iop_Sub8) {
2858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pfx & PFX_LOCK) {
2859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
2860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( size, dst1, dst0, src,
2861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
2862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
2863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
2864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( size, dst1, dst0, src,
2865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
2866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
2868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
2869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (keep) {
2870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
2871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("locked case\n" );
2872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
2873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(dst0)/*expval*/,
2874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(dst1)/*newval*/, guest_RIP_curr_instr );
2875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
2876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (0) vex_printf("nonlocked case\n");
2877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), mkexpr(dst1));
2878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
2879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
2880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
2881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
2882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
2883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
2884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
2885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s,%s\n", t_amd64opc, nameISize(size),
2887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          nameIRegG(size,pfx,rm), dis_buf);
2888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle move instructions of the form
2894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov E, G  meaning
2895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov reg-or-mem, reg
2896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, and the data size.  Returns
2897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address advanced completely over this instruction.
2898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
2900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
2901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E,  tmpv
2903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpv, %G
2904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem  -->    (getAddr E) -> tmpa
2906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmpb
2907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpb, %G
2908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_mov_E_G ( VexAbiInfo* vbi,
2911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Prefix      pfx,
2912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         size,
2913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Long        delta0 )
2914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
2916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getUChar(delta0);
2917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(size, pfx, rm, getIRegE(size, pfx, rm));
2921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIRegE(size,pfx,rm),
2923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIRegG(size,pfx,rm));
2924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
2930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(size, pfx, rm, loadLE(szToITy(size), mkexpr(addr)));
2931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           dis_buf,
2933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIRegG(size,pfx,rm));
2934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta0+len;
2935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle move instructions of the form
2940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov G, E  meaning
2941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mov reg, reg-or-mem
2942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Is passed the a ptr to the modRM byte, and the data size.  Returns
2943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the address advanced completely over this instruction.
2944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(src) is reg.
2946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(dst) is reg-or-mem
2947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %G,  tmp
2949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmp, %E
2950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem, -->    (getAddr E) -> tmpa
2952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpv
2953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ST tmpv, (tmpa)
2954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
2955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_mov_G_E ( VexAbiInfo* vbi,
2957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Prefix      pfx,
2958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         size,
2959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Long        delta0 )
2960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
2962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getUChar(delta0);
2963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
2964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
2966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegE(size, pfx, rm, getIRegG(size, pfx, rm));
2967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIRegG(size,pfx,rm),
2969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIRegE(size,pfx,rm));
2970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
2971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
2974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
2975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
2976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getIRegG(size, pfx, rm) );
2977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s,%s\n", nameISize(size),
2978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIRegG(size,pfx,rm),
2979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           dis_buf);
2980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
2981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
2982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
2983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
2985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* op $immediate, AL/AX/EAX/RAX. */
2986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
2987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_op_imm_A ( Int    size,
2988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Bool   carrying,
2989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IROp   op8,
2990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Bool   keep,
2991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Long   delta,
2992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     HChar* t_amd64opc )
2993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
2994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    size4 = imin(size,4);
2995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(size);
2996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst0  = newTemp(ty);
2997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src   = newTemp(ty);
2998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1  = newTemp(ty);
2999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long  lit    = getSDisp(size4,delta);
3000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(dst0, getIRegRAX(size));
3001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src,  mkU(ty,lit & mkSizeMask(size)));
3002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isAddSub(op8) && !carrying) {
3004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
3005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(op8, dst0, src, ty);
3006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isLogic(op8)) {
3009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!carrying);
3010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)) );
3011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1(op8, dst1, ty);
3012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op8 == Iop_Add8 && carrying) {
3015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      helper_ADC( size, dst1, dst0, src,
3016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
3017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op8 == Iop_Sub8 && carrying) {
3020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      helper_SBB( size, dst1, dst0, src,
3021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
3022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("dis_op_imm_A(amd64,guest)");
3025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (keep)
3027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRAX(size, mkexpr(dst1));
3028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c $%lld, %s\n", t_amd64opc, nameISize(size),
3030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           lit, nameIRegRAX(size));
3031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta+size4;
3032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Sign- and Zero-extending moves. */
3036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_movx_E_G ( VexAbiInfo* vbi,
3038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Prefix pfx,
3039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Long delta, Int szs, Int szd, Bool sign_extend )
3040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getUChar(delta);
3042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
3043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(szd, pfx, rm,
3044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    doScalarWidening(
3045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       szs,szd,sign_extend,
3046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       getIRegE(szs,pfx,rm)));
3047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
3048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szs),
3049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szd),
3050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegE(szs,pfx,rm),
3051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegG(szd,pfx,rm));
3052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta;
3053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
3056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
3057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
3058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar  dis_buf[50];
3059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
3060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(szd, pfx, rm,
3061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    doScalarWidening(
3062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       szs,szd,sign_extend,
3063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       loadLE(szToITy(szs),mkexpr(addr))));
3064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c%c%c %s,%s\n", sign_extend ? 's' : 'z',
3065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szs),
3066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameISize(szd),
3067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf,
3068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegG(szd,pfx,rm));
3069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta;
3070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate code to divide ArchRegs RDX:RAX / EDX:EAX / DX:AX / AX by
3075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the 64 / 32 / 16 / 8 bit quantity in the given IRTemp.  */
3076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_div ( Int sz, IRTemp t, Bool signed_divide )
3078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* special-case the 64-bit case */
3080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8) {
3081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   op     = signed_divide ? Iop_DivModS128to64
3082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    : Iop_DivModU128to64;
3083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src128 = newTemp(Ity_I128);
3084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst128 = newTemp(Ity_I128);
3085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src128, binop(Iop_64HLto128,
3086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            getIReg64(R_RDX),
3087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            getIReg64(R_RAX)) );
3088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst128, binop(op, mkexpr(src128), mkexpr(t)) );
3089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64( R_RAX, unop(Iop_128to64,mkexpr(dst128)) );
3090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64( R_RDX, unop(Iop_128HIto64,mkexpr(dst128)) );
3091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   op    = signed_divide ? Iop_DivModS64to32
3093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   : Iop_DivModU64to32;
3094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src64 = newTemp(Ity_I64);
3095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64 = newTemp(Ity_I64);
3096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (sz) {
3097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:
3098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64,
3099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_32HLto64, getIRegRDX(4), getIRegRAX(4)) );
3100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64,
3101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, mkexpr(src64), mkexpr(t)) );
3102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 4, unop(Iop_64to32,mkexpr(dst64)) );
3103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRDX( 4, unop(Iop_64HIto32,mkexpr(dst64)) );
3104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: {
3106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
3107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
3108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, unop(widen3264,
3109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_16HLto32,
3110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getIRegRDX(2),
3111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getIRegRAX(2))) );
3112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64, binop(op, mkexpr(src64), unop(widen1632,mkexpr(t))) );
3113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 2, unop(Iop_32to16,unop(Iop_64to32,mkexpr(dst64))) );
3114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRDX( 2, unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(dst64))) );
3115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: {
3118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen3264 = signed_divide ? Iop_32Sto64 : Iop_32Uto64;
3119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen1632 = signed_divide ? Iop_16Sto32 : Iop_16Uto32;
3120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp widen816  = signed_divide ? Iop_8Sto16  : Iop_8Uto16;
3121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src64, unop(widen3264,
3122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(widen1632, getIRegRAX(2))) );
3123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dst64,
3124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, mkexpr(src64),
3125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(widen1632, unop(widen816, mkexpr(t)))) );
3126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 1, unop(Iop_16to8,
3127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_32to16,
3128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_64to32,mkexpr(dst64)))) );
3129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegAH( unop(Iop_16to8,
3130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_32to16,
3131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64HIto32,mkexpr(dst64)))) );
3132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
3135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("codegen_div(amd64)");
3136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_Grp1 ( VexAbiInfo* vbi,
3142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Prefix pfx,
3143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Long delta, UChar modrm,
3144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Int am_sz, Int d_sz, Int sz, Long d64 )
3145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
3147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
3148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty   = szToITy(sz);
3149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst1 = newTemp(ty);
3150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  src  = newTemp(ty);
3151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  dst0 = newTemp(ty);
3152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
3153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op8  = Iop_INVALID;
3154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong   mask = mkSizeMask(sz);
3155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregLO3ofRM(modrm)) {
3157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0: op8 = Iop_Add8; break;  case 1: op8 = Iop_Or8;  break;
3158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: break;  // ADC
3159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 3: break;  // SBB
3160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: op8 = Iop_And8; break;  case 5: op8 = Iop_Sub8; break;
3161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: op8 = Iop_Xor8; break;  case 7: op8 = Iop_Sub8; break;
3162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
3163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("dis_Grp1(amd64): unhandled case");
3164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(am_sz == 1);
3168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIRegE(sz,pfx,modrm));
3170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src,  mkU(ty,d64 & mask));
3171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregLO3ofRM(modrm) == 2 /* ADC */) {
3173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_ADC( sz, dst1, dst0, src,
3174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
3175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
3176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregLO3ofRM(modrm) == 3 /* SBB */) {
3177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper_SBB( sz, dst1, dst0, src,
3178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     /*no store*/IRTemp_INVALID, IRTemp_INVALID, 0 );
3179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
3181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
3182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
3183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
3184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
3185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregLO3ofRM(modrm) < 7)
3188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(sz, pfx, modrm, mkexpr(dst1));
3189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + d_sz);
3191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $%lld, %s\n",
3192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameGrp1(gregLO3ofRM(modrm)), nameISize(sz), d64,
3193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIRegE(sz,pfx,modrm));
3194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta, dis_buf, /*xtra*/d_sz );
3196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
3198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src, mkU(ty,d64 & mask));
3199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregLO3ofRM(modrm) == 2 /* ADC */) {
3201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pfx & PFX_LOCK) {
3202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
3203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( sz, dst1, dst0, src,
3204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
3205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
3207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_ADC( sz, dst1, dst0, src,
3208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
3209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else
3211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregLO3ofRM(modrm) == 3 /* SBB */) {
3212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pfx & PFX_LOCK) {
3213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* cas-style store */
3214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( sz, dst1, dst0, src,
3215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       /*store*/addr, dst0/*expVal*/, guest_RIP_curr_instr );
3216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* normal store */
3218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            helper_SBB( sz, dst1, dst0, src,
3219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /*store*/addr, IRTemp_INVALID, 0 );
3220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1, binop(mkSizedOp(ty,op8), mkexpr(dst0), mkexpr(src)));
3223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(modrm) < 7) {
3224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
3225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(dst0)/*expVal*/,
3226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(dst1)/*newVal*/,
3227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_RIP_curr_instr );
3228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), mkexpr(dst1));
3230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (isAddSub(op8))
3233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(op8, dst0, src, ty);
3234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
3235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1(op8, dst1, ty);
3236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (len+d_sz);
3239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $%lld, %s\n",
3240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameGrp1(gregLO3ofRM(modrm)), nameISize(sz),
3241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          d64, dis_buf);
3242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 2 extended opcodes.  shift_expr must be an 8-bit typed
3248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expression. */
3249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_Grp2 ( VexAbiInfo* vbi,
3252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Prefix pfx,
3253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Long delta, UChar modrm,
3254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Int am_sz, Int d_sz, Int sz, IRExpr* shift_expr,
3255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 HChar* shift_expr_txt, Bool* decode_OK )
3256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* delta on entry points at the modrm byte. */
3258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
3260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   isShift, isRotate, isRotateC;
3261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
3262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst0  = newTemp(ty);
3263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1  = newTemp(ty);
3264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr  = IRTemp_INVALID;
3265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
3269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put value to shift/rotate in dst0. */
3271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, getIRegE(sz, pfx, modrm));
3273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + d_sz);
3274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta, dis_buf, /*xtra*/d_sz );
3276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dst0, loadLE(ty,mkexpr(addr)));
3277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len + d_sz;
3278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isShift = False;
3281b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   switch (gregLO3ofRM(modrm)) { case 4: case 5: case 6: case 7: isShift = True; }
3282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isRotate = False;
3284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregLO3ofRM(modrm)) { case 0: case 1: isRotate = True; }
3285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isRotateC = False;
3287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregLO3ofRM(modrm)) { case 2: case 3: isRotateC = True; }
3288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (!isShift && !isRotate && !isRotateC) {
3290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*NOTREACHED*/
3291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("dis_Grp2(Reg): unhandled case(amd64)");
3292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRotateC) {
3295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Call a helper; this insn is so ridiculous it does not deserve
3296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         better.  One problem is, the helper has to calculate both the
3297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         new value and the new flags.  This is more than 64 bits, and
3298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         there is no way to return more than 64 bits from the helper.
3299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Hence the crude and obvious solution is to call it twice,
3300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         using the sign of the sz field to indicate whether it is the
3301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value or rflags result we want.
3302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
3303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool     left = toBool(gregLO3ofRM(modrm) == 2);
3304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr** argsVALUE;
3305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr** argsRFLAGS;
3306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp new_value  = newTemp(Ity_I64);
3308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp new_rflags = newTemp(Ity_I64);
3309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp old_rflags = newTemp(Ity_I64);
3310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( old_rflags, widenUto64(mk_amd64g_calculate_rflags_all()) );
3312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argsVALUE
3314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          widenUto64(shift_expr),   /* rotate amount */
3316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(old_rflags),
3317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU64(sz) );
3318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( new_value,
3319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprCCall(
3320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Ity_I64,
3321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    0/*regparm*/,
3322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    left ? &amd64g_calculate_RCL  : &amd64g_calculate_RCR,
3324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    argsVALUE
3325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 )
3326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
3327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argsRFLAGS
3329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = mkIRExprVec_4( widenUto64(mkexpr(dst0)), /* thing to rotate */
3330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          widenUto64(shift_expr),   /* rotate amount */
3331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(old_rflags),
3332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU64(-sz) );
3333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( new_rflags,
3334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprCCall(
3335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Ity_I64,
3336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    0/*regparm*/,
3337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    left ? "amd64g_calculate_RCL" : "amd64g_calculate_RCR",
3338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    left ? &amd64g_calculate_RCL  : &amd64g_calculate_RCR,
3339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    argsRFLAGS
3340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 )
3341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
3342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst1, narrowTo(ty, mkexpr(new_value)) );
3344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
3345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(new_rflags) ));
3346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
3348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isShift) {
3352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp pre64     = newTemp(Ity_I64);
3354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res64     = newTemp(Ity_I64);
3355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res64ss   = newTemp(Ity_I64);
3356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp shift_amt = newTemp(Ity_I8);
3357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar  mask      = toUChar(sz==8 ? 63 : 31);
3358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   op64;
3359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
3361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: op64 = Iop_Shl64; break;
3362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: op64 = Iop_Shr64; break;
3363b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 6: op64 = Iop_Shl64; break;
3364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: op64 = Iop_Sar64; break;
3365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
3366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vpanic("dis_Grp2:shift"); break;
3367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Widen the value to be shifted to 64 bits, do the shift, and
3370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         narrow back down.  This seems surprisingly long-winded, but
3371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unfortunately the AMD semantics requires that 8/16/32-bit
3372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shifts give defined results for shift values all the way up
3373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to 32, and this seems the simplest way to do it.  It has the
3374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         advantage that the only IR level shifts generated are of 64
3375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bit values, and the shift amount is guaranteed to be in the
3376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         range 0 .. 63, thereby observing the IR semantics requiring
3377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         all shift values to be in the range 0 .. 2^word_size-1.
3378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Therefore the shift amount is masked with 63 for 64-bit shifts
3380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and 31 for all others.
3381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
3382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* shift_amt = shift_expr & MASK, regardless of operation size */
3383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( shift_amt, binop(Iop_And8, shift_expr, mkU8(mask)) );
3384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* suitably widen the value to be shifted to 64 bits. */
3386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( pre64, op64==Iop_Sar64 ? widenSto64(mkexpr(dst0))
3387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     : widenUto64(mkexpr(dst0)) );
3388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* res64 = pre64 `shift` shift_amt */
3390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res64, binop(op64, mkexpr(pre64), mkexpr(shift_amt)) );
3391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* res64ss = pre64 `shift` ((shift_amt - 1) & MASK) */
3393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res64ss,
3394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(op64,
3395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkexpr(pre64),
3396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And8,
3397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,
3398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(shift_amt), mkU8(1)),
3399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU8(mask))) );
3400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Build the flags thunk. */
3402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2_shift(op64, res64, res64ss, ty, shift_amt);
3403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Narrow the result back down. */
3405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst1, narrowTo(ty, mkexpr(res64)) );
3406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (isShift) */
3408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
3410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isRotate) {
3411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    ccOp      = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1
3412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        : (ty==Ity_I32 ? 2 : 3));
3413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   left      = toBool(gregLO3ofRM(modrm) == 0);
3414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rot_amt   = newTemp(Ity_I8);
3415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rot_amt64 = newTemp(Ity_I8);
3416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oldFlags  = newTemp(Ity_I64);
3417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar  mask      = toUChar(sz==8 ? 63 : 31);
3418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* rot_amt = shift_expr & mask */
3420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* By masking the rotate amount thusly, the IR-level Shl/Shr
3421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         expressions never shift beyond the word size and thus remain
3422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         well defined. */
3423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rot_amt64, binop(Iop_And8, shift_expr, mkU8(mask)));
3424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I64)
3426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rot_amt, mkexpr(rot_amt64));
3427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
3428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rot_amt, binop(Iop_And8, mkexpr(rot_amt64), mkU8(8*sz-1)));
3429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (left) {
3431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst1 = (dst0 << rot_amt) | (dst0 >>u (wordsize-rot_amt)) */
3433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1,
3434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(ty,Iop_Or8),
3435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shl8),
3436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
3437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(rot_amt)
3438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ),
3439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shr8),
3440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
3441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
3443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
3444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
3445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ccOp += AMD64G_CC_OP_ROLB;
3446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else { /* right */
3448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst1 = (dst0 >>u rot_amt) | (dst0 << (wordsize-rot_amt)) */
3450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(dst1,
3451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( mkSizedOp(ty,Iop_Or8),
3452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shr8),
3453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
3454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(rot_amt)
3455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ),
3456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( mkSizedOp(ty,Iop_Shl8),
3457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(dst0),
3458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Sub8,mkU8(8*sz), mkexpr(rot_amt))
3459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
3460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
3461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
3462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ccOp += AMD64G_CC_OP_RORB;
3463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* dst1 now holds the rotated value.  Build flag thunk.  We
3467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         need the resulting value for this, and the previous flags.
3468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Except don't set it if the rotate count is zero. */
3469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(oldFlags, mk_amd64g_calculate_rflags_all());
3471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* CC_DEP1 is the rotated value.  CC_NDEP is flags before. */
3473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,
3474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt64),
3475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_OP,Ity_I64),
3476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU64(ccOp))) );
3477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1,
3478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt64),
3479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_DEP1,Ity_I64),
3480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      widenUto64(mkexpr(dst1)))) );
3481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2,
3482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt64),
3483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_DEP2,Ity_I64),
3484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkU64(0))) );
3485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP,
3486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Mux0X( mkexpr(rot_amt64),
3487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Get(OFFB_CC_NDEP,Ity_I64),
3488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(oldFlags))) );
3489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* if (isRotate) */
3490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Save result, and finish up. */
3492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegE(sz, pfx, modrm, mkexpr(dst1));
3494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vex_traceflags & VEX_TRACE_FE) {
3495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("%s%c ",
3496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
3497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_expr_txt)
3498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("%s", shift_expr_txt);
3499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
3500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRExpr(shift_expr);
3501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf(", %s\n", nameIRegE(sz,pfx,modrm));
3502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(mkexpr(addr), mkexpr(dst1));
3505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (vex_traceflags & VEX_TRACE_FE) {
3506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("%s%c ",
3507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    nameGrp2(gregLO3ofRM(modrm)), nameISize(sz) );
3508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (shift_expr_txt)
3509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vex_printf("%s", shift_expr_txt);
3510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
3511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ppIRExpr(shift_expr);
3512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf(", %s\n", dis_buf);
3513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 8 extended opcodes (but BT/BTS/BTC/BTR only). */
3520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_Grp8_Imm ( VexAbiInfo* vbi,
3522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Prefix pfx,
3523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Long delta, UChar modrm,
3524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int am_sz, Int sz, ULong src_val,
3525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Bool* decode_OK )
3526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* src_val denotes a d8.
3528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      And delta on entry points at the modrm byte. */
3529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty     = szToITy(sz);
3531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2     = newTemp(Ity_I64);
3532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2m    = newTemp(Ity_I64);
3533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_addr = IRTemp_INVALID;
3534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
3535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong  mask;
3536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* we're optimists :-) */
3538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Limit src_val -- the bit offset -- to something within a word.
3541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The Intel docs say that literal offsets larger than a word are
3542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      masked in this way. */
3543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (sz) {
3544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2:  src_val &= 15; break;
3545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4:  src_val &= 31; break;
3546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 8:  src_val &= 63; break;
3547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: *decode_OK = False; return delta;
3548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Invent a mask suitable for the operation. */
3551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregLO3ofRM(modrm)) {
3552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: /* BT */  mask = 0;                  break;
3553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: /* BTS */ mask = 1ULL << src_val;    break;
3554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: /* BTR */ mask = ~(1ULL << src_val); break;
3555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: /* BTC */ mask = 1ULL << src_val;    break;
3556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If this needs to be extended, probably simplest to make a
3557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            new function to handle the other cases (0 .. 3).  The
3558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Intel docs do however not indicate any use for 0 .. 3, so
3559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we don't expect this to happen. */
3560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: *decode_OK = False; return delta;
3561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the value to be tested and modified into t2, which is
3564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      64-bits wide regardless of sz. */
3565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(am_sz == 1);
3567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, widenUto64(getIRegE(sz, pfx, modrm)) );
3568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += (am_sz + 1);
3569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameISize(sz),
3571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                src_val, nameIRegE(sz,pfx,modrm));
3572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int len;
3574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 1 );
3575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta  += (len+1);
3576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, widenUto64(loadLE(ty, mkexpr(t_addr))) );
3577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c $0x%llx, %s\n", nameGrp8(gregLO3ofRM(modrm)),
3578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameISize(sz),
3579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                src_val, dis_buf);
3580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Compute the new value into t2m, if non-BT. */
3583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (gregLO3ofRM(modrm)) {
3584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: /* BT */
3585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 5: /* BTS */
3587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_Or64, mkU64(mask), mkexpr(t2)) );
3588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 6: /* BTR */
3590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_And64, mkU64(mask), mkexpr(t2)) );
3591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 7: /* BTC */
3593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2m, binop(Iop_Xor64, mkU64(mask), mkexpr(t2)) );
3594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     default:
3596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/ /*the previous switch guards this*/
3597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
3598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Write the result back, if non-BT. */
3601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (gregLO3ofRM(modrm) != 4 /* BT */) {
3602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
3603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	putIRegE(sz, pfx, modrm, narrowTo(ty, mkexpr(t2m)));
3604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
3605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (pfx & PFX_LOCK) {
3606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            casLE( mkexpr(t_addr),
3607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   narrowTo(ty, mkexpr(t2))/*expd*/,
3608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   narrowTo(ty, mkexpr(t2m))/*new*/,
3609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   guest_RIP_curr_instr );
3610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
3611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE(mkexpr(t_addr), narrowTo(ty, mkexpr(t2m)));
3612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Copy relevant bit from t2 into the carry flag. */
3617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
3618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
3619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
3620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
3621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
3622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
3623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr64, mkexpr(t2), mkU8(src_val)),
3624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(1))
3625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
3626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
3627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
3628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
3629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Signed/unsigned widening multiply.  Generate IR to multiply the
3635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value in RAX/EAX/AX/AL by the given IRTemp, and park the result in
3636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   RDX:RAX/EDX:EAX/DX:AX/AX.
3637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
3638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void codegen_mulL_A_D ( Int sz, Bool syned,
3639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               IRTemp tmp, HChar* tmp_txt )
3640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
3642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
3643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t1, getIRegRAX(sz) );
3645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (ty) {
3647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I64: {
3648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res128  = newTemp(Ity_I128);
3649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I64);
3650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I64);
3651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS64 : Iop_MullU64;
3652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I64, t1, tmp, tBaseOp );
3654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res128, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_128HIto64,mkexpr(res128)));
3656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_128to64,mkexpr(res128)));
3657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64(R_RDX, mkexpr(resHi));
3658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64(R_RAX, mkexpr(resLo));
3659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I32: {
3662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res64   = newTemp(Ity_I64);
3663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I32);
3664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I32);
3665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS32 : Iop_MullU32;
3666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I32, t1, tmp, tBaseOp );
3668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_64HIto32,mkexpr(res64)));
3670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_64to32,mkexpr(res64)));
3671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRDX(4, mkexpr(resHi));
3672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX(4, mkexpr(resLo));
3673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I16: {
3676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res32   = newTemp(Ity_I32);
3677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I16);
3678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I16);
3679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS16 : Iop_MullU16;
3680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I16, t1, tmp, tBaseOp );
3682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res32, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_32HIto16,mkexpr(res32)));
3684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_32to16,mkexpr(res32)));
3685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRDX(2, mkexpr(resHi));
3686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX(2, mkexpr(resLo));
3687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Ity_I8: {
3690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp res16   = newTemp(Ity_I16);
3691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resHi   = newTemp(Ity_I8);
3692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp resLo   = newTemp(Ity_I8);
3693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   mulOp   = syned ? Iop_MullS8 : Iop_MullU8;
3694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UInt   tBaseOp = syned ? AMD64G_CC_OP_SMULB : AMD64G_CC_OP_UMULB;
3695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         setFlags_MUL ( Ity_I8, t1, tmp, tBaseOp );
3696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res16, binop(mulOp, mkexpr(t1), mkexpr(tmp)) );
3697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resHi, unop(Iop_16HIto8,mkexpr(res16)));
3698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( resLo, unop(Iop_16to8,mkexpr(res16)));
3699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX(2, mkexpr(res16));
3700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
3701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
3703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ppIRType(ty);
3704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("codegen_mulL_A_D(amd64)");
3705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c %s\n", syned ? "imul" : "mul", nameISize(sz), tmp_txt);
3707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 3 extended opcodes. */
3711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_Grp3 ( VexAbiInfo* vbi,
3713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Prefix pfx, Int sz, Long delta, Bool* decode_OK )
3714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long    d64;
3716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm;
3717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
3718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
3719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
3720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty = szToITy(sz);
3721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t1 = newTemp(ty);
3722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst1, src, dst0;
3723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getUChar(delta);
3725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
3727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: { /* TEST */
3728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            d64 = getSDisp(imin(4,sz), delta);
3730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += imin(4,sz);
3731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
3732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getIRegE(sz,pfx,modrm),
3734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU(ty, d64 & mkSizeMask(sz))));
3735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1( Iop_And8, dst1, ty );
3736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("test%c $%lld, %s\n",
3737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameISize(sz), d64,
3738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameIRegE(sz, pfx, modrm));
3739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
3742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* NOT */
3745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(sz, pfx, modrm,
3747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(mkSizedOp(ty,Iop_Not8),
3748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   getIRegE(sz, pfx, modrm)));
3749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("not%c %s\n", nameISize(sz),
3750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIRegE(sz, pfx, modrm));
3751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: /* NEG */
3753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst0 = newTemp(ty);
3755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src  = newTemp(ty);
3756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
3757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst0, mkU(ty,0));
3758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src,  getIRegE(sz, pfx, modrm));
3759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0),
3760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       mkexpr(src)));
3761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(sz, pfx, modrm, mkexpr(dst1));
3763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("neg%c %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm));
3764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* MUL (unsigned widening) */
3766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src = newTemp(ty);
3768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src, getIRegE(sz,pfx,modrm));
3769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, False, src,
3770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegE(sz,pfx,modrm) );
3771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: /* IMUL (signed widening) */
3773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src = newTemp(ty);
3775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src, getIRegE(sz,pfx,modrm));
3776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, True, src,
3777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegE(sz,pfx,modrm) );
3778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* DIV */
3780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIRegE(sz, pfx, modrm) );
3782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, False );
3783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("div%c %s\n", nameISize(sz),
3784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIRegE(sz, pfx, modrm));
3785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: /* IDIV */
3787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
3788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIRegE(sz, pfx, modrm) );
3789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, True );
3790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("idiv%c %s\n", nameISize(sz),
3791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegE(sz, pfx, modrm));
3792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*NOTREACHED*/
3795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("Grp3(amd64,R)");
3796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta, dis_buf,
3799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /* we have to inform disAMode of any immediate
3800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			   bytes used */
3801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        gregLO3ofRM(modrm)==0/*TEST*/
3802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           ? imin(4,sz)
3803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           : 0
3804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      );
3805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1   = newTemp(ty);
3806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
3807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(ty,mkexpr(addr)));
3808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
3809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: { /* TEST */
3810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            d64 = getSDisp(imin(4,sz), delta);
3811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += imin(4,sz);
3812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
3813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_And8),
3814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(t1),
3815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU(ty, d64 & mkSizeMask(sz))));
3816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1( Iop_And8, dst1, ty );
3817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("test%c $%lld, %s\n", nameISize(sz), d64, dis_buf);
3818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
3820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:
3821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* NOT */
3824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
3825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, unop(mkSizedOp(ty,Iop_Not8), mkexpr(t1)));
3826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
3827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
3828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_RIP_curr_instr );
3829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(dst1) );
3831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("not%c %s\n", nameISize(sz), dis_buf);
3833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: /* NEG */
3835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst0 = newTemp(ty);
3836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            src  = newTemp(ty);
3837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dst1 = newTemp(ty);
3838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst0, mkU(ty,0));
3839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(src,  mkexpr(t1));
3840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(dst1, binop(mkSizedOp(ty,Iop_Sub8), mkexpr(dst0),
3841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                       mkexpr(src)));
3842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
3843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(dst1)/*new*/,
3844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    guest_RIP_curr_instr );
3845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(dst1) );
3847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_DEP1_DEP2(Iop_Sub8, dst0, src, ty);
3849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("neg%c %s\n", nameISize(sz), dis_buf);
3850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* MUL (unsigned widening) */
3852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, False, t1, dis_buf );
3853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5: /* IMUL */
3855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_mulL_A_D ( sz, True, t1, dis_buf );
3856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* DIV */
3858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, False );
3859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("div%c %s\n", nameISize(sz), dis_buf);
3860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7: /* IDIV */
3862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            codegen_div ( sz, t1, True );
3863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("idiv%c %s\n", nameISize(sz), dis_buf);
3864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /*NOTREACHED*/
3867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("Grp3(amd64,M)");
3868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 4 extended opcodes. */
3875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_Grp4 ( VexAbiInfo* vbi,
3877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Prefix pfx, Long delta, Bool* decode_OK )
3878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   alen;
3880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm;
3881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
3882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = Ity_I8;
3883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
3884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(ty);
3885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getUChar(delta);
3889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIRegE(1, pfx, modrm));
3891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
3892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(1, pfx, modrm, mkexpr(t2));
3895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(1, pfx, modrm, mkexpr(t2));
3900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
3907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)),
3908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIRegE(1, pfx, modrm));
3909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
3910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
3911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, loadLE(ty, mkexpr(addr)) );
3912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
3913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Add8, mkexpr(t1), mkU8(1)));
3915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
3916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr );
3918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(t2) );
3920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub8, mkexpr(t1), mkU8(1)));
3925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
3926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr), mkexpr(t1)/*expd*/, mkexpr(t2)/*new*/,
3927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr );
3928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
3929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), mkexpr(t2) );
3930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
3931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
3934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
3935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
3936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
3937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
3938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sb %s\n", nameGrp4(gregLO3ofRM(modrm)), dis_buf);
3939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
3940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
3941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
3942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Group 5 extended opcodes. */
3945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
3946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_Grp5 ( VexAbiInfo* vbi,
3947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Prefix pfx, Int sz, Long delta,
3948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 DisResult* dres, Bool* decode_OK )
3949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
3950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     len;
3951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm;
3952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
3953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr = IRTemp_INVALID;
3954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType  ty = szToITy(sz);
3955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t1 = newTemp(ty);
3956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t2 = IRTemp_INVALID;
3957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  t3 = IRTemp_INVALID;
3958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    showSz = True;
3959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_OK = True;
3961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getUChar(delta);
3963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
3964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIRegE(sz,pfx,modrm));
3965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
3966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
3967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
3969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
3971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(sz,pfx,modrm, mkexpr(t2));
3972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
3974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
3975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
3976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
3977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
3978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(sz,pfx,modrm, mkexpr(t2));
3979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* call Ev */
3981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Ignore any sz value and operate as if sz==8. */
3982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!(sz == 4 || sz == 8)) goto unhandled;
3983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 8;
3984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t3 = newTemp(Ity_I64);
3985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t3, getIRegE(sz,pfx,modrm));
3986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I64);
3987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
3988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg64(R_RSP, mkexpr(t2));
3989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
3990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            make_redzone_AbiHint(vbi, t2, t3/*nia*/, "call-Ev(reg)");
3991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jmp_treg(Ijk_Call,t3);
3992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres->whatNext = Dis_StopHere;
3993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            showSz = False;
3994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
3995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* jmp Ev */
3996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Ignore any sz value and operate as if sz==8. */
3997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!(sz == 4 || sz == 8)) goto unhandled;
3998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 8;
3999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t3 = newTemp(Ity_I64);
4000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t3, getIRegE(sz,pfx,modrm));
4001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jmp_treg(Ijk_Boring,t3);
4002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres->whatNext = Dis_StopHere;
4003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            showSz = False;
4004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
4006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
4007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
4008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
4010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
4011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       showSz ? nameISize(sz) : ' ',
4012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       nameIRegE(sz, pfx, modrm));
4013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
4015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (gregLO3ofRM(modrm) != 2 && gregLO3ofRM(modrm) != 4
4016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  && gregLO3ofRM(modrm) != 6) {
4017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, loadLE(ty,mkexpr(addr)));
4018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
4020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: /* INC */
4021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
4022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Add8),
4023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
4024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
4025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
4026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
4027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),mkexpr(t2));
4029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( True, t2, ty );
4031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: /* DEC */
4033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(ty);
4034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(mkSizedOp(ty,Iop_Sub8),
4035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(t1), mkU(ty,1)));
4036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pfx & PFX_LOCK) {
4037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               casLE( mkexpr(addr),
4038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
4039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
4040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),mkexpr(t2));
4041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
4042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            setFlags_INC_DEC( False, t2, ty );
4043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: /* call Ev */
4045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Ignore any sz value and operate as if sz==8. */
4046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!(sz == 4 || sz == 8)) goto unhandled;
4047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 8;
4048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t3 = newTemp(Ity_I64);
4049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I64);
4051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
4052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg64(R_RSP, mkexpr(t2));
4053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
4054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            make_redzone_AbiHint(vbi, t2, t3/*nia*/, "call-Ev(mem)");
4055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jmp_treg(Ijk_Call,t3);
4056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres->whatNext = Dis_StopHere;
4057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            showSz = False;
4058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4: /* JMP Ev */
4060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Ignore any sz value and operate as if sz==8. */
4061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!(sz == 4 || sz == 8)) goto unhandled;
4062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 8;
4063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t3 = newTemp(Ity_I64);
4064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jmp_treg(Ijk_Boring,t3);
4066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres->whatNext = Dis_StopHere;
4067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            showSz = False;
4068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
4069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6: /* PUSH Ev */
4070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* There is no encoding for 32-bit operand size; hence ... */
4071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (sz == 4) sz = 8;
4072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (!(sz == 8 || sz == 2)) goto unhandled;
4073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (sz == 8) {
4074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t3 = newTemp(Ity_I64);
4075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t3, loadLE(Ity_I64,mkexpr(addr)));
4076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t2 = newTemp(Ity_I64);
4077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( t2, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
4078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIReg64(R_RSP, mkexpr(t2) );
4079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(t2), mkexpr(t3) );
4080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    } else {
4082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto unhandled; /* awaiting test case */
4083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    }
4084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
4085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unhandled:
4086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            *decode_OK = False;
4087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return delta;
4088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
4090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s%c %s\n", nameGrp5(gregLO3ofRM(modrm)),
4091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       showSz ? nameISize(sz) : ' ',
4092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       dis_buf);
4093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
4095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
4099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassembling string ops (including REP prefixes)    ---*/
4100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
4101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Code shared by all the string ops */
4103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_string_op_increment ( Int sz, IRTemp t_inc )
4105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar logSz;
4107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 || sz == 4 || sz == 2) {
4108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      logSz = 1;
4109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) logSz = 2;
4110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 8) logSz = 3;
4111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_inc,
4112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_Shl64, IRExpr_Get( OFFB_DFLAG, Ity_I64 ),
4113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(logSz) ) );
4114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_inc,
4116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              IRExpr_Get( OFFB_DFLAG, Ity_I64 ) );
4117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid dis_string_op( void (*dis_OP)( Int, IRTemp, Prefix pfx ),
4122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int sz, HChar* name, Prefix pfx )
4123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_inc = newTemp(Ity_I64);
4125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Really we ought to inspect the override prefixes, but we don't.
4126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The following assertion catches any resulting sillyness. */
4127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(pfx == clearSegBits(pfx));
4128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_string_op_increment(sz, t_inc);
4129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   dis_OP( sz, t_inc, pfx );
4130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c\n", name, nameISize(sz));
4131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid dis_MOVS ( Int sz, IRTemp t_inc, Prefix pfx )
4135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
4137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td = newTemp(Ity_I64);   /* RDI */
4138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts = newTemp(Ity_I64);   /* RSI */
4139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRExpr *incd, *incs;
4140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx)) {
4142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, unop(Iop_32Uto64, getIReg32(R_RDI)) );
4143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( ts, unop(Iop_32Uto64, getIReg32(R_RSI)) );
4144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
4145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, getIReg64(R_RDI) );
4146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( ts, getIReg64(R_RSI) );
4147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
4148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   storeLE( mkexpr(td), loadLE(ty,mkexpr(ts)) );
4150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incd = binop(Iop_Add64, mkexpr(td), mkexpr(t_inc));
4152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incs = binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc));
4153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx)) {
4154b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incd = unop(Iop_32Uto64, unop(Iop_64to32, incd));
4155b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incs = unop(Iop_32Uto64, unop(Iop_64to32, incs));
4156b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
4157b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RDI, incd );
4158b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RSI, incs );
4159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4162b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid dis_LODS ( Int sz, IRTemp t_inc, Prefix pfx )
4163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
4165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts = newTemp(Ity_I64);   /* RSI */
4166b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRExpr *incs;
4167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4168b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4169b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( ts, unop(Iop_32Uto64, getIReg32(R_RSI)) );
4170b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else
4171b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( ts, getIReg64(R_RSI) );
4172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIRegRAX ( sz, loadLE(ty, mkexpr(ts)) );
4174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4175b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incs = binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc));
4176b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4177b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incs = unop(Iop_32Uto64, unop(Iop_64to32, incs));
4178b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RSI, incs );
4179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4182b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid dis_STOS ( Int sz, IRTemp t_inc, Prefix pfx )
4183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
4185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ta = newTemp(ty);        /* rAX */
4186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td = newTemp(Ity_I64);   /* RDI */
4187b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRExpr *incd;
4188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ta, getIRegRAX(sz) );
4190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4191b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4192b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, unop(Iop_32Uto64, getIReg32(R_RDI)) );
4193b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else
4194b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, getIReg64(R_RDI) );
4195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   storeLE( mkexpr(td), mkexpr(ta) );
4197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4198b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incd = binop(Iop_Add64, mkexpr(td), mkexpr(t_inc));
4199b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4200b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incd = unop(Iop_32Uto64, unop(Iop_64to32, incd));
4201b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RDI, incd );
4202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4205b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid dis_CMPS ( Int sz, IRTemp t_inc, Prefix pfx )
4206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
4208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tdv = newTemp(ty);      /* (RDI) */
4209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tsv = newTemp(ty);      /* (RSI) */
4210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td  = newTemp(Ity_I64); /*  RDI  */
4211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ts  = newTemp(Ity_I64); /*  RSI  */
4212b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRExpr *incd, *incs;
4213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4214b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx)) {
4215b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, unop(Iop_32Uto64, getIReg32(R_RDI)) );
4216b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( ts, unop(Iop_32Uto64, getIReg32(R_RSI)) );
4217b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
4218b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, getIReg64(R_RDI) );
4219b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( ts, getIReg64(R_RSI) );
4220b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
4221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tdv, loadLE(ty,mkexpr(td)) );
4223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tsv, loadLE(ty,mkexpr(ts)) );
4225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2 ( Iop_Sub8, tsv, tdv, ty );
4227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4228b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incd = binop(Iop_Add64, mkexpr(td), mkexpr(t_inc));
4229b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incs = binop(Iop_Add64, mkexpr(ts), mkexpr(t_inc));
4230b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx)) {
4231b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incd = unop(Iop_32Uto64, unop(Iop_64to32, incd));
4232b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incs = unop(Iop_32Uto64, unop(Iop_64to32, incs));
4233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
4234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RDI, incd );
4235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RSI, incs );
4236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanovvoid dis_SCAS ( Int sz, IRTemp t_inc, Prefix pfx )
4240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty  = szToITy(sz);
4242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp ta  = newTemp(ty);       /*  rAX  */
4243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp td  = newTemp(Ity_I64);  /*  RDI  */
4244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tdv = newTemp(ty);       /* (RDI) */
4245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRExpr *incd;
4246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( ta, getIRegRAX(sz) );
4248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, unop(Iop_32Uto64, getIReg32(R_RDI)) );
4251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   else
4252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( td, getIReg64(R_RDI) );
4253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tdv, loadLE(ty,mkexpr(td)) );
4255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2 ( Iop_Sub8, ta, tdv, ty );
4257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   incd = binop(Iop_Add64, mkexpr(td), mkexpr(t_inc));
4259b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4260b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      incd = unop(Iop_32Uto64, unop(Iop_64to32, incd));
4261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   putIReg64( R_RDI, incd );
4262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Wrap the appropriate string op inside a REP/REPE/REPNE.  We assume
4266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the insn is the last one in the basic block, and so emit a jump to
4267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the next insn, rather than just falling through. */
4268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_REP_op ( AMD64Condcode cond,
4270b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                  void (*dis_OP)(Int, IRTemp, Prefix),
4271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Int sz, Addr64 rip, Addr64 rip_next, HChar* name,
4272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Prefix pfx )
4273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_inc = newTemp(Ity_I64);
4275b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRTemp tc;
4276b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   IRExpr* cmp;
4277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Really we ought to inspect the override prefixes, but we don't.
4279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      The following assertion catches any resulting sillyness. */
4280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(pfx == clearSegBits(pfx));
4281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4282b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx)) {
4283b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tc = newTemp(Ity_I32);  /*  ECX  */
4284b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( tc, getIReg32(R_RCX) );
4285b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      cmp = binop(Iop_CmpEQ32, mkexpr(tc), mkU32(0));
4286b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
4287b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      tc = newTemp(Ity_I64);  /*  RCX  */
4288b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( tc, getIReg64(R_RCX) );
4289b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      cmp = binop(Iop_CmpEQ64, mkexpr(tc), mkU64(0));
4290b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
4291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4292b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   stmt( IRStmt_Exit( cmp, Ijk_Boring, IRConst_U64(rip_next) ) );
4293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4294b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (haveASO(pfx))
4295b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putIReg32(R_RCX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
4296b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov  else
4297b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putIReg64(R_RCX, binop(Iop_Sub64, mkexpr(tc), mkU64(1)) );
4298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dis_string_op_increment(sz, t_inc);
4300b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   dis_OP (sz, t_inc, pfx);
4301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (cond == AMD64CondAlways) {
4303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmp_lit(Ijk_Boring,rip);
4304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit( mk_amd64g_calculate_condition(cond),
4306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Ijk_Boring,
4307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IRConst_U64(rip) ) );
4308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmp_lit(Ijk_Boring,rip_next);
4309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%c\n", name, nameISize(sz));
4311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
4315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Arithmetic, etc.                                     ---*/
4316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
4317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMUL E, G.  Supplied eip points to the modR/M byte. */
4319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_mul_E_G ( VexAbiInfo* vbi,
4321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Prefix      pfx,
4322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Int         size,
4323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    Long        delta0 )
4324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    alen;
4326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
4327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm = getUChar(delta0);
4328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(size);
4329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp te = newTemp(ty);
4330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tg = newTemp(ty);
4331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resLo = newTemp(ty);
4332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tg, getIRegG(size, pfx, rm) );
4334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
4335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( te, getIRegE(size, pfx, rm) );
4336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &alen, vbi, pfx, delta0, dis_buf, 0 );
4338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( te, loadLE(ty,mkexpr(addr)) );
4339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_MUL ( ty, te, tg, AMD64G_CC_OP_SMULB );
4342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tg) ) );
4344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIRegG(size, pfx, rm, mkexpr(resLo) );
4346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
4348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("imul%c %s, %s\n", nameISize(size),
4349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIRegE(size,pfx,rm),
4350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIRegG(size,pfx,rm));
4351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
4352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("imul%c %s, %s\n", nameISize(size),
4354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             dis_buf,
4355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameIRegG(size,pfx,rm));
4356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return alen+delta0;
4357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* IMUL I * E -> G.  Supplied rip points to the modR/M byte. */
4362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_imul_I_E_G ( VexAbiInfo* vbi,
4364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Prefix      pfx,
4365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int         size,
4366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Long        delta,
4367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Int         litsize )
4368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long   d64;
4370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    alen;
4371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
4372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm = getUChar(delta);
4373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(size);
4374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp te = newTemp(ty);
4375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tl = newTemp(ty);
4376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resLo = newTemp(ty);
4377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(/*size == 1 ||*/ size == 2 || size == 4 || size == 8);
4379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
4381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(te, getIRegE(size, pfx, rm));
4382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
4383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &alen, vbi, pfx, delta, dis_buf,
4385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     imin(4,litsize) );
4386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(te, loadLE(ty, mkexpr(addr)));
4387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
4388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d64 = getSDisp(imin(4,litsize),delta);
4390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += imin(4,litsize);
4391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   d64 &= mkSizeMask(size);
4393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(tl, mkU(ty,d64));
4394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resLo, binop( mkSizedOp(ty, Iop_Mul8), mkexpr(te), mkexpr(tl) ));
4396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_MUL ( ty, te, tl, AMD64G_CC_OP_SMULB );
4398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIRegG(size, pfx, rm, mkexpr(resLo));
4400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("imul%c $%lld, %s, %s\n",
4402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameISize(size), d64,
4403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( epartIsReg(rm) ? nameIRegE(size,pfx,rm) : dis_buf ),
4404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameIRegG(size,pfx,rm) );
4405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
4406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an IR sequence to do a popcount operation on the supplied
4410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp, and return a new IRTemp holding the result.  'ty' may be
4411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Ity_I16, Ity_I32 or Ity_I64 only. */
4412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_POPCOUNT ( IRType ty, IRTemp src )
4413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int i;
4415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I16) {
4416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp old = IRTemp_INVALID;
4417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp nyu = IRTemp_INVALID;
4418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask[4], shift[4];
4419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < 4; i++) {
4420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask[i]  = newTemp(ty);
4421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shift[i] = 1 << i;
4422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[0], mkU16(0x5555));
4424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[1], mkU16(0x3333));
4425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[2], mkU16(0x0F0F));
4426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[3], mkU16(0x00FF));
4427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old = src;
4428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < 4; i++) {
4429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nyu = newTemp(ty);
4430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(nyu,
4431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Add16,
4432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And16,
4433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old),
4434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(mask[i])),
4435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And16,
4436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr16, mkexpr(old), mkU8(shift[i])),
4437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(mask[i]))));
4438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         old = nyu;
4439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return nyu;
4441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I32) {
4443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp old = IRTemp_INVALID;
4444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp nyu = IRTemp_INVALID;
4445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask[5], shift[5];
4446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < 5; i++) {
4447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask[i]  = newTemp(ty);
4448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shift[i] = 1 << i;
4449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[0], mkU32(0x55555555));
4451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[1], mkU32(0x33333333));
4452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[2], mkU32(0x0F0F0F0F));
4453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[3], mkU32(0x00FF00FF));
4454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[4], mkU32(0x0000FFFF));
4455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old = src;
4456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < 5; i++) {
4457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nyu = newTemp(ty);
4458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(nyu,
4459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Add32,
4460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32,
4461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old),
4462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(mask[i])),
4463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And32,
4464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, mkexpr(old), mkU8(shift[i])),
4465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(mask[i]))));
4466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         old = nyu;
4467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return nyu;
4469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (ty == Ity_I64) {
4471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp old = IRTemp_INVALID;
4472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp nyu = IRTemp_INVALID;
4473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask[6], shift[6];
4474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < 6; i++) {
4475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask[i]  = newTemp(ty);
4476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         shift[i] = 1 << i;
4477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[0], mkU64(0x5555555555555555ULL));
4479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[1], mkU64(0x3333333333333333ULL));
4480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[2], mkU64(0x0F0F0F0F0F0F0F0FULL));
4481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[3], mkU64(0x00FF00FF00FF00FFULL));
4482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[4], mkU64(0x0000FFFF0000FFFFULL));
4483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(mask[5], mkU64(0x00000000FFFFFFFFULL));
4484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      old = src;
4485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = 0; i < 6; i++) {
4486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         nyu = newTemp(ty);
4487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(nyu,
4488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Add64,
4489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And64,
4490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(old),
4491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(mask[i])),
4492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_And64,
4493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr64, mkexpr(old), mkU8(shift[i])),
4494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkexpr(mask[i]))));
4495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         old = nyu;
4496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
4497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return nyu;
4498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*NOTREACHED*/
4500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0);
4501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate an IR sequence to do a count-leading-zeroes operation on
4505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the supplied IRTemp, and return a new IRTemp holding the result.
4506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   'ty' may be Ity_I16, Ity_I32 or Ity_I64 only.  In the case where
4507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   the argument is zero, return the number of bits in the word (the
4508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   natural semantics). */
4509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRTemp gen_LZCNT ( IRType ty, IRTemp src )
4510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(ty == Ity_I64 || ty == Ity_I32 || ty == Ity_I16);
4512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src64 = newTemp(Ity_I64);
4514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src64, widenUto64( mkexpr(src) ));
4515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src64x = newTemp(Ity_I64);
4517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(src64x,
4518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          binop(Iop_Shl64, mkexpr(src64),
4519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU8(64 - 8 * sizeofIRType(ty))));
4520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // Clz64 has undefined semantics when its input is zero, so
4522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   // special-case around that.
4523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res64 = newTemp(Ity_I64);
4524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res64,
4525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          IRExpr_Mux0X(
4526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             unop(Iop_1Uto8,
4527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CmpEQ64, mkexpr(src64x), mkU64(0))),
4528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             unop(Iop_Clz64, mkexpr(src64x)),
4529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkU64(8 * sizeofIRType(ty))
4530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
4531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res = newTemp(ty);
4533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(res, narrowTo(ty, mkexpr(res64)));
4534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return res;
4535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
4539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
4540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- x87 FLOATING POINT INSTRUCTIONS                      ---*/
4541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
4542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
4543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Helper functions for dealing with the register stack. --- */
4545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Set the emulation-warning pseudo-register. --- */
4547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_emwarn ( IRExpr* e /* :: Ity_I32 */ )
4549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
4551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_EMWARN, e ) );
4552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */
4555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mkQNaN64 ( void )
4557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* QNaN is 0 2047 1 0(51times)
4559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     == 0b 11111111111b 1 0(51times)
4560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     == 0x7FF8 0000 0000 0000
4561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
4562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL));
4563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the top-of-stack pointer :: Ity_I32 --------- */
4566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ftop ( void )
4568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FTOP, Ity_I32 );
4570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ftop ( IRExpr* e )
4573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
4575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FTOP, e ) );
4576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the C3210 bits. --------- */
4579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr*  /* :: Ity_I64 */ get_C3210 ( void )
4581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FC3210, Ity_I64 );
4583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_C3210 ( IRExpr* e  /* :: Ity_I64 */ )
4586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I64);
4588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FC3210, e ) );
4589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/put the FPU rounding mode. --------- */
4592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_fpround ( void )
4593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 ));
4595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_fpround ( IRExpr* /* :: Ity_I32 */ e )
4598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
4600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) );
4601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Synthesise a 2-bit FPU rounding mode. --------- */
4605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Produces a value in 0 .. 3, which is encoded as per the type
4606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRoundingMode.  Since the guest_FPROUND value is also encoded as
4607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   per IRRoundingMode, we merely need to get it and mask it for
4608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   safety.
4609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_roundingmode ( void )
4611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return binop( Iop_And32, get_fpround(), mkU32(3) );
4613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
4616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return mkU32(Irrm_NEAREST);
4618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/set FP register tag bytes. --------- */
4622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, generate 'ST_TAG(i) = e'. */
4624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST_TAG ( Int i, IRExpr* value )
4626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
4628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_I8);
4629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
4630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding 'ST_TAG(i)'.  This will be
4634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   zero to indicate "Empty" and nonzero to indicate "NonEmpty".  */
4635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST_TAG ( Int i )
4637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
4639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_GetI( descr, get_ftop(), i );
4640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* --------- Get/set FP registers. --------- */
4644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, emit 'ST(i) = e' and set the
4646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   register's tag to indicate the register is full.  The previous
4647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   state of the register is not checked. */
4648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST_UNCHECKED ( Int i, IRExpr* value )
4650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr;
4652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, value) == Ity_F64);
4653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
4654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
4655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Mark the register as in-use. */
4656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_TAG(i, mkU8(1));
4657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, and some expression e, emit
4660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ST(i) = is_full(i) ? NaN : e
4661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and set the tag accordingly.
4662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_ST ( Int i, IRExpr* value )
4665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED( i,
4667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( get_ST_TAG(i),
4668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   /* 0 means empty */
4669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   value,
4670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   /* non-0 means full */
4671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkQNaN64()
4672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
4673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
4674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding 'ST(i)'. */
4678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST_UNCHECKED ( Int i )
4680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPREGS, Ity_F64, 8 );
4682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_GetI( descr, get_ftop(), i );
4683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given i, generate an expression yielding
4687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  is_full(i) ? ST(i) : NaN
4688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_ST ( Int i )
4691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
4693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr_Mux0X( get_ST_TAG(i),
4694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /* 0 means empty */
4695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkQNaN64(),
4696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /* non-0 means full */
4697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    get_ST_UNCHECKED(i));
4698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Adjust FTOP downwards by one register. */
4702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_push ( void )
4704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop( binop(Iop_Sub32, get_ftop(), mkU32(1)) );
4706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Adjust FTOP upwards by one register, and mark the vacated register
4709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   as empty.  */
4710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_pop ( void )
4712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_TAG(0, mkU8(0));
4714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
4715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Clear the C2 bit of the FPU status register, for
4718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sin/cos/tan/sincos. */
4719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void clear_C2 ( void )
4721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_C3210( binop(Iop_And64, get_C3210(), mkU64(~AMD64G_FC_MASK_C2)) );
4723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Invent a plausible-looking FPU status word value:
4726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ((ftop & 7) << 11) | (c3210 & 0x4700)
4727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
4728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* get_FPU_sw ( void )
4729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
4731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unop(Iop_32to16,
4732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Or32,
4733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shl32,
4734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, get_ftop(), mkU32(7)),
4735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU8(11)),
4736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And32, unop(Iop_64to32, get_C3210()),
4737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU32(0x4700))
4738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
4739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ------------------------------------------------------- */
4743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Given all that stack-mangling junk, we can now go ahead
4744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   and describe FP instructions.
4745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(0) = ST(0) `op` mem64/32(addr)
4748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Need to check ST(0)'s tag on read, but not on write.
4749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         IROp op, Bool dbl )
4753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dbl) {
4756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
4757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
4758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0),
4760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                loadLE(Ity_F64,mkexpr(addr))
4761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
4762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
4764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
4765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0),
4767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr)))
4768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
4769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(0) = mem64/32(addr) `op` ST(0)
4774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Need to check ST(0)'s tag on read, but not on write.
4775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf,
4778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            IROp op, Bool dbl )
4779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf);
4781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (dbl) {
4782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
4783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
4784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                loadLE(Ity_F64,mkexpr(addr)),
4786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0)
4787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
4788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
4789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_ST_UNCHECKED(0,
4790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         triop( op,
4791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))),
4793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                get_ST(0)
4794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
4795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
4796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(dst) = ST(dst) `op` ST(src).
4800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check dst and src tags when reading but not on write.
4801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Bool pop_after )
4805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED(
4808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st_dst,
4809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      triop( op,
4810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_dst),
4812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_src) )
4813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
4814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
4815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
4816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* ST(dst) = ST(src) `op` ST(dst).
4819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Check dst and src tags when reading but not on write.
4820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst,
4823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         Bool pop_after )
4824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("f%s%s st(%u), st(%u)\n", op_txt, pop_after?"p":"", st_src, st_dst );
4826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ST_UNCHECKED(
4827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      st_dst,
4828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      triop( op,
4829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
4830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_src),
4831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             get_ST(st_dst) )
4832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
4833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
4834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
4835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* %rflags(Z,P,C) = UCOMI( st(0), st(i) ) */
4838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fp_do_ucomi_ST0_STi ( UInt i, Bool pop_after )
4839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("fucomi%s %%st(0),%%st(%u)\n", pop_after ? "p" : "", i);
4841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a bit of a hack (and isn't really right).  It sets
4842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Z,P,C,O correctly, but forces A and S to zero, whereas the Intel
4843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      documentation implies A and S are unchanged.
4844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
4845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* It's also fishy in that it is used both for COMIP and
4846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UCOMIP, and they aren't the same (although similar). */
4847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
4848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
4849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
4850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
4851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( Iop_And64,
4852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop( Iop_32Uto64,
4853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_CmpF64, get_ST(0), get_ST(i))),
4854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkU64(0x45)
4855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )));
4856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pop_after)
4857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      fp_pop();
4858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* returns
4862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   32to16( if e32 <s -32768 || e32 >s 32767 then -32768 else e32 )
4863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
4864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* x87ishly_qnarrow_32_to_16 ( IRExpr* e32 )
4865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t32 = newTemp(Ity_I32);
4867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t32, e32 );
4868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
4869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr_Mux0X(
4870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_1Uto8,
4871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_CmpLT64U,
4872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_32Uto64,
4873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_Add32, mkexpr(t32), mkU32(32768))),
4874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU64(65536))),
4875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU16( 0x8000 ),
4876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_32to16, mkexpr(t32)));
4877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
4878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
4881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_FPU ( /*OUT*/Bool* decode_ok,
4882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi, Prefix pfx, Long delta )
4883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
4884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
4885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UInt   r_src, r_dst;
4886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
4887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1, t2;
4888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* On entry, delta points at the second byte of the insn (the modrm
4890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      byte).*/
4891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar first_opcode = getUChar(delta-1);
4892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm        = getUChar(delta+0);
4893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD8 opcodes +-+-+-+-+-+-+-+ */
4895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xD8) {
4897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
4898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
4900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           specifies an address. */
4901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
4902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
4903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
4905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FADD single-real */
4907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, False );
4908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FMUL single-real */
4911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, False );
4912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             case 2: /* FCOM single-real */
4915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                DIP("fcoms %s\n", dis_buf);
4916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* This forces C1 to zero, which isn't right. */
4917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                put_C3210(
4918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                    binop( Iop_And32,
4919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                           binop(Iop_Shl32,
4920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 binop(Iop_CmpF64,
4921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                       get_ST(0),
4922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                       unop(Iop_F32toF64,
4923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                            loadLE(Ity_F32,mkexpr(addr)))),
4924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 mkU8(8)),
4925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                           mkU32(0x4500)
4926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                    ));
4927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                break;
4928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
4929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             case 3: /* FCOMP single-real */
4930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                DIP("fcomps %s\n", dis_buf);
4931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* This forces C1 to zero, which isn't right. */
4932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                put_C3210(
4933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                    binop( Iop_And32,
4934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                           binop(Iop_Shl32,
4935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 binop(Iop_CmpF64,
4936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                       get_ST(0),
4937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                       unop(Iop_F32toF64,
4938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                            loadLE(Ity_F32,mkexpr(addr)))),
4939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 mkU8(8)),
4940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                           mkU32(0x4500)
4941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                    ));
4942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                fp_pop();
4943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                break;
4944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FSUB single-real */
4946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, False );
4947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FSUBR single-real */
4950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, False );
4951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FDIV single-real */
4954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, False );
4955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FDIVR single-real */
4958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, False );
4959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
4962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
4963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xD8\n");
4964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
4965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
4966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
4967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
4968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
4969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADD %st(?),%st(0) */
4971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, modrm - 0xC0, 0, False );
4972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMUL %st(?),%st(0) */
4975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, modrm - 0xC8, 0, False );
4976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Dunno if this is right */
4979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCOM %st(?),%st(0) */
4980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD0;
4981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcom %%st(0),%%st(%d)\n", r_dst);
4982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
4985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
4986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
4987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
4988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
4989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
4990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
4991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
4992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Dunno if this is right */
4994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCOMP %st(?),%st(0) */
4995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD8;
4996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcomp %%st(0),%%st(%d)\n", r_dst);
4997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
4998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
4999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
5000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
5003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
5006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUB %st(?),%st(0) */
5010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, modrm - 0xE0, 0, False );
5011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUBR %st(?),%st(0) */
5014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, modrm - 0xE8, 0, False );
5015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIV %st(?),%st(0) */
5018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, modrm - 0xF0, 0, False );
5019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIVR %st(?),%st(0) */
5022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, modrm - 0xF8, 0, False );
5023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xD9 opcodes +-+-+-+-+-+-+-+ */
5032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xD9) {
5034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
5039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
5042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FLD single-real */
5044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("flds %s\n", dis_buf);
5045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_F32toF64,
5047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_F32, mkexpr(addr))));
5048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FST single-real */
5051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsts %s\n", dis_buf);
5052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),
5053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
5054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FSTP single-real */
5057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstps %s\n", dis_buf);
5058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr),
5059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_F64toF32, get_roundingmode(), get_ST(0)));
5060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: { /* FLDENV m28 */
5064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VexEmWarn amd64g_do_FLDENV ( VexGuestX86State*, HWord ) */
5066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp    ew = newTemp(Ity_I32);
5067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   w64 = newTemp(Ity_I64);
5068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty*   d = unsafeIRDirty_0_N (
5069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 0/*regparms*/,
5070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "amd64g_dirtyhelper_FLDENV",
5071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 &amd64g_dirtyhelper_FLDENV,
5072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkIRExprVec_1( mkexpr(addr) )
5073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              );
5074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
5075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->tmp      = w64;
5076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading memory */
5077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
5078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 28;
5080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
5082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 4;
5083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
5085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
5086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
5087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
5089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPTAGS;
5090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(UChar);
5091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
5093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPROUND;
5094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = sizeof(ULong);
5095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
5097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FC3210;
5098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(ULong);
5099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ew contains any emulation warning we may need to
5103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  issue.  If needed, side-exit to the next insn,
5104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  reporting the warning, so that Valgrind's dispatcher
5105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sees the warning. */
5106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       assign(ew, unop(Iop_64to32,mkexpr(w64)) );
5107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
5108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
5109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
5110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
5112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRConst_U64( guest_RIP_bbstart+delta )
5113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldenv %s\n", dis_buf);
5117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: {/* FLDCW */
5121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* The only thing we observe in the control word is the
5122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  rounding mode.  Therefore, pass the 16-bit value
5123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  (x87 native-format control word) to a clean helper,
5124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getting back a 64-bit value, the lower half of which
5125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is the FPROUND value to store, and the upper half of
5126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  which is the emulation-warning token which may be
5127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  generated.
5128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               */
5129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ULong amd64h_check_fldcw ( ULong ); */
5130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp t64 = newTemp(Ity_I64);
5131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp ew = newTemp(Ity_I32);
5132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldcw %s\n", dis_buf);
5133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( t64, mkIRExprCCall(
5134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               Ity_I64, 0/*regparms*/,
5135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "amd64g_check_fldcw",
5136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &amd64g_check_fldcw,
5137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkIRExprVec_1(
5138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop( Iop_16Uto64,
5139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        loadLE(Ity_I16, mkexpr(addr)))
5140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               )
5141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            )
5142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     );
5143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_fpround( unop(Iop_64to32, mkexpr(t64)) );
5145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
5146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_emwarn( mkexpr(ew) );
5147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Finally, if an emulation warning was reported,
5148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  side-exit to the next insn, reporting the warning,
5149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  so that Valgrind's dispatcher sees the warning. */
5150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt(
5151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRStmt_Exit(
5152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
5153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_EmWarn,
5154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRConst_U64( guest_RIP_bbstart+delta )
5155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: { /* FNSTENV m28 */
5161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void amd64g_do_FSTENV ( VexGuestAMD64State*, HWord ) */
5163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
5164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
5165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "amd64g_dirtyhelper_FSTENV",
5166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &amd64g_dirtyhelper_FSTENV,
5167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkIRExprVec_1( mkexpr(addr) )
5168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
5169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
5170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
5171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
5172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 28;
5174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're reading guest state */
5176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 4;
5177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Read;
5179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
5180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
5181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Read;
5183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPTAGS;
5184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(UChar);
5185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Read;
5187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPROUND;
5188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = sizeof(ULong);
5189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Read;
5191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FC3210;
5192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(ULong);
5193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstenv %s\n", dis_buf);
5197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FNSTCW */
5201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Fake up a native x87 FPU control word.  The only
5202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  thing it depends on is FPROUND[1:0], so call a clean
5203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  helper to cook it up. */
5204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* ULong amd64g_create_fpucw ( ULong fpround ) */
5205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstcw %s\n", dis_buf);
5206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(
5207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(addr),
5208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop( Iop_64to16,
5209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkIRExprCCall(
5210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Ity_I64, 0/*regp*/,
5211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           "amd64g_create_fpucw", &amd64g_create_fpucw,
5212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) )
5213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
5214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xD9\n");
5221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FLD %st(?) */
5229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
5230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fld %%st(%u)\n", r_src);
5231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t1 = newTemp(Ity_F64);
5232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t1, get_ST(r_src));
5233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, mkexpr(t1));
5235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FXCH %st(?) */
5238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
5239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxch %%st(%u)\n", r_src);
5240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t1 = newTemp(Ity_F64);
5241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               t2 = newTemp(Ity_F64);
5242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t1, get_ST(0));
5243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign(t2, get_ST(r_src));
5244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, mkexpr(t2));
5245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_src, mkexpr(t1));
5246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0: /* FCHS */
5249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fchs\n");
5250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, unop(Iop_NegF64, get_ST(0)));
5251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE1: /* FABS */
5254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fabs\n");
5255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
5256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE5: { /* FXAM */
5259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This is an interesting one.  It examines %st(0),
5260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  regardless of whether the tag says it's empty or not.
5261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Here, just pass both the tag (in our format) and the
5262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  value (as a double, actually a ULong) to a helper
5263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  function. */
5264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args
5265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
5266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_ReinterpF64asI64,
5267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        get_ST_UNCHECKED(0)) );
5268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(mkIRExprCCall(
5269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            Ity_I64,
5270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            0/*regparm*/,
5271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
5272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args
5273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ));
5274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxam\n");
5275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8: /* FLD1 */
5279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fld1\n");
5280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
5282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
5283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE9: /* FLDL2T */
5286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl2t\n");
5287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
5289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
5290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEA: /* FLDL2E */
5293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl2e\n");
5294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
5296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
5297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEB: /* FLDPI */
5300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldpi\n");
5301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
5303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
5304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEC: /* FLDLG2 */
5307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldlg2\n");
5308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
5310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
5311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xED: /* FLDLN2 */
5314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldln2\n");
5315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
5317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
5318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xEE: /* FLDZ */
5321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldz\n");
5322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
5324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
5325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0: /* F2XM1 */
5328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("f2xm1\n");
5329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_2xm1F64,
5331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF1: /* FYL2X */
5336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fyl2x\n");
5337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
5338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_Yl2xF64,
5339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
5341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF2: /* FPTAN */
5346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ftan\n");
5347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_TanF64,
5349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
5353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
5354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF3: /* FPATAN */
5357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fpatan\n");
5358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
5359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_AtanF64,
5360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
5362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF4: { /* FXTRACT */
5367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp argF = newTemp(Ity_F64);
5368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp sigF = newTemp(Ity_F64);
5369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp expF = newTemp(Ity_F64);
5370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp argI = newTemp(Ity_I64);
5371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp sigI = newTemp(Ity_I64);
5372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp expI = newTemp(Ity_I64);
5373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fxtract\n");
5374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( argF, get_ST(0) );
5375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
5376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( sigI,
5377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprCCall(
5378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Ity_I64, 0/*regparms*/,
5379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86amd64g_calculate_FXTRACT",
5380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86amd64g_calculate_FXTRACT,
5381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(argI),
5382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkIRExpr_HWord(0)/*sig*/ ))
5383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( expI,
5385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprCCall(
5386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          Ity_I64, 0/*regparms*/,
5387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "x86amd64g_calculate_FXTRACT",
5388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &x86amd64g_calculate_FXTRACT,
5389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(argI),
5390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkIRExpr_HWord(1)/*exp*/ ))
5391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
5393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
5394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* exponent */
5395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0, mkexpr(expF) );
5396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* significand */
5398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, mkexpr(sigF) );
5399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF5: { /* FPREM1 -- IEEE compliant */
5403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
5404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a2 = newTemp(Ity_F64);
5405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem1\n");
5406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Do FPREM1 twice, once to get the remainder, and once
5407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to get the C3210 flag values. */
5408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
5409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a2, get_ST(1) );
5410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRem1F64,
5412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
5414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)));
5415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32Uto64,
5417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRem1C3210F64,
5418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
5420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)) ));
5421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF7: /* FINCSTP */
5425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fincstp\n");
5426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ftop( binop(Iop_Add32, get_ftop(), mkU32(1)) );
5427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8: { /* FPREM -- not IEEE compliant */
5430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
5431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a2 = newTemp(Ity_F64);
5432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fprem\n");
5433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Do FPREM twice, once to get the remainder, and once
5434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  to get the C3210 flag values. */
5435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
5436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a2, get_ST(1) );
5437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRemF64,
5439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
5441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)));
5442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32Uto64,
5444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_PRemC3210F64,
5445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1),
5447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a2)) ));
5448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF9: /* FYL2XP1 */
5452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fyl2xp1\n");
5453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(1,
5454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_Yl2xp1F64,
5455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1),
5457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFA: /* FSQRT */
5462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsqrt\n");
5463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SqrtF64,
5465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFB: { /* FSINCOS */
5470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp a1 = newTemp(Ity_F64);
5471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               assign( a1, get_ST(0) );
5472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsincos\n");
5473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SinF64,
5475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1)));
5477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0,
5479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CosF64,
5480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(a1)));
5482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
5483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFC: /* FRNDINT */
5487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("frndint\n");
5488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_RoundF64toInt, get_roundingmode(), get_ST(0)) );
5490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFD: /* FSCALE */
5493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fscale\n");
5494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(Iop_ScaleF64,
5496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
5498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(1)));
5499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFE: /* FSIN */
5502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fsin\n");
5503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SinF64,
5505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
5508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xFF: /* FCOS */
5511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcos\n");
5512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_CosF64,
5514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               clear_C2(); /* HACK */
5517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDA opcodes +-+-+-+-+-+-+-+ */
5526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDA) {
5528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   fop;
5534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
5535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
5537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FIADD m32int */ /* ST(0) += m32int */
5539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fiaddl %s\n", dis_buf);
5540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_AddF64;
5541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
5542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FIMUL m32int */ /* ST(0) *= m32int */
5544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fimull %s\n", dis_buf);
5545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_MulF64;
5546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
5547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FISUB m32int */ /* ST(0) -= m32int */
5549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubl %s\n", dis_buf);
5550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
5551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
5552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FISUBR m32int */ /* ST(0) = m32int - ST(0) */
5554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubrl %s\n", dis_buf);
5555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
5556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m32;
5557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FIDIV m32int */ /* ST(0) /= m32int */
5559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubl %s\n", dis_buf);
5560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
5561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m32;
5562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FIDIVR m32int */ /* ST(0) = m32int / ST(0) */
5564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivrl %s\n", dis_buf);
5565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
5566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m32;
5567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_fop_m32:
5569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
5571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
5573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
5574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, mkexpr(addr)))));
5575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_foprev_m32:
5578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
5580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
5581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
5582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             loadLE(Ity_I32, mkexpr(addr))),
5583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
5584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDA\n");
5589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FCMOVB ST(i), ST(0) */
5598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
5599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovb %%st(%u), %%st(0)\n", r_src);
5600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
5602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
5603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_amd64g_calculate_condition(AMD64CondB)),
5604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
5605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FCMOVE(Z) ST(i), ST(0) */
5608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
5609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovz %%st(%u), %%st(0)\n", r_src);
5610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
5612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
5613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_amd64g_calculate_condition(AMD64CondZ)),
5614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
5615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCMOVBE ST(i), ST(0) */
5618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD0;
5619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovbe %%st(%u), %%st(0)\n", r_src);
5620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
5622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
5623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_amd64g_calculate_condition(AMD64CondBE)),
5624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
5625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCMOVU ST(i), ST(0) */
5628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD8;
5629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovu %%st(%u), %%st(0)\n", r_src);
5630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
5632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
5633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_amd64g_calculate_condition(AMD64CondP)),
5634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
5635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE9: /* FUCOMPP %st(0),%st(1) */
5638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucompp %%st(0),%%st(1)\n");
5639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
5642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
5645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
5648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDB opcodes +-+-+-+-+-+-+-+ */
5660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDB) {
5662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
5667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
5670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FILD m32int */
5672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildl %s\n", dis_buf);
5673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_I32StoF64,
5675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_I32, mkexpr(addr))));
5676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPL m32 (SSE3) */
5679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisttpl %s\n", dis_buf);
5680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
5682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FIST m32 */
5686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistl %s\n", dis_buf);
5687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
5689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FISTP m32 */
5692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistpl %s\n", dis_buf);
5693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
5694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
5695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: { /* FLD extended-real */
5699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ULong amd64g_loadF80le ( ULong )
5701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  addr holds the address.  First, do a dirty call to
5702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  get hold of the data. */
5703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp   val  = newTemp(Ity_I64);
5704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args = mkIRExprVec_1 ( mkexpr(addr) );
5705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_1_N (
5707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               val,
5708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
5709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "amd64g_dirtyhelper_loadF80le",
5710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &amd64g_dirtyhelper_loadF80le,
5711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               args
5712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
5713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare that we're reading memory */
5714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Read;
5715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 10;
5717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* execute the dirty call, dumping the result in val. */
5719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(val)));
5722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldt %s\n", dis_buf);
5724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: { /* FSTP extended-real */
5728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void amd64g_storeF80le ( ULong addr, ULong data )
5730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               */
5731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr** args
5732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  = mkIRExprVec_2( mkexpr(addr),
5733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_ReinterpF64asI64, get_ST(0)) );
5734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d = unsafeIRDirty_0_N (
5736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               0/*regparms*/,
5737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               "amd64g_dirtyhelper_storeF80le",
5738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               &amd64g_dirtyhelper_storeF80le,
5739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               args
5740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            );
5741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing memory */
5742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mFx   = Ifx_Write;
5743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mAddr = mkexpr(addr);
5744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->mSize = 10;
5745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* execute the dirty call. */
5747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstpt\n %s", dis_buf);
5751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDB\n");
5757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FCMOVNB ST(i), ST(0) */
5766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC0;
5767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnb %%st(%u), %%st(0)\n", r_src);
5768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
5769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                IRExpr_Mux0X(
5770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_1Uto8,
5771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mk_amd64g_calculate_condition(AMD64CondNB)),
5772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    get_ST(0), get_ST(r_src)) );
5773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FCMOVNE(NZ) ST(i), ST(0) */
5776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xC8;
5777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnz %%st(%u), %%st(0)\n", r_src);
5778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(
5779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  0,
5780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Mux0X(
5781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto8,
5782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mk_amd64g_calculate_condition(AMD64CondNZ)),
5783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     get_ST(0),
5784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     get_ST(r_src)
5785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FCMOVNBE ST(i), ST(0) */
5790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD0;
5791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnbe %%st(%u), %%st(0)\n", r_src);
5792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(
5793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  0,
5794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Mux0X(
5795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto8,
5796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mk_amd64g_calculate_condition(AMD64CondNBE)),
5797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     get_ST(0),
5798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     get_ST(r_src)
5799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FCMOVNU ST(i), ST(0) */
5804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_src = (UInt)modrm - 0xD8;
5805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcmovnu %%st(%u), %%st(0)\n", r_src);
5806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(
5807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  0,
5808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRExpr_Mux0X(
5809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto8,
5810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mk_amd64g_calculate_condition(AMD64CondNP)),
5811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     get_ST(0),
5812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     get_ST(r_src)
5813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  )
5814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
5815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE2:
5818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnclex\n");
5819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE3: {
5822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Uses dirty helper:
5823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     void amd64g_do_FINIT ( VexGuestAMD64State* ) */
5824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRDirty* d  = unsafeIRDirty_0_N (
5825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0/*regparms*/,
5826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                "amd64g_dirtyhelper_FINIT",
5827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &amd64g_dirtyhelper_FINIT,
5828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkIRExprVec_0()
5829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             );
5830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->needsBBP = True;
5831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* declare we're writing guest state */
5833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->nFxState = 5;
5834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].fx     = Ifx_Write;
5836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].offset = OFFB_FTOP;
5837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[0].size   = sizeof(UInt);
5838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].fx     = Ifx_Write;
5840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].offset = OFFB_FPREGS;
5841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[1].size   = 8 * sizeof(ULong);
5842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].fx     = Ifx_Write;
5844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].offset = OFFB_FPTAGS;
5845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[2].size   = 8 * sizeof(UChar);
5846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].fx     = Ifx_Write;
5848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].offset = OFFB_FPROUND;
5849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[3].size   = sizeof(ULong);
5850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].fx     = Ifx_Write;
5852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].offset = OFFB_FC3210;
5853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               d->fxState[4].size   = sizeof(ULong);
5854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               stmt( IRStmt_Dirty(d) );
5856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fninit\n");
5858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
5860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMI %st(0),%st(?) */
5862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, False );
5863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FCOMI %st(0),%st(?) */
5866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, False );
5867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDC opcodes +-+-+-+-+-+-+-+ */
5876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDC) {
5878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
5883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
5886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FADD double-real */
5888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "add", dis_buf, Iop_AddF64, True );
5889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FMUL double-real */
5892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "mul", dis_buf, Iop_MulF64, True );
5893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             case 2: /* FCOM double-real */
5896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                DIP("fcoml %s\n", dis_buf);
5897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* This forces C1 to zero, which isn't right. */
5898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                put_C3210(
5899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                    binop( Iop_And32,
5900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                           binop(Iop_Shl32,
5901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 binop(Iop_CmpF64,
5902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                       get_ST(0),
5903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                       loadLE(Ity_F64,mkexpr(addr))),
5904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 mkU8(8)),
5905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                           mkU32(0x4500)
5906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                    ));
5907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                break;
5908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FCOMP double-real */
5910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcompl %s\n", dis_buf);
5911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
5912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
5913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
5914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
5915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
5916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64,
5917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      get_ST(0),
5918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      loadLE(Ity_F64,mkexpr(addr))),
5919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
5920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
5921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
5922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
5923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FSUB double-real */
5926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "sub", dis_buf, Iop_SubF64, True );
5927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FSUBR double-real */
5930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "subr", dis_buf, Iop_SubF64, True );
5931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FDIV double-real */
5934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_mem_ST_0 ( addr, "div", dis_buf, Iop_DivF64, True );
5935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FDIVR double-real */
5938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_mem_ST_0 ( addr, "divr", dis_buf, Iop_DivF64, True );
5939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
5943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDC\n");
5944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
5948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
5950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
5951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADD %st(0),%st(?) */
5953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, False );
5954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMUL %st(0),%st(?) */
5957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, False );
5958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUBR %st(0),%st(?) */
5961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0, modrm - 0xE0, False );
5962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUB %st(0),%st(?) */
5965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0, modrm - 0xE8, False );
5966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIVR %st(0),%st(?) */
5969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, False );
5970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIV %st(0),%st(?) */
5973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, False );
5974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
5975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
5977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
5978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
5979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
5981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
5982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDD opcodes +-+-+-+-+-+-+-+ */
5984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
5985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDD) {
5986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
5988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
5990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
5991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
5992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
5993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
5995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FLD double-real */
5997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fldl %s\n", dis_buf);
5998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
5999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, loadLE(Ity_F64, mkexpr(addr)));
6000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPQ m64 (SSE3) */
6003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistppll %s\n", dis_buf);
6004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
6006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FST double-real */
6010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstl %s\n", dis_buf);
6011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), get_ST(0));
6012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FSTP double-real */
6015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstpl %s\n", dis_buf);
6016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE(mkexpr(addr), get_ST(0));
6017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             case 4: { /* FRSTOR m108 */
6021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* Uses dirty helper:
6022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      VexEmWarn x86g_do_FRSTOR ( VexGuestX86State*, Addr32 ) */
6023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                IRTemp   ew = newTemp(Ity_I32);
6024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                IRDirty* d  = unsafeIRDirty_0_N (
6025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 0/*regparms*/,
6026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 "x86g_dirtyhelper_FRSTOR",
6027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 &x86g_dirtyhelper_FRSTOR,
6028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                 mkIRExprVec_1( mkexpr(addr) )
6029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                              );
6030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->needsBBP = True;
6031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->tmp      = ew;
6032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* declare we're reading memory */
6033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->mFx   = Ifx_Read;
6034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->mAddr = mkexpr(addr);
6035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->mSize = 108;
6036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* declare we're writing guest state */
6038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->nFxState = 5;
6039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[0].fx     = Ifx_Write;
6041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[0].offset = OFFB_FTOP;
6042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[0].size   = sizeof(UInt);
6043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[1].fx     = Ifx_Write;
6045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[1].offset = OFFB_FPREGS;
6046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[1].size   = 8 * sizeof(ULong);
6047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[2].fx     = Ifx_Write;
6049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[2].offset = OFFB_FPTAGS;
6050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[2].size   = 8 * sizeof(UChar);
6051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[3].fx     = Ifx_Write;
6053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[3].offset = OFFB_FPROUND;
6054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[3].size   = sizeof(UInt);
6055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[4].fx     = Ifx_Write;
6057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[4].offset = OFFB_FC3210;
6058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[4].size   = sizeof(UInt);
6059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                stmt( IRStmt_Dirty(d) );
6061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* ew contains any emulation warning we may need to
6063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                   issue.  If needed, side-exit to the next insn,
6064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                   reporting the warning, so that Valgrind's dispatcher
6065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                   sees the warning. */
6066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                put_emwarn( mkexpr(ew) );
6067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                stmt(
6068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                   IRStmt_Exit(
6069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
6070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      Ijk_EmWarn,
6071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
6072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                   )
6073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                );
6074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                DIP("frstor %s\n", dis_buf);
6076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                break;
6077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             }
6078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             case 6: { /* FNSAVE m108 */
6080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* Uses dirty helper:
6081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      void x86g_do_FSAVE ( VexGuestX86State*, UInt ) */
6082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                IRDirty* d = unsafeIRDirty_0_N (
6083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                0/*regparms*/,
6084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                "x86g_dirtyhelper_FSAVE",
6085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                &x86g_dirtyhelper_FSAVE,
6086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                mkIRExprVec_1( mkexpr(addr) )
6087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                             );
6088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->needsBBP = True;
6089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* declare we're writing memory */
6090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->mFx   = Ifx_Write;
6091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->mAddr = mkexpr(addr);
6092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->mSize = 108;
6093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                /* declare we're reading guest state */
6095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->nFxState = 5;
6096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[0].fx     = Ifx_Read;
6098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[0].offset = OFFB_FTOP;
6099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[0].size   = sizeof(UInt);
6100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[1].fx     = Ifx_Read;
6102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[1].offset = OFFB_FPREGS;
6103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[1].size   = 8 * sizeof(ULong);
6104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[2].fx     = Ifx_Read;
6106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[2].offset = OFFB_FPTAGS;
6107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[2].size   = 8 * sizeof(UChar);
6108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[3].fx     = Ifx_Read;
6110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[3].offset = OFFB_FPROUND;
6111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[3].size   = sizeof(UInt);
6112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[4].fx     = Ifx_Read;
6114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[4].offset = OFFB_FC3210;
6115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                d->fxState[4].size   = sizeof(UInt);
6116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                stmt( IRStmt_Dirty(d) );
6118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
6119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                DIP("fnsave %s\n", dis_buf);
6120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                break;
6121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..             }
6122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: { /* FNSTSW m16 */
6124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr* sw = get_FPU_sw();
6125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vassert(typeOfIRExpr(irsb->tyenv, sw) == Ity_I16);
6126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr), sw );
6127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstsw %s\n", dis_buf);
6128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
6133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDD\n");
6134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
6135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
6137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
6138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
6139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FFREE %st(?) */
6141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xC0;
6142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ffree %%st(%u)\n", r_dst);
6143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_TAG ( r_dst, mkU8(0) );
6144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD0 ... 0xD7: /* FST %st(0),%st(?) */
6147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD0;
6148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fst %%st(0),%%st(%u)\n", r_dst);
6149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* P4 manual says: "If the destination operand is a
6150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  non-empty register, the invalid-operation exception
6151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is not generated.  Hence put_ST_UNCHECKED. */
6152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_dst, get_ST(0));
6153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD8 ... 0xDF: /* FSTP %st(0),%st(?) */
6156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xD8;
6157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fstp %%st(0),%%st(%u)\n", r_dst);
6158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* P4 manual says: "If the destination operand is a
6159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  non-empty register, the invalid-operation exception
6160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  is not generated.  Hence put_ST_UNCHECKED. */
6161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(r_dst, get_ST(0));
6162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FUCOM %st(0),%st(?) */
6166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xE0;
6167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucom %%st(0),%%st(%u)\n", r_dst);
6168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
6169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
6170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
6171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
6172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
6173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
6174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
6175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
6176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
6177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMP %st(0),%st(?) */
6180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               r_dst = (UInt)modrm - 0xE8;
6181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fucomp %%st(0),%%st(%u)\n", r_dst);
6182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
6183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
6184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
6185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
6186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
6187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(r_dst)),
6188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
6189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
6190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
6191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
6196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDE opcodes +-+-+-+-+-+-+-+ */
6201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDE) {
6203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
6205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
6207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
6208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp   fop;
6209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
6211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
6213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FIADD m16int */ /* ST(0) += m16int */
6215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fiaddw %s\n", dis_buf);
6216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_AddF64;
6217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
6218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FIMUL m16int */ /* ST(0) *= m16int */
6220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fimulw %s\n", dis_buf);
6221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_MulF64;
6222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
6223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4: /* FISUB m16int */ /* ST(0) -= m16int */
6225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubw %s\n", dis_buf);
6226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
6227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
6228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FISUBR m16int */ /* ST(0) = m16int - ST(0) */
6230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubrw %s\n", dis_buf);
6231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_SubF64;
6232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m16;
6233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6: /* FIDIV m16int */ /* ST(0) /= m16int */
6235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisubw %s\n", dis_buf);
6236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
6237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_fop_m16;
6238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FIDIVR m16int */ /* ST(0) = m16int / ST(0) */
6240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fidivrw %s\n", dis_buf);
6241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fop = Iop_DivF64;
6242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto do_foprev_m16;
6243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_fop_m16:
6245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
6246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
6247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
6248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0),
6249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
6250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_16Sto32,
6251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I16, mkexpr(addr))))));
6252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do_foprev_m16:
6255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_UNCHECKED(0,
6256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  triop(fop,
6257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
6258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_I32StoF64,
6259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_16Sto32,
6260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I16, mkexpr(addr)))),
6261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        get_ST(0)));
6262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
6266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDE\n");
6267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
6268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
6271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
6273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
6274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0 ... 0xC7: /* FADDP %st(0),%st(?) */
6276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "add", Iop_AddF64, 0, modrm - 0xC0, True );
6277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC8 ... 0xCF: /* FMULP %st(0),%st(?) */
6280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "mul", Iop_MulF64, 0, modrm - 0xC8, True );
6281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xD9: /* FCOMPP %st(0),%st(1) */
6284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fcompp %%st(0),%%st(1)\n");
6285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* This forces C1 to zero, which isn't right. */
6286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_C3210(
6287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop(Iop_32Uto64,
6288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop( Iop_And32,
6289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shl32,
6290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_CmpF64, get_ST(0), get_ST(1)),
6291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
6292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU32(0x4500)
6293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )));
6294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0 ... 0xE7: /* FSUBRP %st(0),%st(?) */
6299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "subr", Iop_SubF64, 0,  modrm - 0xE0, True );
6300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FSUBP %st(0),%st(?) */
6303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "sub", Iop_SubF64, 0,  modrm - 0xE8, True );
6304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FDIVRP %st(0),%st(?) */
6307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_oprev_ST_ST ( "divr", Iop_DivF64, 0, modrm - 0xF0, True );
6308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF8 ... 0xFF: /* FDIVP %st(0),%st(?) */
6311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_op_ST_ST ( "div", Iop_DivF64, 0, modrm - 0xF8, True );
6312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
6316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* -+-+-+-+-+-+-+-+-+-+-+-+ 0xDF opcodes +-+-+-+-+-+-+-+ */
6322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (first_opcode == 0xDF) {
6324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (modrm < 0xC0) {
6326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* bits 5,4,3 are an opcode extension, and the modRM also
6328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            specifies an address. */
6329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += len;
6331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
6333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: /* FILD m16int */
6335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildw %s\n", dis_buf);
6336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
6337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, unop(Iop_I32StoF64,
6338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_16Sto32,
6339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   loadLE(Ity_I16, mkexpr(addr)))));
6340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: /* FISTTPS m16 (SSE3) */
6343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fisttps %s\n", dis_buf);
6344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        x87ishly_qnarrow_32_to_16(
6346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) ));
6347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2: /* FIST m16 */
6351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fists %s\n", dis_buf);
6352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        x87ishly_qnarrow_32_to_16(
6354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) ));
6355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3: /* FISTP m16 */
6358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistps %s\n", dis_buf);
6359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        x87ishly_qnarrow_32_to_16(
6361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) ));
6362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5: /* FILD m64 */
6366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fildll %s\n", dis_buf);
6367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_push();
6368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST(0, binop(Iop_I64StoF64,
6369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               get_roundingmode(),
6370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               loadLE(Ity_I64, mkexpr(addr))));
6371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7: /* FISTP m64 */
6374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fistpll %s\n", dis_buf);
6375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
6377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm));
6382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               vex_printf("first_opcode == 0xDF\n");
6383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
6384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
6387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
6389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (modrm) {
6390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0: /* FFREEP %st(0) */
6392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("ffreep %%st(%d)\n", 0);
6393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               put_ST_TAG ( 0, mkU8(0) );
6394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_pop();
6395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE0: /* FNSTSW %ax */
6398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("fnstsw %%ax\n");
6399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* Invent a plausible-looking FPU status word value and
6400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  dump it in %AX:
6401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ((ftop & 7) << 11) | (c3210 & 0x4700)
6402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               */
6403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIRegRAX(
6404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  2,
6405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32to16,
6406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Or32,
6407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shl32,
6408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   binop(Iop_And32, get_ftop(), mkU32(7)),
6409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU8(11)),
6410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_And32,
6411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   unop(Iop_64to32, get_C3210()),
6412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(0x4700))
6413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )));
6414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
6417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );
6418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xF0 ... 0xF7: /* FCOMIP %st(0),%st(?) */
6421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               /* not really right since COMIP != UCOMIP */
6422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               fp_do_ucomi_ST0_STi( (UInt)modrm - 0xF0, True );
6423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
6424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
6426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               goto decode_fail;
6427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
6429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
6433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_fail;
6434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = True;
6436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_fail:
6439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = False;
6440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
6446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- MMX INSTRUCTIONS                                     ---*/
6447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*---                                                      ---*/
6448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
6449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Effect of MMX insns on x87 FPU state (table 11-2 of
6451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IA32 arch manual, volume 3):
6452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Read from, or write to MMX register (viz, any insn except EMMS):
6454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * All tags set to Valid (non-empty) -- FPTAGS[i] := nonzero
6455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP stack pointer set to zero
6456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   EMMS:
6458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * All tags set to Invalid (empty) -- FPTAGS[i] := zero
6459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * FP stack pointer set to zero
6460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
6461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_MMX_preamble ( void )
6463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         i;
6465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
6466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     zero  = mkU32(0);
6467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     tag1  = mkU8(1);
6468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop(zero);
6469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 8; i++)
6470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_PutI( descr, zero, i, tag1 ) );
6471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void do_EMMS_preamble ( void )
6474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int         i;
6476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRRegArray* descr = mkIRRegArray( OFFB_FPTAGS, Ity_I8, 8 );
6477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     zero  = mkU32(0);
6478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr*     tag0  = mkU8(0);
6479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   put_ftop(zero);
6480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = 0; i < 8; i++)
6481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_PutI( descr, zero, i, tag0 ) );
6482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* getMMXReg ( UInt archreg )
6486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
6488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return IRExpr_Get( OFFB_FPREGS + 8 * archreg, Ity_I64 );
6489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void putMMXReg ( UInt archreg, IRExpr* e )
6493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(archreg < 8);
6495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv,e) == Ity_I64);
6496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_FPREGS + 8 * archreg, e ) );
6497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for non-shift MMX insns.  Note this is incomplete in the
6501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sense that it does not first call do_MMX_preamble() -- that is the
6502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   responsibility of its caller. */
6503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_MMXop_regmem_to_reg ( VexAbiInfo* vbi,
6506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                Prefix      pfx,
6507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                Long        delta,
6508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                UChar       opc,
6509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                HChar*      name,
6510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                Bool        show_granularity )
6511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   modrm = getUChar(delta);
6514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    isReg = epartIsReg(modrm);
6515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argL  = NULL;
6516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argR  = NULL;
6517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argG  = NULL;
6518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* argE  = NULL;
6519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  res   = newTemp(Ity_I64);
6520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    invG  = False;
6522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op    = Iop_INVALID;
6523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   void*   hAddr = NULL;
6524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar*  hName = NULL;
6525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    eLeft = False;
6526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  define XXX(_name) do { hAddr = &_name; hName = #_name; } while (0)
6528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
6530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Original MMX ones */
6531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC: op = Iop_Add8x8; break;
6532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD: op = Iop_Add16x4; break;
6533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: op = Iop_Add32x2; break;
6534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC: op = Iop_QAdd8Sx8; break;
6536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: op = Iop_QAdd16Sx4; break;
6537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC: op = Iop_QAdd8Ux8; break;
6539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: op = Iop_QAdd16Ux4; break;
6540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8: op = Iop_Sub8x8;  break;
6542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9: op = Iop_Sub16x4; break;
6543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: op = Iop_Sub32x2; break;
6544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8: op = Iop_QSub8Sx8; break;
6546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: op = Iop_QSub16Sx4; break;
6547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8: op = Iop_QSub8Ux8; break;
6549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: op = Iop_QSub16Ux4; break;
6550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: op = Iop_MulHi16Sx4; break;
6552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: op = Iop_Mul16x4; break;
6553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: XXX(amd64g_calculate_mmx_pmaddwd); break;
6554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74: op = Iop_CmpEQ8x8; break;
6556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75: op = Iop_CmpEQ16x4; break;
6557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: op = Iop_CmpEQ32x2; break;
6558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64: op = Iop_CmpGT8Sx8; break;
6560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65: op = Iop_CmpGT16Sx4; break;
6561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: op = Iop_CmpGT32Sx2; break;
6562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6563b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x6B: op = Iop_QNarrowBin32Sto16Sx4; eLeft = True; break;
6564b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x63: op = Iop_QNarrowBin16Sto8Sx8;  eLeft = True; break;
6565b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      case 0x67: op = Iop_QNarrowBin16Sto8Ux8;  eLeft = True; break;
6566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68: op = Iop_InterleaveHI8x8;  eLeft = True; break;
6568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69: op = Iop_InterleaveHI16x4; eLeft = True; break;
6569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: op = Iop_InterleaveHI32x2; eLeft = True; break;
6570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60: op = Iop_InterleaveLO8x8;  eLeft = True; break;
6572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61: op = Iop_InterleaveLO16x4; eLeft = True; break;
6573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: op = Iop_InterleaveLO32x2; eLeft = True; break;
6574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: op = Iop_And64; break;
6576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: op = Iop_And64; invG = True; break;
6577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: op = Iop_Or64; break;
6578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* Possibly do better here if argL and argR are the
6579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    same reg */
6580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 op = Iop_Xor64; break;
6581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Introduced in SSE1 */
6583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE0: op = Iop_Avg8Ux8;    break;
6584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE3: op = Iop_Avg16Ux4;   break;
6585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEE: op = Iop_Max16Sx4;   break;
6586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDE: op = Iop_Max8Ux8;    break;
6587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEA: op = Iop_Min16Sx4;   break;
6588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDA: op = Iop_Min8Ux8;    break;
6589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE4: op = Iop_MulHi16Ux4; break;
6590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF6: XXX(amd64g_calculate_mmx_psadbw); break;
6591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Introduced in SSE2 */
6593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD4: op = Iop_Add64; break;
6594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFB: op = Iop_Sub64; break;
6595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
6597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n0x%x\n", (Int)opc);
6598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vpanic("dis_MMXop_regmem_to_reg");
6599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#  undef XXX
6602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   argG = getMMXReg(gregLO3ofRM(modrm));
6604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (invG)
6605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argG = unop(Iop_Not64, argG);
6606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isReg) {
6608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argE = getMMXReg(eregLO3ofRM(modrm));
6610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
6612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
6614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argE = loadLE(Ity_I64, mkexpr(addr));
6615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (eLeft) {
6618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argL = argE;
6619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argR = argG;
6620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argL = argG;
6622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      argR = argE;
6623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != Iop_INVALID) {
6626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hName == NULL);
6627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hAddr == NULL);
6628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(op, argL, argR));
6629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hName != NULL);
6631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(hAddr != NULL);
6632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( res,
6633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(
6634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Ity_I64,
6635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 0/*regparms*/, hName, hAddr,
6636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprVec_2( argL, argR )
6637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
6638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
6639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
6642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s%s %s, %s\n",
6644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       name, show_granularity ? nameMMXGran(opc & 3) : "",
6645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( isReg ? nameMMXReg(eregLO3ofRM(modrm)) : dis_buf ),
6646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameMMXReg(gregLO3ofRM(modrm)) );
6647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of G by the amount specified at the bottom
6653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of E.  This is a straight copy of dis_SSE_shiftG_byE. */
6654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_MMX_shiftG_byE ( VexAbiInfo* vbi,
6656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  Prefix pfx, Long delta,
6657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  HChar* opname, IROp op )
6658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
6660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, size;
6661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
6662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
6663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta);
6664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g0   = newTemp(Ity_I64);
6665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g1   = newTemp(Ity_I64);
6666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt  = newTemp(Ity_I64);
6667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt8 = newTemp(Ity_I8);
6668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
6670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, getMMXReg(eregLO3ofRM(rm)) );
6671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(eregLO3ofRM(rm)),
6673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(gregLO3ofRM(rm)) );
6674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
6675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
6677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, loadLE(Ity_I64, mkexpr(addr)) );
6678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
6679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
6680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameMMXReg(gregLO3ofRM(rm)) );
6681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
6682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( g0,   getMMXReg(gregLO3ofRM(rm)) );
6684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt8, unop(Iop_64to8, mkexpr(amt)) );
6685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
6687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
6688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
6689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x4: shl = True; size = 32; break;
6690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x2: shl = True; size = 32; break;
6691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64:    shl = True; size = 64; break;
6692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x4: shr = True; size = 16; break;
6693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x2: shr = True; size = 32; break;
6694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:    shr = True; size = 64; break;
6695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x4: sar = True; size = 16; break;
6696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x2: sar = True; size = 32; break;
6697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
6698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
6701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
6702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
6703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
6704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           mkU64(0),
6706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
6707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
6708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
6709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
6710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
6711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
6712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
6713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
6714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,binop(Iop_CmpLT64U,mkexpr(amt),mkU64(size))),
6715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkU8(size-1)),
6716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
6717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
6718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
6719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
6721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( gregLO3ofRM(rm), mkexpr(g1) );
6724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of E by an immediate byte.  This is a
6729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   straight copy of dis_SSE_shiftE_imm. */
6730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_MMX_shiftE_imm ( Long delta, HChar* opname, IROp op )
6733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
6735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta);
6736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e0   = newTemp(Ity_I64);
6737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e1   = newTemp(Ity_I64);
6738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   amt, size;
6739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(rm));
6740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(gregLO3ofRM(rm) == 2
6741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
6742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amt = getUChar(delta+1);
6743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += 2;
6744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s $%d,%s\n", opname,
6745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)amt,
6746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameMMXReg(eregLO3ofRM(rm)) );
6747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( e0, getMMXReg(eregLO3ofRM(rm)) );
6749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
6751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
6752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
6753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x4: shl = True; size = 16; break;
6754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x2: shl = True; size = 32; break;
6755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shl64:    shl = True; size = 64; break;
6756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x4: sar = True; size = 16; break;
6757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x2: sar = True; size = 32; break;
6758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x4: shr = True; size = 16; break;
6759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x2: shr = True; size = 32; break;
6760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_Shr64:    shr = True; size = 64; break;
6761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
6762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
6765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( e1, amt >= size
6766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    ? mkU64(0)
6767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    : binop(op, mkexpr(e0), mkU8(amt))
6768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
6769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
6770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
6771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( e1, amt >= size
6772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    ? binop(op, mkexpr(e0), mkU8(size-1))
6773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    : binop(op, mkexpr(e0), mkU8(amt))
6774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
6775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
6776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
6777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
6778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putMMXReg( eregLO3ofRM(rm), mkexpr(e1) );
6780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
6781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
6782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Completely handle all MMX instructions except emms. */
6785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
6787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_MMX ( Bool* decode_ok,
6788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi, Prefix pfx, Int sz, Long delta )
6789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
6790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
6791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar modrm;
6792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
6793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar opc = getUChar(delta);
6794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta++;
6795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dis_MMX handles all insns except emms. */
6797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_MMX_preamble();
6798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
6800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6E:
6802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 4) {
6803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* MOVD (src)ireg32-or-mem32 (E), (dst)mmxreg (G)*/
6804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            modrm = getUChar(delta);
6805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (epartIsReg(modrm)) {
6806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta++;
6807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putMMXReg(
6808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  gregLO3ofRM(modrm),
6809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop( Iop_32HLto64,
6810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(0),
6811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIReg32(eregOfRexRM(pfx,modrm)) ) );
6812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd %s, %s\n",
6813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameIReg32(eregOfRexRM(pfx,modrm)),
6814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameMMXReg(gregLO3ofRM(modrm)));
6815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta += len;
6818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putMMXReg(
6819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  gregLO3ofRM(modrm),
6820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop( Iop_32HLto64,
6821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU32(0),
6822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         loadLE(Ity_I32, mkexpr(addr)) ) );
6823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
6827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 8) {
6828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* MOVD (src)ireg64-or-mem64 (E), (dst)mmxreg (G)*/
6829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            modrm = getUChar(delta);
6830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (epartIsReg(modrm)) {
6831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta++;
6832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putMMXReg( gregLO3ofRM(modrm),
6833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getIReg64(eregOfRexRM(pfx,modrm)) );
6834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd %s, %s\n",
6835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameIReg64(eregOfRexRM(pfx,modrm)),
6836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameMMXReg(gregLO3ofRM(modrm)));
6837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta += len;
6840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putMMXReg( gregLO3ofRM(modrm),
6841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
6842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd{64} %s, %s\n", dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
6846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7E:
6851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 4) {
6852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* MOVD (src)mmxreg (G), (dst)ireg32-or-mem32 (E) */
6853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            modrm = getUChar(delta);
6854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (epartIsReg(modrm)) {
6855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta++;
6856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIReg32( eregOfRexRM(pfx,modrm),
6857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd %s, %s\n",
6859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameMMXReg(gregLO3ofRM(modrm)),
6860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameIReg32(eregOfRexRM(pfx,modrm)));
6861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta += len;
6864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_64to32, getMMXReg(gregLO3ofRM(modrm)) ) );
6866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
6870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 8) {
6871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* MOVD (src)mmxreg (G), (dst)ireg64-or-mem64 (E) */
6872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            modrm = getUChar(delta);
6873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (epartIsReg(modrm)) {
6874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta++;
6875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               putIReg64( eregOfRexRM(pfx,modrm),
6876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getMMXReg(gregLO3ofRM(modrm)) );
6877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd %s, %s\n",
6878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameMMXReg(gregLO3ofRM(modrm)),
6879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameIReg64(eregOfRexRM(pfx,modrm)));
6880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } else {
6881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               delta += len;
6883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               storeLE( mkexpr(addr),
6884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       getMMXReg(gregLO3ofRM(modrm)) );
6885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               DIP("movd{64} %s, %s\n", nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            }
6887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6F:
6893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
6894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4
6895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
6896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
6898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
6899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
6900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( gregLO3ofRM(modrm), getMMXReg(eregLO3ofRM(modrm)) );
6901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
6902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(eregLO3ofRM(modrm)),
6903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregLO3ofRM(modrm)));
6904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
6907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putMMXReg( gregLO3ofRM(modrm), loadLE(Ity_I64, mkexpr(addr)) );
6908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n",
6909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                dis_buf, nameMMXReg(gregLO3ofRM(modrm)));
6910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7F:
6914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
6915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4
6916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
6917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
6919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
6920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Fall through.  The assembler doesn't appear to generate
6921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               these. */
6922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
6924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
6925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += len;
6926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
6927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("mov(nt)q %s, %s\n",
6928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameMMXReg(gregLO3ofRM(modrm)), dis_buf);
6929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
6930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC:
6933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD:
6934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
6935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "padd", True );
6938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC:
6941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
6942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4
6943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
6944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "padds", True );
6946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC:
6949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "paddus", True );
6953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8:
6956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9:
6957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
6958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psub", True );
6961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8:
6964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
6965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psubs", True );
6968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8:
6971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
6972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "psubus", True );
6975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
6978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmulhw", False );
6981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
6984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmullw", False );
6987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
6990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(sz == 4);
6991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pmaddwd", False );
6992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
6993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
6994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74:
6995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75:
6996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
6997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
6998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
6999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pcmpeq", True );
7000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64:
7003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65:
7004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
7005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pcmpgt", True );
7008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
7011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packssdw", False );
7014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
7017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packsswb", False );
7020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
7023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "packuswb", False );
7026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68:
7029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69:
7030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
7031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4
7032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
7033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "punpckh", True );
7035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60:
7038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61:
7039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
7040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4
7041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && /*ignore redundant REX.W*/!(sz==8 && haveNo66noF2noF3(pfx)))
7042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "punpckl", True );
7044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
7047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pand", False );
7050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
7053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pandn", False );
7056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
7059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "por", False );
7062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
7065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMXop_regmem_to_reg ( vbi, pfx, delta, opc, "pxor", False );
7068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SHIFT_BY_REG(_name,_op)                                     \
7071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                delta = dis_MMX_shiftG_byE(vbi, pfx, delta, _name, _op); \
7072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                break;
7073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
7075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF1: SHIFT_BY_REG("psllw", Iop_ShlN16x4);
7076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF2: SHIFT_BY_REG("pslld", Iop_ShlN32x2);
7077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF3: SHIFT_BY_REG("psllq", Iop_Shl64);
7078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
7080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD1: SHIFT_BY_REG("psrlw", Iop_ShrN16x4);
7081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD2: SHIFT_BY_REG("psrld", Iop_ShrN32x2);
7082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD3: SHIFT_BY_REG("psrlq", Iop_Shr64);
7083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
7085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE1: SHIFT_BY_REG("psraw", Iop_SarN16x4);
7086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE2: SHIFT_BY_REG("psrad", Iop_SarN32x2);
7087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SHIFT_BY_REG
7089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x71:
7091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x72:
7092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x73: {
7093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
7094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         UChar byte2, subopc;
7095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
7096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         byte2  = getUChar(delta);      /* amode / sub-opcode */
7098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         subopc = toUChar( (byte2 >> 3) & 7 );
7099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        define SHIFT_BY_IMM(_name,_op)                        \
7101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            do { delta = dis_MMX_shiftE_imm(delta,_name,_op);  \
7102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            } while (0)
7103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              if (subopc == 2 /*SRL*/ && opc == 0x71)
7105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  SHIFT_BY_IMM("psrlw", Iop_ShrN16x4);
7106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 2 /*SRL*/ && opc == 0x72)
7107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrld", Iop_ShrN32x2);
7108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 2 /*SRL*/ && opc == 0x73)
7109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrlq", Iop_Shr64);
7110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 4 /*SAR*/ && opc == 0x71)
7112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psraw", Iop_SarN16x4);
7113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 4 /*SAR*/ && opc == 0x72)
7114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psrad", Iop_SarN32x2);
7115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x71)
7117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psllw", Iop_ShlN16x4);
7118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x72)
7119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  SHIFT_BY_IMM("pslld", Iop_ShlN32x2);
7120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else if (subopc == 6 /*SHL*/ && opc == 0x73)
7121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 SHIFT_BY_IMM("psllq", Iop_Shl64);
7122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else goto mmx_decode_failure;
7124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#        undef SHIFT_BY_IMM
7126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF7: {
7130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp addr    = newTemp(Ity_I64);
7131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regD    = newTemp(Ity_I64);
7132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regM    = newTemp(Ity_I64);
7133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp mask    = newTemp(Ity_I64);
7134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddata = newTemp(Ity_I64);
7135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdata = newTemp(Ity_I64);
7136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
7138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 || (!epartIsReg(modrm)))
7139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto mmx_decode_failure;
7140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
7141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( addr, handleAddrOverrides( vbi, pfx, getIReg64(R_RDI) ));
7143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regM, getMMXReg( eregLO3ofRM(modrm) ));
7144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regD, getMMXReg( gregLO3ofRM(modrm) ));
7145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( mask, binop(Iop_SarN8x8, mkexpr(regM), mkU8(7)) );
7146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( olddata, loadLE( Ity_I64, mkexpr(addr) ));
7147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( newdata,
7148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Or64,
7149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
7150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(regD),
7151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(mask) ),
7152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
7153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(olddata),
7154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_Not64, mkexpr(mask)))) );
7155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(newdata) );
7156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("maskmovq %s,%s\n", nameMMXReg( eregLO3ofRM(modrm) ),
7157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg( gregLO3ofRM(modrm) ) );
7158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
7159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* --- MMX decode failure --- */
7162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
7163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx_decode_failure:
7164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *decode_ok = False;
7165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         return delta; /* ignored */
7166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *decode_ok = True;
7170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
7175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- More misc arithmetic and other obscure insns.        ---*/
7176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
7177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate base << amt with vacated places filled with stuff
7179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from xtra.  amt guaranteed in 0 .. 63. */
7180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* shiftL64_with_extras ( IRTemp base, IRTemp xtra, IRTemp amt )
7182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if   amt == 0
7184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      then base
7185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else (base << amt) | (xtra >>u (64-amt))
7186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
7187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr_Mux0X(
7189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkexpr(amt),
7190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkexpr(base),
7191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or64,
7192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl64, mkexpr(base), mkexpr(amt)),
7193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shr64, mkexpr(xtra),
7194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
7195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
7196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate base >>u amt with vacated places filled with stuff
7200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   from xtra.  amt guaranteed in 0 .. 63. */
7201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownIRExpr* shiftR64_with_extras ( IRTemp xtra, IRTemp base, IRTemp amt )
7203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* if   amt == 0
7205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      then base
7206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else (base >>u amt) | (xtra << (64-amt))
7207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
7208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
7209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr_Mux0X(
7210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkexpr(amt),
7211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkexpr(base),
7212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or64,
7213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shr64, mkexpr(base), mkexpr(amt)),
7214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl64, mkexpr(xtra),
7215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Sub8, mkU8(64), mkexpr(amt)))
7216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
7217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
7218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Double length left and right shifts.  Apparently only required in
7221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   v-size (no b- variant). */
7222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_SHLRD_Gv_Ev ( VexAbiInfo* vbi,
7224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Prefix pfx,
7225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Long delta, UChar modrm,
7226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Int sz,
7227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr* shift_amt,
7228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Bool amt_is_literal,
7229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        HChar* shift_amt_txt,
7230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Bool left_shift )
7231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* shift_amt :: Ity_I8 is the amount to shift.  shift_amt_txt is used
7233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for printing it.   And eip on entry points at the modrm byte. */
7234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int len;
7235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
7236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty     = szToITy(sz);
7238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp gsrc   = newTemp(ty);
7239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp esrc   = newTemp(ty);
7240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr   = IRTemp_INVALID;
7241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpSH  = newTemp(Ity_I8);
7242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpSS  = newTemp(Ity_I8);
7243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmp64  = IRTemp_INVALID;
7244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp res64  = IRTemp_INVALID;
7245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rss64  = IRTemp_INVALID;
7246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp resTy  = IRTemp_INVALID;
7247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rssTy  = IRTemp_INVALID;
7248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    mask   = sz==8 ? 63 : 31;
7249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4 || sz == 8);
7251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The E-part is the destination; this is shifted.  The G-part
7253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supplies bits to be shifted into the E-part, but is not
7254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      changed.
7255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If shifting left, form a double-length word with E at the top
7257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and G at the bottom, and shift this left.  The result is then in
7258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the high part.
7259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If shifting right, form a double-length word with G at the top
7261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and E at the bottom, and shift this right.  The result is then
7262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      at the bottom.  */
7263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Fetch the operands. */
7265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( gsrc, getIRegG(sz, pfx, modrm) );
7267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
7269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
7270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( esrc, getIRegE(sz, pfx, modrm) );
7271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sh%cd%c %s, %s, %s\n",
7272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ( left_shift ? 'l' : 'r' ), nameISize(sz),
7273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          shift_amt_txt,
7274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIRegG(sz, pfx, modrm), nameIRegE(sz, pfx, modrm));
7275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta, dis_buf,
7277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        /* # bytes following amode */
7278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        amt_is_literal ? 1 : 0 );
7279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
7280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( esrc, loadLE(ty, mkexpr(addr)) );
7281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sh%cd%c %s, %s, %s\n",
7282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          ( left_shift ? 'l' : 'r' ), nameISize(sz),
7283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          shift_amt_txt,
7284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameIRegG(sz, pfx, modrm), dis_buf);
7285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Calculate the masked shift amount (tmpSH), the masked subshift
7288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      amount (tmpSS), the shifted value (res64) and the subshifted
7289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      value (rss64). */
7290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpSH, binop(Iop_And8, shift_amt, mkU8(mask)) );
7292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( tmpSS, binop(Iop_And8,
7293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Sub8, mkexpr(tmpSH), mkU8(1) ),
7294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(mask)));
7295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   tmp64 = newTemp(Ity_I64);
7297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   res64 = newTemp(Ity_I64);
7298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   rss64 = newTemp(Ity_I64);
7299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2 || sz == 4) {
7301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* G is xtra; E is data */
7303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* what a freaking nightmare: */
7304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4 && left_shift) {
7305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( tmp64, binop(Iop_32HLto64, mkexpr(esrc), mkexpr(gsrc)) );
7306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64,
7307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shr64,
7308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
7309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU8(32)) );
7310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rss64,
7311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shr64,
7312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSS)),
7313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU8(32)) );
7314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
7316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4 && !left_shift) {
7317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( tmp64, binop(Iop_32HLto64, mkexpr(gsrc), mkexpr(esrc)) );
7318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
7319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rss64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSS)) );
7320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
7322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && left_shift) {
7323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( tmp64,
7324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_32HLto64,
7325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_16HLto32, mkexpr(esrc), mkexpr(gsrc)),
7326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc))
7327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
7328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* result formed by shifting [esrc'gsrc'gsrc'gsrc] */
7329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64,
7330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shr64,
7331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shl64, mkexpr(tmp64), mkexpr(tmpSH)),
7332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU8(48)) );
7333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* subshift formed by shifting [esrc'0000'0000'0000] */
7334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rss64,
7335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Shr64,
7336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_Shl64,
7337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shl64, unop(Iop_16Uto64, mkexpr(esrc)),
7338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU8(48)),
7339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(tmpSS)),
7340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkU8(48)) );
7341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
7343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2 && !left_shift) {
7344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( tmp64,
7345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_32HLto64,
7346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(gsrc)),
7347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_16HLto32, mkexpr(gsrc), mkexpr(esrc))
7348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ));
7349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* result formed by shifting [gsrc'gsrc'gsrc'esrc] */
7350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, binop(Iop_Shr64, mkexpr(tmp64), mkexpr(tmpSH)) );
7351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* subshift formed by shifting [0000'0000'0000'esrc] */
7352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rss64, binop(Iop_Shr64,
7353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_16Uto64, mkexpr(esrc)),
7354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(tmpSS)) );
7355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 8);
7360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (left_shift) {
7361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, shiftL64_with_extras( esrc, gsrc, tmpSH ));
7362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rss64, shiftL64_with_extras( esrc, gsrc, tmpSS ));
7363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
7364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res64, shiftR64_with_extras( gsrc, esrc, tmpSH ));
7365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rss64, shiftR64_with_extras( gsrc, esrc, tmpSS ));
7366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   resTy = newTemp(ty);
7371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   rssTy = newTemp(ty);
7372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( resTy, narrowTo(ty, mkexpr(res64)) );
7373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( rssTy, narrowTo(ty, mkexpr(rss64)) );
7374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Put result back and write the flags thunk. */
7376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   setFlags_DEP1_DEP2_shift ( left_shift ? Iop_Shl64 : Iop_Sar64,
7377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              resTy, rssTy, ty, tmpSH );
7378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
7380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegE(sz, pfx, modrm, mkexpr(resTy));
7381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(resTy) );
7383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (amt_is_literal) delta++;
7386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle BT/BTS/BTR/BTC Gv, Ev.  Apparently b-size is not
7391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   required. */
7392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Browntypedef enum { BtOpNone, BtOpSet, BtOpReset, BtOpComp } BtOp;
7394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic HChar* nameBtOp ( BtOp op )
7396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
7398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpNone:  return "";
7399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpSet:   return "s";
7400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpReset: return "r";
7401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case BtOpComp:  return "c";
7402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vpanic("nameBtOp(amd64)");
7403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_bt_G_E ( VexAbiInfo* vbi,
7409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Prefix pfx, Int sz, Long delta, BtOp op )
7410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
7412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  modrm;
7413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int    len;
7414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t_fetched, t_bitno0, t_bitno1, t_bitno2, t_addr0,
7415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     t_addr1, t_rsp, t_mask, t_new;
7416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 2 || sz == 4 || sz == 8);
7418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_fetched = t_bitno0 = t_bitno1 = t_bitno2
7420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = t_addr0 = t_addr1 = t_rsp
7421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             = t_mask = t_new = IRTemp_INVALID;
7422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_fetched = newTemp(Ity_I8);
7424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_new     = newTemp(Ity_I8);
7425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno0  = newTemp(Ity_I64);
7426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno1  = newTemp(Ity_I64);
7427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_bitno2  = newTemp(Ity_I8);
7428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   t_addr1   = newTemp(Ity_I64);
7429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm     = getUChar(delta);
7430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_bitno0, widenSto64(getIRegG(sz, pfx, modrm)) );
7432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
7434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
7435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Get it onto the client's stack.  Oh, this is a horrible
7436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         kludge.  See https://bugs.kde.org/show_bug.cgi?id=245925.
7437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Because of the ELF ABI stack redzone, there may be live data
7438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         up to 128 bytes below %RSP.  So we can't just push it on the
7439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stack, else we may wind up trashing live data, and causing
7440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         impossible-to-find simulation errors.  (Yes, this did
7441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         happen.)  So we need to drop RSP before at least 128 before
7442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pushing it.  That unfortunately means hitting Memcheck's
7443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         fast-case painting code.  Ideally we should drop more than
7444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         128, to reduce the chances of breaking buggy programs that
7445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         have live data below -128(%RSP).  Memcheck fast-cases moves
7446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of 288 bytes due to the need to handle ppc64-linux quickly,
7447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         so let's use 288.  Of course the real fix is to get rid of
7448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this kludge entirely.  */
7449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_rsp = newTemp(Ity_I64);
7450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr0 = newTemp(Ity_I64);
7451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(vbi->guest_stack_redzone_size == 128);
7453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_rsp, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(288)) );
7454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, mkexpr(t_rsp));
7455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t_rsp), getIRegE(sz, pfx, modrm) );
7457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Make t_addr0 point at it. */
7459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_addr0, mkexpr(t_rsp) );
7460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Mask out upper bits of the shift amount, since we're doing a
7462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         reg. */
7463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_bitno1, binop(Iop_And64,
7464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(t_bitno0),
7465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU64(sz == 8 ? 63 : sz == 4 ? 31 : 15)) );
7466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_addr0 = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
7469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
7470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_bitno1, mkexpr(t_bitno0) );
7471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* At this point: t_addr0 is the address being operated on.  If it
7474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      was a reg, we will have pushed it onto the client's stack.
7475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_bitno1 is the bit number, suitably masked in the case of a
7476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg.  */
7477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now the main sequence. */
7479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_addr1,
7480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_Add64,
7481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkexpr(t_addr0),
7482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_Sar64, mkexpr(t_bitno1), mkU8(3))) );
7483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_addr1 now holds effective address */
7485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_bitno2,
7487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_64to8,
7488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_And64, mkexpr(t_bitno1), mkU64(7))) );
7489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_bitno2 contains offset of bit within byte */
7491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != BtOpNone) {
7493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t_mask = newTemp(Ity_I8);
7494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t_mask, binop(Iop_Shl8, mkU8(1), mkexpr(t_bitno2)) );
7495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* t_mask is now a suitable byte mask */
7498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( t_fetched, loadLE(Ity_I8, mkexpr(t_addr1)) );
7500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (op != BtOpNone) {
7502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (op) {
7503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpSet:
7504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
7505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or8, mkexpr(t_fetched), mkexpr(t_mask)) );
7506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpComp:
7508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
7509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Xor8, mkexpr(t_fetched), mkexpr(t_mask)) );
7510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case BtOpReset:
7512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t_new,
7513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_And8, mkexpr(t_fetched),
7514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    unop(Iop_Not8, mkexpr(t_mask))) );
7515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
7516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
7517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("dis_bt_G_E(amd64)");
7518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ((pfx & PFX_LOCK) && !epartIsReg(modrm)) {
7520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(t_addr1), mkexpr(t_fetched)/*expd*/,
7521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 mkexpr(t_new)/*new*/,
7522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 guest_RIP_curr_instr );
7523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
7524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(t_addr1), mkexpr(t_new) );
7525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
7526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Side effect done; now get selected bit into Carry flag */
7529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: C=selected bit, O,S,Z,A,P undefined, so are set to zero. */
7530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
7531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
7534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
7535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shr64,
7536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_8Uto64, mkexpr(t_fetched)),
7537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t_bitno2)),
7538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(1)))
7539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
7540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
7541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
7542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Move reg operand from stack back to reg */
7545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(modrm)) {
7546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t_rsp still points at it. */
7547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* only write the reg if actually modifying it; doing otherwise
7548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         zeroes the top half erroneously when doing btl due to
7549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         standard zero-extend rule */
7550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (op != BtOpNone)
7551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(sz, pfx, modrm, loadLE(szToITy(sz), mkexpr(t_rsp)) );
7552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t_rsp), mkU64(288)) );
7553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("bt%s%c %s, %s\n",
7556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameBtOp(op), nameISize(sz), nameIRegG(sz, pfx, modrm),
7557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( epartIsReg(modrm) ? nameIRegE(sz, pfx, modrm) : dis_buf ) );
7558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle BSF/BSR.  Only v-size seems necessary. */
7565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_bs_E_G ( VexAbiInfo* vbi,
7567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   Prefix pfx, Int sz, Long delta, Bool fwds )
7568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool   isReg;
7570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  modrm;
7571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar  dis_buf[50];
7572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
7574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src   = newTemp(ty);
7575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst   = newTemp(ty);
7576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src64 = newTemp(Ity_I64);
7577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dst64 = newTemp(Ity_I64);
7578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src8  = newTemp(Ity_I8);
7579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 8 || sz == 4 || sz == 2);
7581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   modrm = getUChar(delta);
7583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   isReg = epartIsReg(modrm);
7584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (isReg) {
7585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
7586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIRegE(sz, pfx, modrm) );
7587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
7588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    len;
7589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode( &len, vbi, pfx, delta, dis_buf, 0 );
7590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
7591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, loadLE(ty, mkexpr(addr)) );
7592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("bs%c%c %s, %s\n",
7595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       fwds ? 'f' : 'r', nameISize(sz),
7596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ( isReg ? nameIRegE(sz, pfx, modrm) : dis_buf ),
7597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameIRegG(sz, pfx, modrm));
7598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First, widen src to 64 bits if it is not already. */
7600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( src64, widenUto64(mkexpr(src)) );
7601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Generate an 8-bit expression which is zero iff the
7603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      original is zero, and nonzero otherwise */
7604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( src8,
7605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,
7606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_CmpNE64,
7607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(src64), mkU64(0))) );
7608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Flags: Z is 1 iff source value is zero.  All others
7610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      are undefined -- we force them to zero. */
7611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
7612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put(
7614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            OFFB_CC_DEP1,
7615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRExpr_Mux0X( mkexpr(src8),
7616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /* src==0 */
7617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU64(AMD64G_CC_MASK_Z),
7618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          /* src!=0 */
7619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkU64(0)
7620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        )
7621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       ));
7622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set NDEP even though it isn't used.  This makes redundant-PUT
7623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      elimination of previous stores to this field work better. */
7624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Result: iff source value is zero, we can't use
7627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Iop_Clz64/Iop_Ctz64 as they have no defined result in that case.
7628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      But anyway, amd64 semantics say the result is undefined in
7629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      such situations.  Hence handle the zero case specially. */
7630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Bleh.  What we compute:
7632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf64:  if src == 0 then {dst is unchanged}
7634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              else Ctz64(src)
7635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr64:  if src == 0 then {dst is unchanged}
7637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              else 63 - Clz64(src)
7638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf32:  if src == 0 then {dst is unchanged}
7640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              else Ctz64(32Uto64(src))
7641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr32:  if src == 0 then {dst is unchanged}
7643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              else 63 - Clz64(32Uto64(src))
7644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsf16:  if src == 0 then {dst is unchanged}
7646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              else Ctz64(32Uto64(16Uto32(src)))
7647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          bsr16:  if src == 0 then {dst is unchanged}
7649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              else 63 - Clz64(32Uto64(16Uto32(src)))
7650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
7651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The main computation, guarding against zero. */
7653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( dst64,
7654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           IRExpr_Mux0X(
7655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkexpr(src8),
7656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* src == 0 -- leave dst unchanged */
7657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              widenUto64( getIRegG( sz, pfx, modrm ) ),
7658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              /* src != 0 */
7659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              fwds ? unop(Iop_Ctz64, mkexpr(src64))
7660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   : binop(Iop_Sub64,
7661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkU64(63),
7662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_Clz64, mkexpr(src64)))
7663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           )
7664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
7665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 2)
7667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, unop(Iop_64to16, mkexpr(dst64)) );
7668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
7669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4)
7670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, unop(Iop_64to32, mkexpr(dst64)) );
7671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
7672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst, mkexpr(dst64) );
7673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* dump result back */
7675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIRegG( sz, pfx, modrm, mkexpr(dst) );
7676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
7678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* swap rAX with the reg specified by reg and REX.B */
7682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_xchg_rAX_Reg ( Prefix pfx, Int sz, UInt regLo3 )
7684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty = szToITy(sz);
7686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(ty);
7687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(ty);
7688b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   vassert(sz == 2 || sz == 4 || sz == 8);
7689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(regLo3 < 8);
7690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8) {
7691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, getIReg64(R_RAX) );
7692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, getIRegRexB(8, pfx, regLo3) );
7693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64( R_RAX, mkexpr(t2) );
7694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRexB(8, pfx, regLo3, mkexpr(t1) );
7695b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else if (sz == 4) {
7696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, getIReg32(R_RAX) );
7697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, getIRegRexB(4, pfx, regLo3) );
7698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg32( R_RAX, mkexpr(t2) );
7699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRexB(4, pfx, regLo3, mkexpr(t1) );
7700b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   } else {
7701b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( t1, getIReg16(R_RAX) );
7702b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( t2, getIRegRexB(2, pfx, regLo3) );
7703b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putIReg16( R_RAX, mkexpr(t2) );
7704b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putIRegRexB(2, pfx, regLo3, mkexpr(t1) );
7705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("xchg%c %s, %s\n",
7707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       nameISize(sz), nameIRegRAX(sz),
7708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameIRegRexB(sz,pfx, regLo3));
7709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_SAHF ( void )
7714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set the flags to:
7716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (amd64g_calculate_flags_all() & AMD64G_CC_MASK_O)
7717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    -- retain the old O flag
7718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      | (%AH & (AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                |AMD64G_CC_MASK_P|AMD64G_CC_MASK_C)
7720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
7721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong  mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp oldflags   = newTemp(Ity_I64);
7724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldflags, mk_amd64g_calculate_rflags_all() );
7725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
7726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
7727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
7728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_CC_DEP1,
7729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or64,
7730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64, mkexpr(oldflags), mkU64(AMD64G_CC_MASK_O)),
7731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64,
7732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(Iop_Shr64, getIReg64(R_RAX), mkU8(8)),
7733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU64(mask_SZACP))
7734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
7735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ));
7736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid codegen_LAHF ( void  )
7741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* AH <- EFLAGS(SF:ZF:0:AF:0:PF:1:CF) */
7743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* rax_with_hole;
7744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* new_byte;
7745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* new_rax;
7746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ULong   mask_SZACP = AMD64G_CC_MASK_S|AMD64G_CC_MASK_Z|AMD64G_CC_MASK_A
7747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        |AMD64G_CC_MASK_C|AMD64G_CC_MASK_P;
7748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  flags = newTemp(Ity_I64);
7750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( flags, mk_amd64g_calculate_rflags_all() );
7751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   rax_with_hole
7753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_And64, getIReg64(R_RAX), mkU64(~0xFF00ULL));
7754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_byte
7755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_Or64, binop(Iop_And64, mkexpr(flags), mkU64(mask_SZACP)),
7756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU64(1<<1));
7757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   new_rax
7758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = binop(Iop_Or64, rax_with_hole,
7759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, new_byte, mkU8(8)));
7760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg64(R_RAX, new_rax);
7761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_cmpxchg_G_E ( /*OUT*/Bool* ok,
7766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        VexAbiInfo*  vbi,
7767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Prefix       pfx,
7768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Int          size,
7769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        Long         delta0 )
7770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
7772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
7773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(size);
7775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp acc   = newTemp(ty);
7776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp src   = newTemp(ty);
7777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dest  = newTemp(ty);
7778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp dest2 = newTemp(ty);
7779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp acc2  = newTemp(ty);
7780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp cond8 = newTemp(Ity_I8);
7781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp addr  = IRTemp_INVALID;
7782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar  rm    = getUChar(delta0);
7783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are 3 cases to consider:
7785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-reg: ignore any lock prefix, generate sequence based
7787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               on Mux0X
7788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, not locked: ignore any lock prefix, generate sequence
7790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           based on Mux0X
7791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, locked: use IRCAS
7793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
7794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 1 */
7797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest, getIRegE(size, pfx, rm) );
7798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0++;
7799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIRegG(size, pfx, rm) );
7800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIRegRAX(size) );
7801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc2,  IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRAX(size, mkexpr(acc2));
7806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegE(size, pfx, rm, mkexpr(dest2));
7807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
7808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegG(size,pfx,rm),
7809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegE(size,pfx,rm) );
7810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && !(pfx & PFX_LOCK)) {
7812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 2 */
7813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest, loadLE(ty, mkexpr(addr)) );
7815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0 += len;
7816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIRegG(size, pfx, rm) );
7817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIRegRAX(size) );
7818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dest2, IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(src)) );
7821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc2,  IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRAX(size, mkexpr(acc2));
7823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(dest2) );
7824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
7825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegG(size,pfx,rm), dis_buf);
7826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && (pfx & PFX_LOCK)) {
7828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 3 */
7829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* src is new value.  acc is expected value.  dest is old value.
7830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Compute success from the output of the IRCAS, and steer the
7831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         new value for RAX accordingly: in case of success, RAX is
7832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unchanged. */
7833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta0 += len;
7835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( src, getIRegG(size, pfx, rm) );
7836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc, getIRegRAX(size) );
7837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_CAS(
7838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkIRCAS( IRTemp_INVALID, dest, Iend_LE, mkexpr(addr),
7839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  NULL, mkexpr(acc), NULL, mkexpr(src) )
7840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
7841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2(Iop_Sub8, acc, dest, ty);
7842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( cond8, unop(Iop_1Uto8, mk_amd64g_calculate_condition(AMD64CondZ)) );
7843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( acc2,  IRExpr_Mux0X(mkexpr(cond8), mkexpr(dest), mkexpr(acc)) );
7844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRAX(size, mkexpr(acc2));
7845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmpxchg%c %s,%s\n", nameISize(size),
7846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegG(size,pfx,rm), dis_buf);
7847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else vassert(0);
7849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *ok = True;
7851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta0;
7852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handle conditional move instructions of the form
7856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cmovcc E(reg-or-mem), G(reg)
7857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   E(src) is reg-or-mem
7859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   G(dst) is reg.
7860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is reg, -->    GET %E, tmps
7862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpd
7863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       CMOVcc tmps, tmpd
7864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpd, %G
7865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   If E is mem  -->    (getAddr E) -> tmpa
7867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       LD (tmpa), tmps
7868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       GET %G, tmpd
7869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       CMOVcc tmps, tmpd
7870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       PUT tmpd, %G
7871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
7872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_cmov_E_G ( VexAbiInfo* vbi,
7874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Prefix        pfx,
7875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Int           sz,
7876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     AMD64Condcode cond,
7877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Long          delta0 )
7878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm  = getUChar(delta0);
7880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
7881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
7882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty   = szToITy(sz);
7884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmps = newTemp(ty);
7885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpd = newTemp(ty);
7886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmps, getIRegE(sz, pfx, rm) );
7889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIRegG(sz, pfx, rm) );
7890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG( sz, pfx, rm,
7892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                IRExpr_Mux0X( unop(Iop_1Uto8,
7893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mk_amd64g_calculate_condition(cond)),
7894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(tmpd),
7895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(tmps) )
7896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
7897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIRegE(sz,pfx,rm),
7899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIRegG(sz,pfx,rm));
7900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
7901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* E refers to memory */
7904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
7905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmps, loadLE(ty, mkexpr(addr)) );
7907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIRegG(sz, pfx, rm) );
7908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG( sz, pfx, rm,
7910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                IRExpr_Mux0X( unop(Iop_1Uto8,
7911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mk_amd64g_calculate_condition(cond)),
7912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(tmpd),
7913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(tmps) )
7914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
7915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cmov%s %s,%s\n", name_AMD64Condcode(cond),
7917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            dis_buf,
7918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIRegG(sz,pfx,rm));
7919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
7920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
7925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_xadd_G_E ( /*OUT*/Bool* decode_ok,
7926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     VexAbiInfo* vbi,
7927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Prefix pfx, Int sz, Long delta0 )
7928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
7929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int   len;
7930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar rm = getUChar(delta0);
7931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar dis_buf[50];
7932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType ty    = szToITy(sz);
7934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpd  = newTemp(ty);
7935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpt0 = newTemp(ty);
7936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp tmpt1 = newTemp(ty);
7937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* There are 3 cases to consider:
7939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-reg: ignore any lock prefix,
7941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               generate 'naive' (non-atomic) sequence
7942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, not locked: ignore any lock prefix, generate 'naive'
7944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           (non-atomic) sequence
7945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      reg-mem, locked: use IRCAS
7947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
7948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
7950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 1 */
7951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd, getIRegE(sz, pfx, rm) );
7952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIRegG(sz, pfx, rm) );
7953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
7955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(sz, pfx, rm, mkexpr(tmpd));
7957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegE(sz, pfx, rm, mkexpr(tmpt1));
7958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
7959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIRegG(sz,pfx,rm),
7960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          				 nameIRegE(sz,pfx,rm));
7961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_ok = True;
7962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return 1+delta0;
7963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && !(pfx & PFX_LOCK)) {
7965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 2 */
7966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
7968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIRegG(sz, pfx, rm) );
7969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
7971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(tmpt1) );
7973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(sz, pfx, rm, mkexpr(tmpd));
7974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
7975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_ok = True;
7977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
7978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else if (!epartIsReg(rm) && (pfx & PFX_LOCK)) {
7980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* case 3 */
7981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addr = disAMode ( &len, vbi, pfx, delta0, dis_buf, 0 );
7982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpd,  loadLE(ty, mkexpr(addr)) );
7983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt0, getIRegG(sz, pfx, rm) );
7984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmpt1, binop(mkSizedOp(ty,Iop_Add8),
7985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpd), mkexpr(tmpt0)) );
7986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      casLE( mkexpr(addr), mkexpr(tmpd)/*expVal*/,
7987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(tmpt1)/*newVal*/, guest_RIP_curr_instr );
7988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      setFlags_DEP1_DEP2( Iop_Add8, tmpd, tmpt0, ty );
7989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(sz, pfx, rm, mkexpr(tmpd));
7990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("xadd%c %s, %s\n",
7991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          nameISize(sz), nameIRegG(sz,pfx,rm), dis_buf);
7992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *decode_ok = True;
7993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return len+delta0;
7994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
7995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*UNREACHED*/
7996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(0);
7997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
7998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
7999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. /* Move 16 bits from Ew (ireg or mem) to G (a segment register). */
8000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
8002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. UInt dis_mov_Ew_Sw ( UChar sorb, Long delta0 )
8003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
8004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Int    len;
8005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    IRTemp addr;
8006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    UChar  rm  = getUChar(delta0);
8007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    HChar  dis_buf[50];
8008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (epartIsReg(rm)) {
8010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putSReg( gregOfRM(rm), getIReg(2, eregOfRM(rm)) );
8011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       DIP("movw %s,%s\n", nameIReg(2,eregOfRM(rm)), nameSReg(gregOfRM(rm)));
8012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return 1+delta0;
8013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    } else {
8014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       addr = disAMode ( &len, sorb, delta0, dis_buf );
8015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putSReg( gregOfRM(rm), loadLE(Ity_I16, mkexpr(addr)) );
8016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       DIP("movw %s,%s\n", dis_buf, nameSReg(gregOfRM(rm)));
8017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return len+delta0;
8018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
8019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
8020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. /* Move 16 bits from G (a segment register) to Ew (ireg or mem).  If
8022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    dst is ireg and sz==4, zero out top half of it.  */
8023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
8025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. UInt dis_mov_Sw_Ew ( UChar sorb,
8026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      Int   sz,
8027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                      UInt  delta0 )
8028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
8029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    Int    len;
8030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    IRTemp addr;
8031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    UChar  rm  = getUChar(delta0);
8032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    HChar  dis_buf[50];
8033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    vassert(sz == 2 || sz == 4);
8035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    if (epartIsReg(rm)) {
8037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       if (sz == 4)
8038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          putIReg(4, eregOfRM(rm), unop(Iop_16Uto32, getSReg(gregOfRM(rm))));
8039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       else
8040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          putIReg(2, eregOfRM(rm), getSReg(gregOfRM(rm)));
8041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), nameIReg(sz,eregOfRM(rm)));
8043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return 1+delta0;
8044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    } else {
8045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       addr = disAMode ( &len, sorb, delta0, dis_buf );
8046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( mkexpr(addr), getSReg(gregOfRM(rm)) );
8047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       DIP("mov %s,%s\n", nameSReg(gregOfRM(rm)), dis_buf);
8048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       return len+delta0;
8049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
8050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
8051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
8054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. void dis_push_segreg ( UInt sreg, Int sz )
8055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
8056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     IRTemp t1 = newTemp(Ity_I16);
8057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     IRTemp ta = newTemp(Ity_I32);
8058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     vassert(sz == 2 || sz == 4);
8059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     assign( t1, getSReg(sreg) );
8061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     assign( ta, binop(Iop_Sub32, getIReg(4, R_ESP), mkU32(sz)) );
8062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     putIReg(4, R_ESP, mkexpr(ta));
8063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     storeLE( mkexpr(ta), mkexpr(t1) );
8064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     DIP("pushw %s\n", nameSReg(sreg));
8066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
8067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. static
8069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. void dis_pop_segreg ( UInt sreg, Int sz )
8070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. {
8071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     IRTemp t1 = newTemp(Ity_I16);
8072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     IRTemp ta = newTemp(Ity_I32);
8073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     vassert(sz == 2 || sz == 4);
8074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     assign( ta, getIReg(4, R_ESP) );
8076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     assign( t1, loadLE(Ity_I16, mkexpr(ta)) );
8077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
8078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     putIReg(4, R_ESP, binop(Iop_Add32, mkexpr(ta), mkU32(sz)) );
8079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     putSReg( sreg, mkexpr(t1) );
8080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..     DIP("pop %s\n", nameSReg(sreg));
8081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. }
8082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
8084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownvoid dis_ret ( VexAbiInfo* vbi, ULong d64 )
8085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t1 = newTemp(Ity_I64);
8087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t2 = newTemp(Ity_I64);
8088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp t3 = newTemp(Ity_I64);
8089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t1, getIReg64(R_RSP));
8090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t2, loadLE(Ity_I64,mkexpr(t1)));
8091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(t3, binop(Iop_Add64, mkexpr(t1), mkU64(8+d64)));
8092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putIReg64(R_RSP, mkexpr(t3));
8093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   make_redzone_AbiHint(vbi, t3, t2/*nia*/, "ret");
8094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jmp_treg(Ijk_Ret,t2);
8095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- SSE/SSE2/SSE3 helpers                                ---*/
8100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
8101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Worker function; do not call directly.
8103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Handles full width G = G `op` E   and   G = (not G) `op` E.
8104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_E_to_G_all_wrk (
8107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi,
8108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Prefix pfx, Long delta,
8109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                HChar* opname, IROp op,
8110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Bool   invertG
8111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
8112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart
8118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      = invertG ? unop(Iop_NotV128, getXMMReg(gregOfRexRM(pfx,rm)))
8119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                : getXMMReg(gregOfRexRM(pfx,rm));
8120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
8123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRexRM(pfx,rm))) );
8124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
8128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
8132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_V128, mkexpr(addr))) );
8133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
8137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes SSE binary operation, G = G `op` E. */
8142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
8144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_SSE_E_to_G_all ( VexAbiInfo* vbi,
8145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Prefix pfx, Long delta,
8146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           HChar* opname, IROp op )
8147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dis_SSE_E_to_G_all_wrk( vbi, pfx, delta, opname, op, False );
8149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes SSE binary operation, G = (not G) `op` E. */
8152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
8154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_SSE_E_to_G_all_invG ( VexAbiInfo* vbi,
8155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                Prefix pfx, Long delta,
8156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                HChar* opname, IROp op )
8157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dis_SSE_E_to_G_all_wrk( vbi, pfx, delta, opname, op, True );
8159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
8163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_E_to_G_lo32 ( VexAbiInfo* vbi,
8165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   Prefix pfx, Long delta,
8166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HChar* opname, IROp op )
8167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
8173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
8176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRexRM(pfx,rm))) );
8177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
8181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can only do a 32-bit memory read, so the upper 3/4 of the
8183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         E operand needs to be made simply of zeroes. */
8184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp epart = newTemp(Ity_V128);
8185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( epart, unop( Iop_32UtoV128,
8187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_I32, mkexpr(addr))) );
8188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart, mkexpr(epart)) );
8190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
8194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
8199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_E_to_G_lo64 ( VexAbiInfo* vbi,
8201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   Prefix pfx, Long delta,
8202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   HChar* opname, IROp op )
8203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
8209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart,
8212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           getXMMReg(eregOfRexRM(pfx,rm))) );
8213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
8217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* We can only do a 64-bit memory read, so the upper half of the
8219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         E operand needs to be made simply of zeroes. */
8220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp epart = newTemp(Ity_V128);
8221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( epart, unop( Iop_64UtoV128,
8223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           loadLE(Ity_I64, mkexpr(addr))) );
8224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(op, gpart, mkexpr(epart)) );
8226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
8230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* All lanes unary SSE operation, G = op(E). */
8235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_E_to_G_unary_all (
8237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi,
8238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Prefix pfx, Long delta,
8239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                HChar* opname, IROp op
8240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
8241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(op, getXMMReg(eregOfRexRM(pfx,rm))) );
8249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
8253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(op, loadLE(Ity_V128, mkexpr(addr))) );
8257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
8261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
8266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_E_to_G_unary_lo32 (
8268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi,
8269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Prefix pfx, Long delta,
8270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                HChar* opname, IROp op
8271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
8272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First we need to get the old G value and patch the low 32 bits
8274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of the E operand into it.  Then apply op and write back to G. */
8275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG0 = newTemp(Ity_V128);
8280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG1 = newTemp(Ity_V128);
8281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
8283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
8286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo32,
8287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
8288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getXMMRegLane32(eregOfRexRM(pfx,rm), 0)) );
8289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
8294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
8297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo32,
8298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
8299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     loadLE(Ity_I32, mkexpr(addr)) ));
8300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
8305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
8310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_E_to_G_unary_lo64 (
8312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi,
8313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Prefix pfx, Long delta,
8314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                HChar* opname, IROp op
8315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
8316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* First we need to get the old G value and patch the low 64 bits
8318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of the E operand into it.  Then apply op and write back to G. */
8319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG0 = newTemp(Ity_V128);
8324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  oldG1 = newTemp(Ity_V128);
8325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( oldG0, getXMMReg(gregOfRexRM(pfx,rm)) );
8327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
8330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo64,
8331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
8332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     getXMMRegLane64(eregOfRexRM(pfx,rm), 0)) );
8333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+1;
8338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( oldG1,
8341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_SetV128lo64,
8342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkexpr(oldG0),
8343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     loadLE(Ity_I64, mkexpr(addr)) ));
8344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm), unop(op, mkexpr(oldG1)) );
8345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      return delta+alen;
8349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* SSE integer binary operation:
8354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G = G `op` E   (eLeft == False)
8355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G = E `op` G   (eLeft == True)
8356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSEint_E_to_G(
8358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                VexAbiInfo* vbi,
8359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Prefix pfx, Long delta,
8360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                HChar* opname, IROp op,
8361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                Bool   eLeft
8362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
8363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen;
8366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm = getUChar(delta);
8368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm));
8369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRExpr* epart = NULL;
8370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      epart = getXMMReg(eregOfRexRM(pfx,rm));
8372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 1;
8376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr  = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      epart = loadLE(Ity_V128, mkexpr(addr));
8379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
8383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( gregOfRexRM(pfx,rm),
8385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              eLeft ? binop(op, epart, gpart)
8386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	            : binop(op, gpart, epart) );
8387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
8388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for doing SSE FP comparisons. */
8392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void findSSECmpOp ( Bool* needNot, IROp* op,
8394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Int imm8, Bool all_lanes, Int sz )
8395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   imm8 &= 7;
8397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *needNot = False;
8398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *op      = Iop_INVALID;
8399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (imm8 >= 4) {
8400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      *needNot = True;
8401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 -= 4;
8402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && all_lanes) {
8405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
8406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ32Fx4; return;
8407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT32Fx4; return;
8408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE32Fx4; return;
8409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN32Fx4; return;
8410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
8411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 4 && !all_lanes) {
8414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
8415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ32F0x4; return;
8416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT32F0x4; return;
8417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE32F0x4; return;
8418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN32F0x4; return;
8419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
8420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 && all_lanes) {
8423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
8424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ64Fx2; return;
8425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT64Fx2; return;
8426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE64Fx2; return;
8427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN64Fx2; return;
8428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
8429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sz == 8 && !all_lanes) {
8432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8) {
8433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: *op = Iop_CmpEQ64F0x2; return;
8434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: *op = Iop_CmpLT64F0x2; return;
8435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: *op = Iop_CmpLE64F0x2; return;
8436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: *op = Iop_CmpUN64F0x2; return;
8437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: break;
8438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
8439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vpanic("findSSECmpOp(amd64,guest)");
8441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Handles SSE 32F/64F comparisons. */
8444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSEcmp_E_to_G ( VexAbiInfo* vbi,
8446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Prefix pfx, Long delta,
8447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 HChar* opname, Bool all_lanes, Int sz )
8448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, imm8;
8451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    needNot = False;
8453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp    op      = Iop_INVALID;
8454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  plain   = newTemp(Ity_V128);
8455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm      = getUChar(delta);
8456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UShort  mask    = 0;
8457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(sz == 4 || sz == 8);
8458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 = getUChar(delta+1);
8460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
8461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( plain, binop(op, getXMMReg(gregOfRexRM(pfx,rm)),
8462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getXMMReg(eregOfRexRM(pfx,rm))) );
8463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
8464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s $%d,%s,%s\n", opname,
8465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (Int)imm8,
8466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(eregOfRexRM(pfx,rm)),
8467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(gregOfRexRM(pfx,rm)) );
8468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 1 );
8470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8 = getUChar(delta+alen);
8471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
8472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( plain,
8473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(
8474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 op,
8475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 getXMMReg(gregOfRexRM(pfx,rm)),
8476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   all_lanes  ? loadLE(Ity_V128, mkexpr(addr))
8477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 : sz == 8    ? unop( Iop_64UtoV128, loadLE(Ity_I64, mkexpr(addr)))
8478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 : /*sz==4*/    unop( Iop_32UtoV128, loadLE(Ity_I32, mkexpr(addr)))
8479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      )
8480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen+1;
8482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s $%d,%s,%s\n", opname,
8483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            (Int)imm8,
8484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            dis_buf,
8485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameXMMReg(gregOfRexRM(pfx,rm)) );
8486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (needNot && all_lanes) {
8489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop(Iop_NotV128, mkexpr(plain)) );
8491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else
8493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (needNot && !all_lanes) {
8494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask = toUShort(sz==4 ? 0x000F : 0x00FF);
8495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm),
8496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_XorV128, mkexpr(plain), mkV128(mask)) );
8497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   else {
8499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,rm), mkexpr(plain) );
8500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
8503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of G by the amount specified at the bottom
8507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   of E. */
8508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic ULong dis_SSE_shiftG_byE ( VexAbiInfo* vbi,
8510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  Prefix pfx, Long delta,
8511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  HChar* opname, IROp op )
8512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar   dis_buf[50];
8514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int     alen, size;
8515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  addr;
8516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
8517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta);
8518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g0   = newTemp(Ity_V128);
8519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  g1   = newTemp(Ity_V128);
8520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt  = newTemp(Ity_I32);
8521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  amt8 = newTemp(Ity_I8);
8522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (epartIsReg(rm)) {
8523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, getXMMRegLane32(eregOfRexRM(pfx,rm), 0) );
8524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(eregOfRexRM(pfx,rm)),
8526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
8528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
8530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
8531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%s %s,%s\n", opname,
8532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        dis_buf,
8533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        nameXMMReg(gregOfRexRM(pfx,rm)) );
8534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
8535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( g0,   getXMMReg(gregOfRexRM(pfx,rm)) );
8537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
8538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
8540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
8541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
8542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x8: shl = True; size = 32; break;
8543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x4: shl = True; size = 32; break;
8544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN64x2: shl = True; size = 64; break;
8545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x8: sar = True; size = 16; break;
8546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x4: sar = True; size = 32; break;
8547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x8: shr = True; size = 16; break;
8548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x4: shr = True; size = 32; break;
8549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN64x2: shr = True; size = 64; break;
8550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
8551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
8554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
8555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
8556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
8557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,
8558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           mkV128(0x0000),
8560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
8561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
8562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
8563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
8564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
8565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign(
8566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        g1,
8567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        IRExpr_Mux0X(
8568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           unop(Iop_1Uto8,
8569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_CmpLT64U, unop(Iop_32Uto64,mkexpr(amt)), mkU64(size))),
8570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkU8(size-1)),
8571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(op, mkexpr(g0), mkexpr(amt8))
8572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
8573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
8574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
8576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( gregOfRexRM(pfx,rm), mkexpr(g1) );
8579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
8580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Vector by scalar shift of E by an immediate byte. */
8584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
8586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownULong dis_SSE_shiftE_imm ( Prefix pfx,
8587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Long delta, HChar* opname, IROp op )
8588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool    shl, shr, sar;
8590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   rm   = getUChar(delta);
8591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e0   = newTemp(Ity_V128);
8592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp  e1   = newTemp(Ity_V128);
8593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar   amt, size;
8594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(epartIsReg(rm));
8595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(gregLO3ofRM(rm) == 2
8596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6);
8597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   amt = getUChar(delta+1);
8598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   delta += 2;
8599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("%s $%d,%s\n", opname,
8600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      (Int)amt,
8601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      nameXMMReg(eregOfRexRM(pfx,rm)) );
8602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( e0, getXMMReg(eregOfRexRM(pfx,rm)) );
8603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   shl = shr = sar = False;
8605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   size = 0;
8606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (op) {
8607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN16x8: shl = True; size = 16; break;
8608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN32x4: shl = True; size = 32; break;
8609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShlN64x2: shl = True; size = 64; break;
8610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN16x8: sar = True; size = 16; break;
8611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_SarN32x4: sar = True; size = 32; break;
8612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN16x8: shr = True; size = 16; break;
8613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN32x4: shr = True; size = 32; break;
8614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case Iop_ShrN64x2: shr = True; size = 64; break;
8615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
8616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (shl || shr) {
8619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( e1, amt >= size
8620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    ? mkV128(0x0000)
8621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    : binop(op, mkexpr(e0), mkU8(amt))
8622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
8623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else
8624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (sar) {
8625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( e1, amt >= size
8626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    ? binop(op, mkexpr(e0), mkU8(size-1))
8627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    : binop(op, mkexpr(e0), mkU8(amt))
8628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     );
8629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } else {
8630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(0);
8631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) );
8634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return delta;
8635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Get the current SSE rounding mode. */
8639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
8641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      unop( Iop_64to32,
8644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( Iop_And64,
8645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   IRExpr_Get( OFFB_SSEROUND, Ity_I64 ),
8646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkU64(3) ));
8647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void put_sse_roundingmode ( IRExpr* sseround )
8650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(typeOfIRExpr(irsb->tyenv, sseround) == Ity_I32);
8652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_SSEROUND,
8653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_32Uto64,sseround) ) );
8654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Break a 128-bit value up into four 32-bit ints. */
8657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void breakup128to32s ( IRTemp t128,
8659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              /*OUTs*/
8660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp* t3, IRTemp* t2,
8661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp* t1, IRTemp* t0 )
8662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp hi64 = newTemp(Ity_I64);
8664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp lo64 = newTemp(Ity_I64);
8665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( hi64, unop(Iop_V128HIto64, mkexpr(t128)) );
8666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( lo64, unop(Iop_V128to64,   mkexpr(t128)) );
8667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t0 && *t0 == IRTemp_INVALID);
8669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t1 && *t1 == IRTemp_INVALID);
8670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t2 && *t2 == IRTemp_INVALID);
8671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t3 && *t3 == IRTemp_INVALID);
8672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t0 = newTemp(Ity_I32);
8674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t1 = newTemp(Ity_I32);
8675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t2 = newTemp(Ity_I32);
8676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t3 = newTemp(Ity_I32);
8677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t0, unop(Iop_64to32,   mkexpr(lo64)) );
8678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t1, unop(Iop_64HIto32, mkexpr(lo64)) );
8679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t2, unop(Iop_64to32,   mkexpr(hi64)) );
8680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t3, unop(Iop_64HIto32, mkexpr(hi64)) );
8681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Construct a 128-bit value from four 32-bit ints. */
8684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
8686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRTemp t1, IRTemp t0 )
8687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_64HLtoV128,
8690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_32HLto64, mkexpr(t3), mkexpr(t2)),
8691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_32HLto64, mkexpr(t1), mkexpr(t0))
8692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
8693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Break a 64-bit value up into four 16-bit ints. */
8696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void breakup64to16s ( IRTemp t64,
8698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             /*OUTs*/
8699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* t3, IRTemp* t2,
8700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp* t1, IRTemp* t0 )
8701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp hi32 = newTemp(Ity_I32);
8703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp lo32 = newTemp(Ity_I32);
8704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
8705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( lo32, unop(Iop_64to32,   mkexpr(t64)) );
8706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t0 && *t0 == IRTemp_INVALID);
8708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t1 && *t1 == IRTemp_INVALID);
8709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t2 && *t2 == IRTemp_INVALID);
8710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(t3 && *t3 == IRTemp_INVALID);
8711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t0 = newTemp(Ity_I16);
8713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t1 = newTemp(Ity_I16);
8714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t2 = newTemp(Ity_I16);
8715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *t3 = newTemp(Ity_I16);
8716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t0, unop(Iop_32to16,   mkexpr(lo32)) );
8717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
8718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t2, unop(Iop_32to16,   mkexpr(hi32)) );
8719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
8720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Construct a 64-bit value from four 16-bit ints. */
8723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
8725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             IRTemp t1, IRTemp t0 )
8726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop( Iop_32HLto64,
8729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
8730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
8731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
8732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PMULHRSW insns.  Given two 64-bit
8736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values (aa,bb), computes, for each of the 4 16-bit lanes:
8737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   (((aa_lane *s32 bb_lane) >>u 14) + 1) >>u 1
8739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PMULHRSW_helper ( IRExpr* aax, IRExpr* bbx )
8741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa      = newTemp(Ity_I64);
8743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bb      = newTemp(Ity_I64);
8744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aahi32s = newTemp(Ity_I64);
8745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aalo32s = newTemp(Ity_I64);
8746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bbhi32s = newTemp(Ity_I64);
8747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bblo32s = newTemp(Ity_I64);
8748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rHi     = newTemp(Ity_I64);
8749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp rLo     = newTemp(Ity_I64);
8750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp one32x2 = newTemp(Ity_I64);
8751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(aa, aax);
8752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(bb, bbx);
8753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aahi32s,
8754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
8755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveHI16x4, mkexpr(aa), mkexpr(aa)),
8756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
8757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aalo32s,
8758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
8759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveLO16x4, mkexpr(aa), mkexpr(aa)),
8760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
8761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bbhi32s,
8762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
8763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveHI16x4, mkexpr(bb), mkexpr(bb)),
8764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
8765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bblo32s,
8766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           binop(Iop_SarN32x2,
8767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_InterleaveLO16x4, mkexpr(bb), mkexpr(bb)),
8768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU8(16) ));
8769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(one32x2, mkU64( (1ULL << 32) + 1 ));
8770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
8771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rHi,
8772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
8773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_ShrN32x2,
8774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
8775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Add32x2,
8776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
8777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_ShrN32x2,
8778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul32x2, mkexpr(aahi32s), mkexpr(bbhi32s)),
8779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(14)
8780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
8781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(one32x2)
8782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
8783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU8(1)
8784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
8785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
8786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign(
8787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rLo,
8788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(
8789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Iop_ShrN32x2,
8790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
8791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Add32x2,
8792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
8793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_ShrN32x2,
8794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul32x2, mkexpr(aalo32s), mkexpr(bblo32s)),
8795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(14)
8796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
8797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mkexpr(one32x2)
8798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ),
8799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkU8(1)
8800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
8801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
8802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_CatEvenLanes16x4, mkexpr(rHi), mkexpr(rLo));
8804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PSIGN{B,W,D} insns.  Given two 64-bit
8807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   values (aa,bb), computes, for each lane:
8808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          if aa_lane < 0 then - bb_lane
8810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else if aa_lane > 0 then bb_lane
8811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     else 0
8812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PSIGN_helper ( IRExpr* aax, IRExpr* bbx, Int laneszB )
8814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa       = newTemp(Ity_I64);
8816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bb       = newTemp(Ity_I64);
8817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp zero     = newTemp(Ity_I64);
8818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp bbNeg    = newTemp(Ity_I64);
8819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp negMask  = newTemp(Ity_I64);
8820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp posMask  = newTemp(Ity_I64);
8821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSub    = Iop_INVALID;
8822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opCmpGTS = Iop_INVALID;
8823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (laneszB) {
8825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: opSub = Iop_Sub8x8;  opCmpGTS = Iop_CmpGT8Sx8;  break;
8826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: opSub = Iop_Sub16x4; opCmpGTS = Iop_CmpGT16Sx4; break;
8827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: opSub = Iop_Sub32x2; opCmpGTS = Iop_CmpGT32Sx2; break;
8828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
8829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aa,      aax );
8832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bb,      bbx );
8833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( zero,    mkU64(0) );
8834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( bbNeg,   binop(opSub,    mkexpr(zero), mkexpr(bb)) );
8835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( negMask, binop(opCmpGTS, mkexpr(zero), mkexpr(aa)) );
8836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( posMask, binop(opCmpGTS, mkexpr(aa),   mkexpr(zero)) );
8837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
8840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(bb),    mkexpr(posMask)),
8841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(bbNeg), mkexpr(negMask)) );
8842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for the SSSE3 (not SSE3) PABS{B,W,D} insns.  Given a 64-bit
8846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   value aa, computes, for each lane
8847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if aa < 0 then -aa else aa
8849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Note that the result is interpreted as unsigned, so that the
8851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   absolute value of the most negative signed input can be
8852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   represented.
8853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PABS_helper ( IRExpr* aax, Int laneszB )
8855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aa      = newTemp(Ity_I64);
8857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp zero    = newTemp(Ity_I64);
8858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp aaNeg   = newTemp(Ity_I64);
8859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp negMask = newTemp(Ity_I64);
8860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp posMask = newTemp(Ity_I64);
8861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSub   = Iop_INVALID;
8862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IROp   opSarN  = Iop_INVALID;
8863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (laneszB) {
8865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 1: opSub = Iop_Sub8x8;  opSarN = Iop_SarN8x8;  break;
8866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 2: opSub = Iop_Sub16x4; opSarN = Iop_SarN16x4; break;
8867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 4: opSub = Iop_Sub32x2; opSarN = Iop_SarN32x2; break;
8868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default: vassert(0);
8869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
8870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aa,      aax );
8872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( negMask, binop(opSarN, mkexpr(aa), mkU8(8*laneszB-1)) );
8873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( posMask, unop(Iop_Not64, mkexpr(negMask)) );
8874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( zero,    mkU64(0) );
8875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   assign( aaNeg,   binop(opSub, mkexpr(zero), mkexpr(aa)) );
8876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
8878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(aa),    mkexpr(posMask)),
8879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64, mkexpr(aaNeg), mkexpr(negMask)) );
8880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic IRExpr* dis_PALIGNR_XMM_helper ( IRTemp hi64,
8883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        IRTemp lo64, Long byteShift )
8884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(byteShift >= 1 && byteShift <= 7);
8886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return
8887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      binop(Iop_Or64,
8888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shl64, mkexpr(hi64), mkU8(8*(8-byteShift))),
8889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shr64, mkexpr(lo64), mkU8(8*byteShift))
8890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
8891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Generate a SIGSEGV followed by a restart of the current instruction
8894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if effective_addr is not 16-aligned.  This is required behaviour
8895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for some SSE3 instructions and all 128-bit SSSE3 instructions.
8896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   This assumes that guest_RIP_curr_instr is set correctly! */
8897f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov/* TODO(glider): we've replaced the 0xF mask with 0x0, effectively disabling
8898f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov * the check. Need to enable it once TSan stops generating unaligned
8899f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov * accesses in the wrappers.
8900f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov * See http://code.google.com/p/data-race-test/issues/detail?id=49 */
8901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void gen_SEGV_if_not_16_aligned ( IRTemp effective_addr )
8902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt(
8904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRStmt_Exit(
8905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_CmpNE64,
8906f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov               binop(Iop_And64,mkexpr(effective_addr),mkU64(0x0)),
8907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU64(0)),
8908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Ijk_SigSEGV,
8909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRConst_U64(guest_RIP_curr_instr)
8910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      )
8911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   );
8912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
8913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Helper for deciding whether a given insn (starting at the opcode
8916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   byte) may validly be used with a LOCK prefix.  The following insns
8917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   may be used with LOCK when their destination operand is in memory.
8918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AFAICS this is exactly the same for both 32-bit and 64-bit mode.
8919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ADD        80 /0,  81 /0,  82 /0,  83 /0,  00,  01
8921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OR         80 /1,  81 /1,  82 /x,  83 /1,  08,  09
8922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ADC        80 /2,  81 /2,  82 /2,  83 /2,  10,  11
8923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SBB        81 /3,  81 /3,  82 /x,  83 /3,  18,  19
8924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   AND        80 /4,  81 /4,  82 /x,  83 /4,  20,  21
8925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   SUB        80 /5,  81 /5,  82 /x,  83 /5,  28,  29
8926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XOR        80 /6,  81 /6,  82 /x,  83 /6,  30,  31
8927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DEC        FE /1,  FF /1
8929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   INC        FE /0,  FF /0
8930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NEG        F6 /3,  F7 /3
8932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   NOT        F6 /2,  F7 /2
8933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XCHG       86, 87
8935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTC        0F BB,  0F BA /7
8937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTR        0F B3,  0F BA /6
8938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   BTS        0F AB,  0F BA /5
8939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CMPXCHG    0F B0,  0F B1
8941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   CMPXCHG8B  0F C7 /1
8942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   XADD       0F C0,  0F C1
8944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   ------------------------------
8946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   80 /0  =  addb $imm8,  rm8
8948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   81 /0  =  addl $imm32, rm32  and  addw $imm16, rm16
8949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   82 /0  =  addb $imm8,  rm8
8950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   83 /0  =  addl $simm8, rm32  and  addw $simm8, rm16
8951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   00     =  addb r8,  rm8
8953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   01     =  addl r32, rm32  and  addw r16, rm16
8954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Same for ADD OR ADC SBB AND SUB XOR
8956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FE /1  = dec rm8
8958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FF /1  = dec rm32  and  dec rm16
8959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FE /0  = inc rm8
8961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   FF /0  = inc rm32  and  inc rm16
8962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F6 /3  = neg rm8
8964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F7 /3  = neg rm32  and  neg rm16
8965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F6 /2  = not rm8
8967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   F7 /2  = not rm32  and  not rm16
8968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   0F BB     = btcw r16, rm16    and  btcl r32, rm32
8970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   OF BA /7  = btcw $imm8, rm16  and  btcw $imm8, rm32
8971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Same for BTS, BTR
8973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
8974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic Bool can_be_used_with_LOCK_prefix ( UChar* opc )
8975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
8976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc[0]) {
8977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x00: case 0x01: case 0x08: case 0x09:
8978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x10: case 0x11: case 0x18: case 0x19:
8979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x20: case 0x21: case 0x28: case 0x29:
8980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x30: case 0x31:
8981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!epartIsReg(opc[1]))
8982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
8983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
8984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x80: case 0x81: case 0x82: case 0x83:
8986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 6
8987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
8988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
8989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
8990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: case 0xFF:
8992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(opc[1]) >= 0 && gregLO3ofRM(opc[1]) <= 1
8993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
8994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
8995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
8996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
8997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF6: case 0xF7:
8998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(opc[1]) >= 2 && gregLO3ofRM(opc[1]) <= 3
8999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && !epartIsReg(opc[1]))
9000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
9001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
9002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x86: case 0x87:
9004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!epartIsReg(opc[1]))
9005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            return True;
9006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
9007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0F: {
9009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (opc[1]) {
9010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xBB: case 0xB3: case 0xAB:
9011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
9012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
9013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
9014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xBA:
9015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (gregLO3ofRM(opc[2]) >= 5 && gregLO3ofRM(opc[2]) <= 7
9016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   && !epartIsReg(opc[2]))
9017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
9018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
9019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xB0: case 0xB1:
9020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
9021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
9022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
9023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC7:
9024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (gregLO3ofRM(opc[2]) == 1 && !epartIsReg(opc[2]) )
9025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
9026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
9027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0xC0: case 0xC1:
9028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               if (!epartIsReg(opc[2]))
9029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  return True;
9030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
9031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default:
9032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               break;
9033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } /* switch (opc[1]) */
9034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
9035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
9038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
9039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc[0]) */
9040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return False;
9042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
9043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
9046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Disassemble a single instruction                     ---*/
9047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
9048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction is
9050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   located in host memory at &guest_code[delta]. */
9051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic
9053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_AMD64_WRK (
9054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             /*OUT*/Bool* expect_CAS,
9055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         put_IP,
9056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
9057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Bool         resteerCisOk,
9058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             void*        callback_opaque,
9059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             Long         delta64,
9060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexArchInfo* archinfo,
9061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             VexAbiInfo*  vbi
9062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )
9063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
9064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRType    ty;
9065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
9066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       alen;
9067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar     opc, modrm, abyte, pre;
9068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long      d64;
9069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   HChar     dis_buf[50];
9070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       am_sz, d_sz, n, n_prefixes;
9071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
9072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   UChar*    insn; /* used in SSE decoders */
9073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* The running delta */
9075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long delta = delta64;
9076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Holds eip at the start of the insn, so that we can print
9078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      consistent error messages for unimplemented insns. */
9079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Long delta_start = delta;
9080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* sz denotes the nominal data-op size of the insn; we change it to
9082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2 if an 0x66 prefix is seen and 8 if REX.W is 1.  In case of
9083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      conflict REX.W takes precedence. */
9084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int sz = 4;
9085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* pfx holds the summary of prefixes. */
9087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Prefix pfx = PFX_EMPTY;
9088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set result defaults. */
9090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.whatNext   = Dis_Continue;
9091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len        = 0;
9092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.continueAt = 0;
9093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *expect_CAS = False;
9095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_RIP_next_assumed == 0);
9097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_RIP_next_mustcheck == False);
9098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID;
9100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\t0x%llx:  ", guest_RIP_bbstart+delta);
9102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We may be asked to update the guest RIP before going further. */
9104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (put_IP)
9105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
9106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Spot "Special" instructions (see comment at top of file). */
9108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   {
9109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar* code = (UChar*)(guest_code + delta);
9110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Spot the 16-byte preamble:
9111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         48C1C703   rolq $3,  %rdi
9112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         48C1C70D   rolq $13, %rdi
9113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         48C1C73D   rolq $61, %rdi
9114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         48C1C733   rolq $51, %rdi
9115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
9116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
9117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               && code[ 3] == 0x03 &&
9118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
9119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               && code[ 7] == 0x0D &&
9120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
9121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               && code[11] == 0x3D &&
9122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
9123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               && code[15] == 0x33) {
9124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Got a "Special" instruction preamble.  Which one is it? */
9125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[16] == 0x48 && code[17] == 0x87
9126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              && code[18] == 0xDB /* xchgq %rbx,%rbx */) {
9127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* %RDX = client_request ( %RAX ) */
9128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%%rdx = client_request ( %%rax )\n");
9129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 19;
9130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
9131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext = Dis_StopHere;
9132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
9133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
9134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
9135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[16] == 0x48 && code[17] == 0x87
9136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              && code[18] == 0xC9 /* xchgq %rcx,%rcx */) {
9137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* %RAX = guest_NRADDR */
9138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("%%rax = guest_NRADDR\n");
9139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 19;
9140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegRAX(8, IRExpr_Get( OFFB_NRADDR, Ity_I64 ));
9141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
9142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
9143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
9144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (code[16] == 0x48 && code[17] == 0x87
9145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              && code[18] == 0xD2 /* xchgq %rdx,%rdx */) {
9146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* call-noredir *%RAX */
9147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("call-noredir *%%rax\n");
9148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 19;
9149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t1 = newTemp(Ity_I64);
9150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t1, getIRegRAX(8));
9151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I64);
9152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
9153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg64(R_RSP, mkexpr(t2));
9154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta));
9155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jmp_treg(Ijk_NoRedir,t1);
9156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext = Dis_StopHere;
9157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_success;
9158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
9159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* We don't know what it is. */
9160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
9161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /*NOTREACHED*/
9162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Eat prefixes, summarising the result in pfx and sz, and rejecting
9166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      as many invalid combinations as possible. */
9167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n_prefixes = 0;
9168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   while (True) {
9169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (n_prefixes > 7) goto decode_failure;
9170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      pre = getUChar(delta);
9171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (pre) {
9172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x66: pfx |= PFX_66; break;
9173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x67: pfx |= PFX_ASO; break;
9174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF2: pfx |= PFX_F2; break;
9175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF3: pfx |= PFX_F3; break;
9176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF0: pfx |= PFX_LOCK; *expect_CAS = True; break;
9177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x2E: pfx |= PFX_CS; break;
9178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x3E: pfx |= PFX_DS; break;
9179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x26: pfx |= PFX_ES; break;
9180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x64: pfx |= PFX_FS; break;
9181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x65: pfx |= PFX_GS; break;
9182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x36: pfx |= PFX_SS; break;
9183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x40 ... 0x4F:
9184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            pfx |= PFX_REX;
9185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pre & (1<<3)) pfx |= PFX_REXW;
9186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pre & (1<<2)) pfx |= PFX_REXR;
9187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pre & (1<<1)) pfx |= PFX_REXX;
9188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            if (pre & (1<<0)) pfx |= PFX_REXB;
9189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
9190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
9191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto not_a_prefix;
9192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      n_prefixes++;
9194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
9195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   not_a_prefix:
9198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Dump invalid combinations */
9200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n = 0;
9201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_F2) n++;
9202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_F3) n++;
9203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n > 1)
9204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure; /* can't have both */
9205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   n = 0;
9207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_CS) n++;
9208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_DS) n++;
9209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_ES) n++;
9210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_FS) n++;
9211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_GS) n++;
9212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_SS) n++;
9213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (n > 1)
9214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure; /* multiple seg overrides == illegal */
9215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We have a %fs prefix.  Reject it if there's no evidence in 'vbi'
9217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      that we should accept it. */
9218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((pfx & PFX_FS) && !vbi->guest_amd64_assume_fs_is_zero)
9219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
9220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Ditto for %gs prefixes. */
9222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((pfx & PFX_GS) && !vbi->guest_amd64_assume_gs_is_0x60)
9223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
9224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set up sz. */
9226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   sz = 4;
9227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_66) sz = 2;
9228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ((pfx & PFX_REX) && (pfx & PFX_REXW)) sz = 8;
9229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Now we should be looking at the primary opcode byte or the
9231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      leading F2 or F3.  Check that any LOCK prefix is actually
9232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      allowed. */
9233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (pfx & PFX_LOCK) {
9235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (can_be_used_with_LOCK_prefix( (UChar*)&guest_code[delta] )) {
9236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lock ");
9237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = False;
9239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
9240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- The SSE/SSE2 decoder.                        --- */
9246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
9247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* What did I do to deserve SSE ?  Perhaps I was really bad in a
9249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      previous life? */
9250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note, this doesn't handle SSE3 right now.  All amd64s support
9252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SSE2 as a minimum so there is no point distinguishing SSE1 vs
9253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SSE2. */
9254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   insn = (UChar*)&guest_code[delta];
9256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* FXSAVE is spuriously at the start here only because it is
9258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      thusly placed in guest-x86/toIR.c. */
9259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /0 = FXSAVE m512 -- write x87 and SSE state to memory.
9261f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Note that the presence or absence of REX.W slightly affects the
9262f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      written format: whether the saved FPU IP and DP pointers are 64
9263f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      or 32 bits.  But the helper function we call simply writes zero
9264f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      bits in the relevant fields (which are 64 bits regardless of
9265f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      what REX.W is) and so it's good enough (iow, equally broken) in
9266f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      both cases. */
9267f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
9268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xAE
9269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregOfRexRM(pfx,insn[2]) == 0) {
9270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       IRDirty* d;
9271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
9273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
9276f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      gen_SEGV_if_not_16_aligned(addr);
9277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9278f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      DIP("%sfxsave %s\n", sz==8 ? "rex64/" : "", dis_buf);
9279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Uses dirty helper:
9281f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            void amd64g_do_FXSAVE ( VexGuestAMD64State*, ULong ) */
9282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N (
9283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
9284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "amd64g_dirtyhelper_FXSAVE",
9285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &amd64g_dirtyhelper_FXSAVE,
9286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_1( mkexpr(addr) )
9287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
9288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->needsBBP = True;
9289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're writing memory */
9291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mFx   = Ifx_Write;
9292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mAddr = mkexpr(addr);
9293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->mSize = 512;
9294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* declare we're reading guest state */
9296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->nFxState = 7;
9297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].fx     = Ifx_Read;
9299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].offset = OFFB_FTOP;
9300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].size   = sizeof(UInt);
9301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].fx     = Ifx_Read;
9303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].offset = OFFB_FPREGS;
9304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].size   = 8 * sizeof(ULong);
9305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].fx     = Ifx_Read;
9307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].offset = OFFB_FPTAGS;
9308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[2].size   = 8 * sizeof(UChar);
9309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].fx     = Ifx_Read;
9311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].offset = OFFB_FPROUND;
9312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[3].size   = sizeof(ULong);
9313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].fx     = Ifx_Read;
9315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].offset = OFFB_FC3210;
9316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[4].size   = sizeof(ULong);
9317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].fx     = Ifx_Read;
9319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].offset = OFFB_XMM0;
9320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[5].size   = 16 * sizeof(U128);
9321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].fx     = Ifx_Read;
9323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].offset = OFFB_SSEROUND;
9324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[6].size   = sizeof(ULong);
9325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Be paranoid ... this assertion tries to ensure the 16 %xmm
9327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 images are packed back-to-back.  If not, the value of
9328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 d->fxState[5].size is wrong. */
9329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(16 == sizeof(U128));
9330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(OFFB_XMM15 == (OFFB_XMM0 + 15 * 16));
9331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
9333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9337f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* 0F AE /1 = FXRSTOR m512 -- read x87 and SSE state from memory.
9338f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      As with FXSAVE above we ignore the value of REX.W since we're
9339f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      not bothering with the FPU DP and IP fields. */
9340f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
9341f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && insn[0] == 0x0F && insn[1] == 0xAE
9342f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && !epartIsReg(insn[2]) && gregOfRexRM(pfx,insn[2]) == 1) {
9343f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       IRDirty* d;
9344f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = getUChar(delta+2);
9345f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      vassert(!epartIsReg(modrm));
9346f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9347f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9348f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      delta += 2+alen;
9349f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      gen_SEGV_if_not_16_aligned(addr);
9350f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9351f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      DIP("%sfxrstor %s\n", sz==8 ? "rex64/" : "", dis_buf);
9352f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9353f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Uses dirty helper:
9354f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            VexEmWarn amd64g_do_FXRSTOR ( VexGuestAMD64State*, ULong )
9355f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         NOTE:
9356f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            the VexEmWarn value is simply ignored
9357f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      */
9358f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d = unsafeIRDirty_0_N (
9359f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             0/*regparms*/,
9360f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             "amd64g_dirtyhelper_FXRSTOR",
9361f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             &amd64g_dirtyhelper_FXRSTOR,
9362f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             mkIRExprVec_1( mkexpr(addr) )
9363f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root          );
9364f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->needsBBP = True;
9365f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9366f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* declare we're reading memory */
9367f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->mFx   = Ifx_Read;
9368f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->mAddr = mkexpr(addr);
9369f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->mSize = 512;
9370f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9371f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* declare we're writing guest state */
9372f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->nFxState = 7;
9373f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9374f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[0].fx     = Ifx_Write;
9375f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[0].offset = OFFB_FTOP;
9376f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[0].size   = sizeof(UInt);
9377f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9378f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[1].fx     = Ifx_Write;
9379f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[1].offset = OFFB_FPREGS;
9380f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[1].size   = 8 * sizeof(ULong);
9381f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9382f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[2].fx     = Ifx_Write;
9383f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[2].offset = OFFB_FPTAGS;
9384f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[2].size   = 8 * sizeof(UChar);
9385f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9386f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[3].fx     = Ifx_Write;
9387f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[3].offset = OFFB_FPROUND;
9388f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[3].size   = sizeof(ULong);
9389f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9390f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[4].fx     = Ifx_Write;
9391f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[4].offset = OFFB_FC3210;
9392f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[4].size   = sizeof(ULong);
9393f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9394f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[5].fx     = Ifx_Write;
9395f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[5].offset = OFFB_XMM0;
9396f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[5].size   = 16 * sizeof(U128);
9397f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9398f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[6].fx     = Ifx_Write;
9399f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[6].offset = OFFB_SSEROUND;
9400f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      d->fxState[6].size   = sizeof(ULong);
9401f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9402f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Be paranoid ... this assertion tries to ensure the 16 %xmm
9403f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	 images are packed back-to-back.  If not, the value of
9404f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root	 d->fxState[5].size is wrong. */
9405f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      vassert(16 == sizeof(U128));
9406f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      vassert(OFFB_XMM15 == (OFFB_XMM0 + 15 * 16));
9407f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9408f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      stmt( IRStmt_Dirty(d) );
9409f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9410f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
9411f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
9412f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
9413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ SSE decoder main ------ */
9414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
9416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x58) {
9418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "addps", Iop_Add32Fx4 );
9419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
9423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
9424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x58) {
9425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "addss", Iop_Add32F0x4 );
9426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 55 = ANDNPS -- G = (not G) and E */
9430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x55) {
9432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "andnps", Iop_AndV128 );
9433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 54 = ANDPS -- G = G and E */
9437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x54) {
9439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "andps", Iop_AndV128 );
9440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
9444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC2) {
9446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpps", True, 4 );
9447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
9451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
9452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC2) {
9453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpss", False, 4 );
9454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2F = COMISS  -- 32F0x4 comparison G,E, and set ZCP */
9458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
9459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
9461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_F32);
9462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_F32);
9463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getXMMRegLane32F( eregOfRexRM(pfx,modrm),
9466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         0/*lowest lane*/ ) );
9467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
9469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(eregOfRexRM(pfx,modrm)),
9470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( argR, loadLE(Ity_F32, mkexpr(addr)) );
9474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%scomiss %s,%s\n", insn[1]==0x2E ? "u" : "",
9476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 dis_buf,
9477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getXMMRegLane32F( gregOfRexRM(pfx,modrm),
9480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      0/*lowest lane*/ ) );
9481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
9483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
9484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
9485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
9486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And64,
9487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop( Iop_32Uto64,
9488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_CmpF64,
9489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop(Iop_F32toF64,mkexpr(argL)),
9490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  unop(Iop_F32toF64,mkexpr(argR)))),
9491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU64(0x45)
9492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )));
9493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
9498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half xmm */
9499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x2A) {
9501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
9502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
9508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2ps %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
9510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
9511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2ps %s,%s\n", dis_buf,
9516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
9517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
9522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 0,
9523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
9524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
9525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64,
9526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64to32, mkexpr(arg64)) )) );
9527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
9529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 1,
9530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_F64toF32,
9531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(rmode),
9532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop(Iop_I32StoF64,
9533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64HIto32, mkexpr(arg64)) )) );
9534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2A = CVTSI2SS
9539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      -- sz==4: convert I32 in mem/ireg to F32 in low quarter xmm
9540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      -- sz==8: convert I64 in mem/ireg to F32 in low quarter xmm */
9541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && (sz == 4 || sz == 8)
9542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x2A) {
9543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
9545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
9546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
9549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg32 = newTemp(Ity_I32);
9550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
9551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
9552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+1;
9553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2ss %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
9554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
9555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
9556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
9558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+alen;
9559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2ss %s,%s\n", dis_buf,
9560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)) );
9561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
9562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32F(
9563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRexRM(pfx,modrm), 0,
9564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_F64toF32,
9565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(rmode),
9566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_I32StoF64, mkexpr(arg32)) ) );
9567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* sz == 8 */
9569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg64 = newTemp(Ity_I64);
9570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
9571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
9572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+1;
9573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2ssq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
9574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRexRM(pfx,modrm)));
9575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
9576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
9578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+alen;
9579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2ssq %s,%s\n", dis_buf,
9580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRexRM(pfx,modrm)) );
9581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
9582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32F(
9583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRexRM(pfx,modrm), 0,
9584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_F64toF32,
9585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(rmode),
9586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_I64StoF64, mkexpr(rmode), mkexpr(arg64)) ) );
9587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2D = CVTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
9593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, according to prevailing SSE rounding mode */
9594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
9595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, rounding towards zero */
9596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64  = newTemp(Ity_I64);
9599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
9600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo  = newTemp(Ity_F32);
9601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32hi  = newTemp(Ity_F32);
9602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
9603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
9605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1));
9611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
9612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
9613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
9614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32hi, loadLE(Ity_F32, binop( Iop_Add64,
9618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(addr),
9619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU64(4) )));
9620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sps2pi %s,%s\n", r2zero ? "t" : "",
9622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
9624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
9627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
9628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
9630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
9633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dst64,
9634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_32HLto64,
9635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S,
9636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(rmode),
9637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_F32toF64, mkexpr(f32hi) ) ),
9638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S,
9639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(rmode),
9640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_F32toF64, mkexpr(f32lo) ) )
9641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
9642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
9645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2D = CVTSS2SI
9649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
9650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    according to prevailing SSE rounding mode
9651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
9652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    according to prevailing SSE rounding mode
9653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
9654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 2C = CVTTSS2SI
9655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==4 -- convert F32 in mem/low quarter xmm to I32 in ireg,
9656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    truncating towards zero
9657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==8 -- convert F32 in mem/low quarter xmm to I64 in ireg,
9658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    truncating towards zero
9659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
9660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx)
9661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F
9662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x2D || insn[1] == 0x2C)) {
9663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
9664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo  = newTemp(Ity_F32);
9665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
9666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4 || sz == 8);
9667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
9672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
9673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
9674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(sz, gregOfRexRM(pfx,modrm), False));
9675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
9678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%sss2si %s,%s\n", r2zero ? "t" : "",
9680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
9681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(sz, gregOfRexRM(pfx,modrm), False));
9682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
9685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
9686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
9688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
9691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32( gregOfRexRM(pfx,modrm),
9692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop( Iop_F64toI32S,
9693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(rmode),
9694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_F32toF64, mkexpr(f32lo))) );
9695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64( gregOfRexRM(pfx,modrm),
9697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop( Iop_F64toI64S,
9698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(rmode),
9699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_F32toF64, mkexpr(f32lo))) );
9700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
9706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5E) {
9708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "divps", Iop_Div32Fx4 );
9709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
9713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
9714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5E) {
9715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "divss", Iop_Div32F0x4 );
9716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /2 = LDMXCSR m32 -- load %mxcsr */
9720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
9721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && haveNo66noF2noF3(pfx)
9722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 2) {
9723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp t64 = newTemp(Ity_I64);
9725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp ew = newTemp(Ity_I32);
9726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
9728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
9730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ldmxcsr %s\n", dis_buf);
9731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The only thing we observe in %mxcsr is the rounding mode.
9733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Therefore, pass the 32-bit value (SSE native-format control
9734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         word) to a clean helper, getting back a 64-bit value, the
9735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lower half of which is the SSEROUND value to store, and the
9736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         upper half of which is the emulation-warning token which may
9737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         be generated.
9738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
9739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ULong amd64h_check_ldmxcsr ( ULong ); */
9740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t64, mkIRExprCCall(
9741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
9742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "amd64g_check_ldmxcsr",
9743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &amd64g_check_ldmxcsr,
9744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_1(
9745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         unop(Iop_32Uto64,
9746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              loadLE(Ity_I32, mkexpr(addr))
9747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         )
9748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
9749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   )
9750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
9751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_sse_roundingmode( unop(Iop_64to32, mkexpr(t64)) );
9753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) );
9754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put_emwarn( mkexpr(ew) );
9755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Finally, if an emulation warning was reported, side-exit to
9756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the next insn, reporting the warning, so that Valgrind's
9757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dispatcher sees the warning. */
9758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt(
9759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRStmt_Exit(
9760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
9761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Ijk_EmWarn,
9762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRConst_U64(guest_RIP_bbstart+delta)
9763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
9764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
9765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
9769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F7 = MASKMOVQ -- 8x8 masked store */
9770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF7) {
9772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool ok = False;
9773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMX( &ok, vbi, pfx, sz, delta+1 );
9774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!ok)
9775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
9776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
9780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5F) {
9782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "maxps", Iop_Max32Fx4 );
9783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
9787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
9788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5F) {
9789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "maxss", Iop_Max32F0x4 );
9790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
9794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
9795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5D) {
9796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "minps", Iop_Min32Fx4 );
9797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
9801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
9802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5D) {
9803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "minss", Iop_Min32F0x4 );
9804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 28 = MOVAPS -- move from E (mem or xmm) to G (xmm). */
9808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 10 = MOVUPS -- move from E (mem or xmm) to G (xmm). */
9809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
9810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x28 || insn[1] == 0x10)) {
9812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
9815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRexRM(pfx,modrm) ));
9816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov[ua]ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
9818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x28/*movaps*/)
9822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
9823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
9824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
9825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov[ua]ps %s,%s\n", dis_buf,
9826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
9827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 29 = MOVAPS -- move from G (xmm) to E (mem or xmm). */
9833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 11 = MOVUPS -- move from G (xmm) to E (mem or xmm). */
9834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
9835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x29 || insn[1] == 0x11)) {
9837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; awaiting test case */
9840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x29/*movaps*/)
9843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
9844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
9845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov[ua]ps %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
9846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf );
9847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
9849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 16 = MOVHPS -- move from mem to high half of XMM. */
9853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 16 = MOVLHPS -- move from lo half to hi half of XMM. */
9854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
9855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x16) {
9857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ) );
9862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
9864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
9868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
9869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhps %s,%s\n", dis_buf,
9870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg( gregOfRexRM(pfx,modrm) ));
9871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 17 = MOVHPS -- move from high half of XMM to mem. */
9876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
9877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x17) {
9879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
9880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
9881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
9882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
9883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
9884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   1/*upper lane*/ ) );
9886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhps %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf);
9888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
9889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
9891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 12 = MOVLPS -- move from mem to low half of XMM. */
9894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* OF 12 = MOVHLPS -- from from hi half to lo half of XMM. */
9895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
9896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x12) {
9898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm),
9902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0/*lower lane*/,
9903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ));
9904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhlps %s, %s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
9905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
9906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
9907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
9908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
9909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm),  0/*lower lane*/,
9910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
9911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlps %s, %s\n",
9912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
9913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
9915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 13 = MOVLPS -- move from low half of XMM to mem. */
9918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
9919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
9920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x13) {
9921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
9922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
9923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
9924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
9925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
9926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
9927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0/*lower lane*/ ) );
9928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlps %s, %s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
9929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                dis_buf);
9930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
9931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
9933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 50 = MOVMSKPS - move 4 sign bits from 4 x F32 in xmm(E)
9936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to 4 lowest bits of ireg(G) */
9937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
9938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x50) {
9939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* sz == 8 is a kludge to handle insns with REX.W redundantly
9940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         set to 1, which has been known to happen:
9941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         4c 0f 50 d9             rex64X movmskps %xmm1,%r11d
9943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         20071106: Intel docs say that REX.W isn't redundant: when
9945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         present, a 64-bit register is written; when not present, only
9946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the 32-bit half is written.  However, testing on a Core2
9947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         machine suggests the entire 64 bit register is written
9948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         irrespective of the status of REX.W.  That could be because
9949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         of the default rule that says "if the lower half of a 32-bit
9950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         register is written, the upper half is zeroed".  By using
9951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32 here we inadvertantly produce the same behaviour as
9952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the Core2, for the same reason -- putIReg32 implements said
9953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         rule.
9954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         AMD docs give no indication that REX.W is even valid for this
9956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         insn. */
9957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
9959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int src;
9960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I32);
9961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
9962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t2 = newTemp(Ity_I32);
9963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t3 = newTemp(Ity_I32);
9964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
9965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         src = eregOfRexRM(pfx,modrm);
9966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t0, binop( Iop_And32,
9967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
9968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(1) ));
9969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, binop( Iop_And32,
9970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
9971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(2) ));
9972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2, binop( Iop_And32,
9973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
9974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(4) ));
9975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t3, binop( Iop_And32,
9976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
9977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(8) ));
9978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32( gregOfRexRM(pfx,modrm),
9979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32,
9980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
9981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
9982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         )
9983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 );
9984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movmskps %s,%s\n", nameXMMReg(src),
9985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg32(gregOfRexRM(pfx,modrm)));
9986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
9987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
9988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
9989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
9990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2B = MOVNTPD -- for us, just a plain SSE store. */
9992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
9993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( ( (haveNo66noF2noF3(pfx) && sz == 4)
9994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || (have66noF2noF3(pfx) && sz == 2)
9995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
9996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x2B) {
9997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
9998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
9999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
10001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
10002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntp%s %s,%s\n", sz==2 ? "d" : "s",
10003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 dis_buf,
10004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E7 = MOVNTQ -- for us, just a plain MMX store.  Note, the
10013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Intel manual does not say anything about the usual business of
10014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the FP reg tags getting trashed whenever an MMX insn happens.
10015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      So we just leave them alone.
10016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
10017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE7) {
10019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
10021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* do_MMX_preamble(); Intel docs don't specify this */
10022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getMMXReg(gregLO3ofRM(modrm)) );
10024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntq %s,%s\n", dis_buf,
10025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregLO3ofRM(modrm)));
10026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 10 = MOVSS -- move 32 bits from E (mem or lo 1/4 xmm) to G
10033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (lo 1/4 xmm).  If E is mem, upper 3/4 of G is zeroed out. */
10034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx)
10035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
10036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x10) {
10037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
10040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane32( eregOfRexRM(pfx,modrm), 0 ));
10041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRexRM(pfx,modrm)));
10043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
10047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32( gregOfRexRM(pfx,modrm), 0,
10048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I32, mkexpr(addr)) );
10049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movss %s,%s\n", dis_buf,
10050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRexRM(pfx,modrm)));
10051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 11 = MOVSS -- move 32 bits from G (lo 1/4 xmm) to E (mem
10057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo 1/4 xmm). */
10058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
10059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x11) {
10060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, we don't yet have a test case */
10063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
10066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
10067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movss %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
10068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf);
10069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
10075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x59) {
10077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "mulps", Iop_Mul32Fx4 );
10078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
10082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
10083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x59) {
10084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "mulss", Iop_Mul32F0x4 );
10085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 56 = ORPS -- G = G and E */
10089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x56) {
10091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "orps", Iop_OrV128 );
10092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
10097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE0) {
10099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pavgb", False );
10102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
10107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE3) {
10109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pavgw", False );
10112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C5 = PEXTRW -- extract 16-bit field from mmx(E) and put
10117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zero-extend of it in ireg(G). */
10118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && (sz == 4 || sz == 8)
10119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC5) {
10120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp sV = newTemp(Ity_I64);
10123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_I16);
10124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(sV, getMMXReg(eregLO3ofRM(modrm)));
10126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         breakup64to16s( sV, &t3, &t2, &t1, &t0 );
10127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (insn[3] & 3) {
10128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:  assign(t5, mkexpr(t0)); break;
10129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:  assign(t5, mkexpr(t1)); break;
10130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:  assign(t5, mkexpr(t2)); break;
10131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:  assign(t5, mkexpr(t3)); break;
10132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
10133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
10134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 8)
10135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg64(gregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(t5)));
10136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
10137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t5)));
10138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pextrw $%d,%s,%s\n",
10139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Int)insn[3], nameMMXReg(eregLO3ofRM(modrm)),
10140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           sz==8 ? nameIReg64(gregOfRexRM(pfx,modrm))
10141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 : nameIReg32(gregOfRexRM(pfx,modrm))
10142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
10143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
10144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* note, for anyone filling in the mem case: this insn has one
10148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         byte after the amode and therefore you must pass 1 as the
10149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         last arg to disAMode */
10150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
10154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put it into the specified lane of mmx(G). */
10155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
10156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
10157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC4) {
10158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Use t0 .. t3 to hold the 4 original 16-bit lanes of the
10159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mmx reg.  t4 is the new lane value.  t5 is the original
10160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mmx value. t6 is the new mmx value. */
10161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int lane;
10162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I16);
10163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I64);
10164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t6 = newTemp(Ity_I64);
10165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t5, getMMXReg(gregLO3ofRM(modrm)));
10169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( t5, &t3, &t2, &t1, &t0 );
10170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
10173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
10174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+1-1];
10175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg16(eregOfRexRM(pfx,modrm)),
10177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
10178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 1 );
10180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+alen-1];
10182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
10183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
10184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
10186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (lane & 3) {
10189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  assign(t6, mk64from16s(t3,t2,t1,t4)); break;
10190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  assign(t6, mk64from16s(t3,t2,t4,t0)); break;
10191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  assign(t6, mk64from16s(t3,t4,t1,t0)); break;
10192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  assign(t6, mk64from16s(t4,t2,t1,t0)); break;
10193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
10194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregLO3ofRM(modrm), mkexpr(t6));
10196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F EE = PMAXSW -- 16x4 signed max */
10201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEE) {
10203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pmaxsw", False );
10206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F DE = PMAXUB -- 8x8 unsigned max */
10211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDE) {
10213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pmaxub", False );
10216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F EA = PMINSW -- 16x4 signed min */
10221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEA) {
10223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pminsw", False );
10226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F DA = PMINUB -- 8x8 unsigned min */
10231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDA) {
10233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pminub", False );
10236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F D7 = PMOVMSKB -- extract sign bits from each of 8 lanes in
10241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx(G), turn them into a byte, and put zero-extend of it in
10242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ireg(G). */
10243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD7) {
10245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I64);
10249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I64);
10250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t0, getMMXReg(eregLO3ofRM(modrm)));
10251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, mkIRExprCCall(
10252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Ity_I64, 0/*regparms*/,
10253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "amd64g_calculate_mmx_pmovmskb",
10254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &amd64g_calculate_mmx_pmovmskb,
10255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_1(mkexpr(t0))));
10256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t1)));
10257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmovmskb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg32(gregOfRexRM(pfx,modrm)));
10259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3;
10260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
10261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
10263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F E4 = PMULUH -- 16x4 hi-half of unsigned widening multiply */
10267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE4) {
10269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "pmuluh", False );
10272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /0 = PREFETCHNTA -- prefetch into caches, */
10276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /1 = PREFETCH0   -- with various different hints */
10277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /2 = PREFETCH1 */
10278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 18 /3 = PREFETCH2 */
10279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0x18
10280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && haveNo66noF2noF3(pfx)
10281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2])
10282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) >= 0 && gregLO3ofRM(insn[2]) <= 3) {
10283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* hintstr = "??";
10284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(!epartIsReg(modrm));
10287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
10290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (gregLO3ofRM(modrm)) {
10292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0: hintstr = "nta"; break;
10293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1: hintstr = "t0"; break;
10294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2: hintstr = "t1"; break;
10295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3: hintstr = "t2"; break;
10296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
10297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("prefetch%s %s\n", hintstr, dis_buf);
10300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F6 = PSADBW -- sum of 8Ux8 absolute differences */
10305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF6) {
10307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
10309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+2, insn[1], "psadbw", False );
10310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
10314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
10315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x70) {
10317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
10318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, s3, s2, s1, s0;
10319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
10320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_I64);
10321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_I64);
10322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
10326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
10327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
10328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufw $%d,%s,%s\n", order,
10329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(eregLO3ofRM(modrm)),
10330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
10331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
10333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           1/*extra byte after amode*/ );
10334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
10335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[2+alen];
10336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufw $%d,%s,%s\n", order,
10338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
10340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sV, &s3, &s2, &s1, &s0 );
10342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
10343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV,
10345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
10346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
10347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregLO3ofRM(modrm), mkexpr(dV));
10349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
10350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
10354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x53) {
10356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
10357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "rcpps", Iop_Recip32Fx4 );
10358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
10362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
10363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x53) {
10364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
10365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "rcpss", Iop_Recip32F0x4 );
10366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 52 = RSQRTPS -- approx reciprocal sqrt 32Fx4 from R/M to R */
10370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x52) {
10372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
10373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "rsqrtps", Iop_RSqrt32Fx4 );
10374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 52 = RSQRTSS -- approx reciprocal sqrt 32F0x4 from R/M to R */
10378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
10379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x52) {
10380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
10381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "rsqrtss", Iop_RSqrt32F0x4 );
10382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /7 = SFENCE -- flush pending operations to memory */
10386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
10387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xAE
10388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7
10389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4) {
10390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 3;
10391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Insert a memory fence.  It's sometimes important that these
10392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are carried through to the generated code. */
10393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_MBE(Imbe_Fence) );
10394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sfence\n");
10395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
10399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC6) {
10401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    select;
10402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
10403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
10405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
10406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[3];
10413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
10414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufps $%d,%s,%s\n", select,
10415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
10416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
10417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
10419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           1/*byte at end of insn*/ );
10420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[2+alen];
10422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
10423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufps $%d,%s,%s\n", select,
10424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
10426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELD(n) ((n)==0 ? d0 : ((n)==1 ? d1 : ((n)==2 ? d2 : d3)))
10432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELS(n) ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
10433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
10435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
10436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mk128from32s( SELS((select>>6)&3), SELS((select>>4)&3),
10437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       SELD((select>>2)&3), SELD((select>>0)&3) )
10438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELD
10441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELS
10442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
10447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x51) {
10449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
10450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "sqrtps", Iop_Sqrt32Fx4 );
10451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 51 = SQRTSS -- approx sqrt 32F0x4 from R/M to R */
10455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
10456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x51) {
10457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo32( vbi, pfx, delta+2,
10458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "sqrtss", Iop_Sqrt32F0x4 );
10459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /3 = STMXCSR m32 -- store %mxcsr */
10463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (insn[0] == 0x0F && insn[1] == 0xAE
10464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && haveNo66noF2noF3(pfx)
10465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 3) {
10466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
10468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
10470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fake up a native SSE mxcsr word.  The only thing it depends
10472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         on is SSEROUND[1:0], so call a clean helper to cook it up.
10473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
10474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ULong amd64h_create_mxcsr ( ULong sseround ) */
10475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("stmxcsr %s\n", dis_buf);
10476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(
10477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mkexpr(addr),
10478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_64to32,
10479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(
10480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 Ity_I64, 0/*regp*/,
10481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 "amd64g_create_mxcsr", &amd64g_create_mxcsr,
10482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkIRExprVec_1( unop(Iop_32Uto64,get_sse_roundingmode()) )
10483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      )
10484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 )
10485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
10490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5C) {
10492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "subps", Iop_Sub32Fx4 );
10493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
10497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
10498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5C) {
10499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo32( vbi, pfx, delta+2, "subss", Iop_Sub32F0x4 );
10500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
10504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
10505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These just appear to be special cases of SHUFPS */
10506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
10508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
10509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
10510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool hi = toBool(insn[1] == 0x15);
10511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
10512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
10513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
10514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
10515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
10516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRexRM(pfx,modrm)),
10522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
10523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
10526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
10528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf,
10529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
10530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
10533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
10534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hi) {
10536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s3, d3, s2, d2 ) );
10537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( s1, d1, s0, d0 ) );
10539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 57 = XORPS -- G = G and E */
10545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x57) {
10547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "xorps", Iop_XorV128 );
10548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
10552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE decoder.                      --- */
10553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
10554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
10556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE2 decoder.                   --- */
10557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
10558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 58 = ADDPD -- add 32Fx4 from R/M to R */
10560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
10561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
10562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x58) {
10563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "addpd", Iop_Add64Fx2 );
10564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 58 = ADDSD -- add 64F0x2 from R/M to R */
10568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx)
10569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
10570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x58) {
10571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "addsd", Iop_Add64F0x2 );
10572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 55 = ANDNPD -- G = (not G) and E */
10576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x55) {
10578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "andnpd", Iop_AndV128 );
10579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 54 = ANDPD -- G = G and E */
10583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x54) {
10585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "andpd", Iop_AndV128 );
10586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
10590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC2) {
10592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmppd", True, 8 );
10593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
10597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
10598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC2) {
10599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEcmp_E_to_G( vbi, pfx, delta+2, "cmpsd", False, 8 );
10600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2F = COMISD  -- 64F0x2 comparison G,E, and set ZCP */
10604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
10605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
10607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_F64);
10608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_F64);
10609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, getXMMRegLane64F( eregOfRexRM(pfx,modrm),
10612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         0/*lowest lane*/ ) );
10613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
10615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(eregOfRexRM(pfx,modrm)),
10616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
10620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("%scomisd %s,%s\n", insn[1]==0x2E ? "u" : "",
10622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 dis_buf,
10623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( argL, getXMMRegLane64F( gregOfRexRM(pfx,modrm),
10626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      0/*lowest lane*/ ) );
10627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
10629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
10630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
10631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
10632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And64,
10633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop( Iop_32Uto64,
10634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)) ),
10635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU64(0x45)
10636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )));
10637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
10642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      F64 in xmm(G) */
10643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) {
10644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
10645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4) goto decode_failure;
10646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) );
10650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2pd %s,%s\n", dis_buf,
10658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
10662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 0,
10663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
10664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
10667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 1,
10668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
10669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
10675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
10676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5B) {
10678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
10679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
10680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtdq2ps %s,%s\n", dis_buf,
10692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
10696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toF32,                    \
10699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
10700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_I32StoF64,mkexpr(_t)))
10701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
10708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), and zero upper half, rounding towards zero */
10714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
10715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), according to prevailing rounding mode, and zero
10716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      upper half */
10717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( ( (haveF2no66noF3(pfx) && sz == 4)
10718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || (have66noF2noF3(pfx) && sz == 2)
10719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
10720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0xE6) {
10721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV   = newTemp(Ity_V128);
10722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
10723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(sz == 2);
10724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
10731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
10732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spd2dq %s,%s\n", r2zero ? "t" : "",
10737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)) );
10739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
10742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
10743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
10745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
10748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
10749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
10750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
10751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
10752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
10753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toI32S,                   \
10755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
10756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
10757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
10764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, according to prevailing SSE rounding mode */
10770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
10771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      I32 in mmx, rounding towards zero */
10772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
10774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst64  = newTemp(Ity_I64);
10775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
10776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo  = newTemp(Ity_F64);
10777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64hi  = newTemp(Ity_F64);
10778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
10779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
10781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
10786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64hi, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 1));
10787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
10788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
10789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
10790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
10793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64hi, loadLE(Ity_F64, binop( Iop_Add64,
10794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkexpr(addr),
10795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                              mkU64(8) )));
10796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
10798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
10799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
10800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
10803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(rmode, mkU32((UInt)Irrm_ZERO) );
10804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
10806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
10809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dst64,
10810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_32HLto64,
10811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
10812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
10813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
10814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(gregLO3ofRM(modrm), mkexpr(dst64));
10817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
10821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo half xmm(G), rounding according to prevailing SSE rounding
10822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mode, and zero upper half */
10823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Note, this is practically identical to CVTPD2DQ.  It would have
10824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been nicer to merge them together, but the insn[] offsets differ
10825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      by one. */
10826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5A) {
10828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV  = newTemp(Ity_V128);
10829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
10830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpd2ps %s,%s\n", dis_buf,
10842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
10846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_F64);
10847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_F64);
10848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_ReinterpI64asF64,
10849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128to64, mkexpr(argV))) );
10850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_ReinterpI64asF64,
10851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop(Iop_V128HIto64, mkexpr(argV))) );
10852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)  binop( Iop_F64toF32,                    \
10854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(rmode),                   \
10855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(_t) )
10856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32(  gregOfRexRM(pfx,modrm), 3, mkU32(0) );
10858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32(  gregOfRexRM(pfx,modrm), 2, mkU32(0) );
10859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
10863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
10868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G) */
10869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
10870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x2A) {
10871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp arg64 = newTemp(Ity_I64);
10872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Only switch to MMX mode if the source is a MMX register.
10876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            This is inconsistent with all other instructions which
10877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            convert between XMM and (M64 or MMX), which always switch
10878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to MMX mode even if 64-bit operand is M64 and not MMX.  At
10879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            least, that's what the Intel docs seem to me to say.
10880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Fixes #210264. */
10881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
10882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, getMMXReg(eregLO3ofRM(modrm)) );
10883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
10885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
10889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtpi2pd %s,%s\n", dis_buf,
10891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
10895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 0,
10896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
10897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F(
10900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 1,
10901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
10902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
10903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G), rounding towards zero */
10909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
10910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(G), as per the prevailing rounding mode */
10911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( ( (have66noF2noF3(pfx) && sz == 2)
10912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          || (haveF3no66noF2(pfx) && sz == 4)
10913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        )
10914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x5B) {
10915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argV   = newTemp(Ity_V128);
10916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
10917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(sz == 4);
10918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) );
10922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
10928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2dq %s,%s\n", dis_buf,
10930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
10934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
10935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
10937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
10940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is less than ideal.  If it turns out to be a performance
10942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         bottleneck it can be improved. */
10943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define CVT(_t)                             \
10944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_F64toI32S,                   \
10945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(rmode),                   \
10946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                unop( Iop_F32toF64,              \
10947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
10948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
10950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
10951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) );
10952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) );
10953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef CVT
10955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
10960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      F64 in xmm(G). */
10961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
10962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5A) {
10963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
10964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32hi = newTemp(Ity_F32);
10965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
10967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
10968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0) );
10969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( f32hi, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 1) );
10970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
10971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
10972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
10973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
10974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
10975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
10976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign( f32hi, loadLE(Ity_F32,
10977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop(Iop_Add64,mkexpr(addr),mkU64(4))) );
10978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
10979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtps2pd %s,%s\n", dis_buf,
10980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)) );
10981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
10982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRexRM(pfx,modrm), 1,
10984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_F32toF64, mkexpr(f32hi)) );
10985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
10986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_F32toF64, mkexpr(f32lo)) );
10987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
10989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
10990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2D = CVTSD2SI
10992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    according to prevailing SSE rounding mode
10994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
10995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    according to prevailing SSE rounding mode
10996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
10997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2C = CVTTSD2SI
10998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==4 -- convert F64 in mem/low half xmm to I32 in ireg,
10999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    truncating towards zero
11000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==8 -- convert F64 in mem/low half xmm to I64 in ireg,
11001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    truncating towards zero
11002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
11003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx)
11004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F
11005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x2D || insn[1] == 0x2C)) {
11006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode  = newTemp(Ity_I32);
11007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo  = newTemp(Ity_F64);
11008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   r2zero = toBool(insn[1] == 0x2C);
11009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4 || sz == 8);
11010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
11015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
11016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
11017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(sz, gregOfRexRM(pfx,modrm), False));
11018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
11021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
11023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
11024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg(sz, gregOfRexRM(pfx,modrm), False));
11025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (r2zero) {
11028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, mkU32((UInt)Irrm_ZERO) );
11029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rmode, get_sse_roundingmode() );
11031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
11034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32( gregOfRexRM(pfx,modrm),
11035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
11036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64( gregOfRexRM(pfx,modrm),
11038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop( Iop_F64toI64S, mkexpr(rmode), mkexpr(f64lo)) );
11039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
11045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      low 1/4 xmm(G), according to prevailing SSE rounding mode */
11046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
11047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5A) {
11048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rmode = newTemp(Ity_I32);
11049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f64lo = newTemp(Ity_F64);
11050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
11051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64lo, getXMMRegLane64F(eregOfRexRM(pfx,modrm), 0));
11056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
11058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
11061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtsd2ss %s,%s\n", dis_buf,
11063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
11064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rmode, get_sse_roundingmode() );
11067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane32F(
11068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm), 0,
11069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
11070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 2A = CVTSI2SD
11076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==4 -- convert I32 in mem/ireg to F64 in low half xmm
11077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      when sz==8 -- convert I64 in mem/ireg to F64 in low half xmm
11078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
11079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && (sz == 4 || sz == 8)
11080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x2A) {
11081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
11084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg32 = newTemp(Ity_I32);
11085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
11086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg32, getIReg32(eregOfRexRM(pfx,modrm)) );
11087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+1;
11088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2sd %s,%s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
11089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
11090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
11093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+alen;
11094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2sd %s,%s\n", dis_buf,
11095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)) );
11096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
11098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           unop(Iop_I32StoF64, mkexpr(arg32))
11099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
11100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* sz == 8 */
11102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp arg64 = newTemp(Ity_I64);
11103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
11104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg64, getIReg64(eregOfRexRM(pfx,modrm)) );
11105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+1;
11106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2sdq %s,%s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
11107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRexRM(pfx,modrm)));
11108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
11111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += 2+alen;
11112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cvtsi2sdq %s,%s\n", dis_buf,
11113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRexRM(pfx,modrm)) );
11114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64F(
11116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRexRM(pfx,modrm),
11117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            0,
11118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop( Iop_I64StoF64,
11119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   get_sse_roundingmode(),
11120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   mkexpr(arg64)
11121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            )
11122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
11123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
11130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      low half xmm(G) */
11131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
11132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5A) {
11133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp f32lo = newTemp(Ity_F32);
11134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32lo, getXMMRegLane32F(eregOfRexRM(pfx,modrm), 0));
11139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
11141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
11144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cvtss2sd %s,%s\n", dis_buf,
11146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
11147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
11150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_F32toF64, mkexpr(f32lo) ) );
11151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
11156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5E) {
11158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "divpd", Iop_Div64Fx2 );
11159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5E = DIVSD -- div 64F0x2 from R/M to R */
11163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x5E) {
11164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
11165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "divsd", Iop_Div64F0x2 );
11166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /5 = LFENCE -- flush pending operations to memory */
11170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /6 = MFENCE -- flush pending operations to memory */
11171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
11172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xAE
11173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
11174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (gregLO3ofRM(insn[2]) == 5 || gregLO3ofRM(insn[2]) == 6)) {
11175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 3;
11176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Insert a memory fence.  It's sometimes important that these
11177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         are carried through to the generated code. */
11178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_MBE(Imbe_Fence) );
11179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("%sfence\n", gregLO3ofRM(insn[2])==5 ? "l" : "m");
11180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5F = MAXPD -- max 64Fx2 from R/M to R */
11184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5F) {
11186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "maxpd", Iop_Max64Fx2 );
11187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5F = MAXSD -- max 64F0x2 from R/M to R */
11191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
11192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5F) {
11193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "maxsd", Iop_Max64F0x2 );
11194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5D = MINPD -- min 64Fx2 from R/M to R */
11198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5D) {
11200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "minpd", Iop_Min64Fx2 );
11201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5D = MINSD -- min 64F0x2 from R/M to R */
11205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
11206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5D) {
11207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "minsd", Iop_Min64F0x2 );
11208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 28 = MOVAPD -- move from E (mem or xmm) to G (xmm). */
11212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 10 = MOVUPD -- move from E (mem or xmm) to G (xmm). */
11213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6F = MOVDQA -- move from E (mem or xmm) to G (xmm). */
11214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
11215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
11216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F
11217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x28 || insn[1] == 0x10 || insn[1] == 0x6F)) {
11218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wot = insn[1]==0x28 ? "apd" :
11219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   insn[1]==0x10 ? "upd" : "dqa";
11220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRexRM(pfx,modrm) ));
11224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(eregOfRexRM(pfx,modrm)),
11225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
11226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x28/*movapd*/ || insn[1] == 0x6F/*movdqa*/)
11230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
11231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
11233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, dis_buf,
11234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
11235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 29 = MOVAPD -- move from G (xmm) to E (mem or xmm). */
11241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 11 = MOVUPD -- move from G (xmm) to E (mem or xmm). */
11242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F
11243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[1] == 0x29 || insn[1] == 0x11)) {
11244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* wot = insn[1]==0x29 ? "apd" : "upd";
11245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRexRM(pfx,modrm),
11248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    getXMMReg( gregOfRexRM(pfx,modrm) ) );
11249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRexRM(pfx,modrm)),
11250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	                           nameXMMReg(eregOfRexRM(pfx,modrm)));
11251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x29/*movapd*/)
11255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
11256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%s %s,%s\n", wot, nameXMMReg(gregOfRexRM(pfx,modrm)),
11258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf );
11259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */
11265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*              or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */
11266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) {
11267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 8);
11268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2) sz = 4;
11269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 4) {
11273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putXMMReg(
11274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               gregOfRexRM(pfx,modrm),
11275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) )
11276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
11277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)),
11278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
11279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
11280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putXMMReg(
11281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               gregOfRexRM(pfx,modrm),
11282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) )
11283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
11284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)),
11285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
11286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 }
11287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(
11291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gregOfRexRM(pfx,modrm),
11292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz == 4
11293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ?  unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) )
11294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       :  unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) )
11295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         );
11296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf,
11297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
11298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */
11303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*              or from xmm low 1/2 to ireg64 or m64. */
11304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) {
11305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2) sz = 4;
11306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4 || sz == 8);
11307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 4) {
11311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg32( eregOfRexRM(pfx,modrm),
11312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) );
11313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg32(eregOfRexRM(pfx,modrm)));
11315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 } else {
11316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIReg64( eregOfRexRM(pfx,modrm),
11317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
11318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg64(eregOfRexRM(pfx,modrm)));
11320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 }
11321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
11325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  sz == 4
11326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0)
11327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) );
11328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q',
11329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */
11335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x7F) {
11337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRexRM(pfx,modrm),
11341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg(gregOfRexRM(pfx,modrm)) );
11342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(eregOfRexRM(pfx,modrm)));
11344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
11347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */
11355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
11356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x6F) {
11357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg( eregOfRexRM(pfx,modrm) ));
11361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
11363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
11368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s,%s\n", dis_buf,
11369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
11370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 7F = MOVDQU -- move from G (xmm) to E (mem or xmm). */
11376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
11377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x7F) {
11378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* awaiting test case */
11381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( eregOfRexRM(pfx,modrm),
11383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMReg(gregOfRexRM(pfx,modrm)) );
11384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(eregOfRexRM(pfx,modrm)));
11386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdqu %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf);
11391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F D6 = MOVDQ2Q -- move from E (lo half xmm, not mem) to G (mmx). */
11396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
11397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD6) {
11398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
11401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putMMXReg( gregLO3ofRM(modrm),
11402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
11403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movdq2q %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregLO3ofRM(modrm)));
11405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* apparently no mem case for this insn */
11409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
11410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 16 = MOVHPD -- move from mem to high half of XMM. */
11414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These seems identical to MOVHPS.  This instruction encoding is
11415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      completely crazy. */
11416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x16) {
11417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; apparently reg-reg is not possible */
11420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm), 1/*upper lane*/,
11424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
11425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhpd %s,%s\n", dis_buf,
11426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg( gregOfRexRM(pfx,modrm) ));
11427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 17 = MOVHPD -- move from high half of XMM to mem. */
11432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Again, this seems identical to MOVHPS. */
11433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x17) {
11434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(insn[2])) {
11435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2;
11436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
11437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
11438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
11439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRexRM(pfx,insn[2]),
11440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   1/*upper lane*/ ) );
11441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movhpd %s,%s\n", nameXMMReg( gregOfRexRM(pfx,insn[2]) ),
11442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               dis_buf);
11443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 12 = MOVLPD -- move from mem to low half of XMM. */
11449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Identical to MOVLPS ? */
11450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x12) {
11451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through; apparently reg-reg is not possible */
11454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm),
11458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0/*lower lane*/,
11459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
11460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlpd %s, %s\n",
11461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             dis_buf, nameXMMReg( gregOfRexRM(pfx,modrm) ));
11462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 13 = MOVLPD -- move from low half of XMM to mem. */
11467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Identical to MOVLPS ? */
11468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x13) {
11469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
11471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
11474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRexRM(pfx,modrm),
11475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   0/*lower lane*/ ) );
11476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movlpd %s, %s\n", nameXMMReg( gregOfRexRM(pfx,modrm) ),
11477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                dis_buf);
11478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 50 = MOVMSKPD - move 2 sign bits from 2 x F64 in xmm(E) to
11484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      2 lowest bits of ireg(G) */
11485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && (sz == 2 || sz == 8)
11486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x50) {
11487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* sz == 8 is a kludge to handle insns with REX.W redundantly
11488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         set to 1, which has been known to happen:
11489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         66 4c 0f 50 d9          rex64X movmskpd %xmm1,%r11d
11490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         20071106: see further comments on MOVMSKPS implementation above.
11491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
11492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Int src;
11495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I32);
11496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I32);
11497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         src = eregOfRexRM(pfx,modrm);
11499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t0, binop( Iop_And32,
11500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(31)),
11501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(1) ));
11502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, binop( Iop_And32,
11503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(30)),
11504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU32(2) ));
11505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32( gregOfRexRM(pfx,modrm),
11506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or32, mkexpr(t0), mkexpr(t1))
11507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  );
11508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movmskpd %s,%s\n", nameXMMReg(src),
11509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg32(gregOfRexRM(pfx,modrm)));
11510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
11514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F7 = MASKMOVDQU -- store selected bytes of double quadword */
11517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF7) {
11519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp regD    = newTemp(Ity_V128);
11522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp mask    = newTemp(Ity_V128);
11523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp olddata = newTemp(Ity_V128);
11524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp newdata = newTemp(Ity_V128);
11525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                addr    = newTemp(Ity_I64);
11526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( addr, handleAddrOverrides( vbi, pfx, getIReg64(R_RDI) ));
11528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( regD, getXMMReg( gregOfRexRM(pfx,modrm) ));
11529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Unfortunately can't do the obvious thing with SarN8x16
11531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            here since that can't be re-emitted as SSE2 code - no such
11532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            insn. */
11533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 assign(
11534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            mask,
11535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_64HLtoV128,
11536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SarN8x8,
11537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getXMMRegLane64( eregOfRexRM(pfx,modrm), 1 ),
11538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(7) ),
11539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_SarN8x8,
11540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ),
11541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(7) ) ));
11542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( olddata, loadLE( Ity_V128, mkexpr(addr) ));
11543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( newdata,
11544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_OrV128,
11545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_AndV128,
11546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(regD),
11547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(mask) ),
11548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_AndV128,
11549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkexpr(olddata),
11550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_NotV128, mkexpr(mask)))) );
11551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(newdata) );
11552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("maskmovdqu %s,%s\n", nameXMMReg( eregOfRexRM(pfx,modrm) ),
11555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg( gregOfRexRM(pfx,modrm) ) );
11556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E7 = MOVNTDQ -- for us, just a plain SSE store. */
11562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE7) {
11564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
11566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
11568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) );
11569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movntdq %s,%s\n", dis_buf,
11570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
11571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
11576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F C3 = MOVNTI -- for us, just a plain ireg store. */
11579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) &&
11580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       insn[0] == 0x0F && insn[1] == 0xC3) {
11581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4 || sz == 8);
11582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!epartIsReg(modrm)) {
11584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), getIRegG(sz, pfx, modrm) );
11586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movnti %s,%s\n", dis_buf,
11587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameIRegG(sz, pfx, modrm));
11588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
11592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D6 = MOVQ -- move 64 bits from G (lo half xmm) to E (mem
11595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo half xmm).  */
11596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
11597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
11598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD6) {
11599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* fall through, awaiting test case */
11602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* dst: lo half copied, hi half zeroed */
11603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
11606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
11607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movq %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf );
11608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F D6 = MOVQ2DQ -- move from E (mmx) to G (lo half xmm, zero
11614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi half). */
11615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
11616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD6) {
11617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_MMX_preamble();
11620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    unop(Iop_64UtoV128, getMMXReg( eregLO3ofRM(modrm) )) );
11622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movq2dq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
11623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
11624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
11626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* apparently no mem case for this insn */
11628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
11629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 7E = MOVQ -- move 64 bits from E (mem or lo half xmm) to
11633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G (lo half xmm).  Upper half of G is zeroed out. */
11634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 10 = MOVSD -- move 64 bits from E (mem or lo half xmm) to
11635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G (lo half xmm).  If E is mem, upper half of G is zeroed out.
11636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      If E is reg, upper half of G is unchanged. */
11637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( (haveF2no66noF3(pfx)
11638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         && insn[0] == 0x0F && insn[1] == 0x10)
11640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        ||
11641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        (haveF3no66noF2(pfx)
11642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         && insn[0] == 0x0F && insn[1] == 0x7E)
11644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ) {
11645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
11648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( eregOfRexRM(pfx,modrm), 0 ));
11649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (insn[1] == 0x7E/*MOVQ*/) {
11650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* zero bits 127:64 */
11651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkU64(0) );
11652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
11653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
11654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRexRM(pfx,modrm)));
11655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm), mkV128(0) );
11659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( gregOfRexRM(pfx,modrm), 0,
11660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          loadLE(Ity_I64, mkexpr(addr)) );
11661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", dis_buf,
11662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRexRM(pfx,modrm)));
11663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 11 = MOVSD -- move 64 bits from G (lo half xmm) to E (mem
11669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      or lo half xmm). */
11670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx)
11671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x11) {
11673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta+2);
11674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64( eregOfRexRM(pfx,modrm), 0,
11676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          getXMMRegLane64( gregOfRexRM(pfx,modrm), 0 ));
11677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(eregOfRexRM(pfx,modrm)));
11679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr),
11683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) );
11684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movsd %s,%s\n", nameXMMReg(gregOfRexRM(pfx,modrm)),
11685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              dis_buf);
11686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
11692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
11693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
11694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x59) {
11695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "mulpd", Iop_Mul64Fx2 );
11696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
11700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx)
11701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x59) {
11703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "mulsd", Iop_Mul64F0x2 );
11704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 56 = ORPD -- G = G and E */
11708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x56) {
11710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "orpd", Iop_OrV128 );
11711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
11715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC6) {
11717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    select;
11718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
11719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_V128);
11720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1 = newTemp(Ity_I64);
11721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0 = newTemp(Ity_I64);
11722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d1 = newTemp(Ity_I64);
11723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
11724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[3];
11731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+2;
11732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufpd $%d,%s,%s\n", select,
11733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
11734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
11735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 1 );
11737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         select = (Int)insn[2+alen];
11739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
11740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("shufpd $%d,%s,%s\n", select,
11741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
11742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
11743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
11747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
11749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELD(n) mkexpr((n)==0 ? d0 : d1)
11751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SELS(n) mkexpr((n)==0 ? s0 : s1)
11752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
11754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
11755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) )
11756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
11757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELD
11759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SELS
11760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
11765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x51) {
11767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_all( vbi, pfx, delta+2,
11768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        "sqrtpd", Iop_Sqrt64Fx2 );
11769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
11773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x51) {
11774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 4);
11775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_unary_lo64( vbi, pfx, delta+2,
11776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         "sqrtsd", Iop_Sqrt64F0x2 );
11777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
11781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5C) {
11783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "subpd", Iop_Sub64Fx2 );
11784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
11788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx)
11789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
11790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x5C) {
11791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_lo64( vbi, pfx, delta+2, "subsd", Iop_Sub64F0x2 );
11792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
11796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
11797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* These just appear to be special cases of SHUFPS */
11798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
11799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 2 /* could be 8 if rex also present */
11800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
11801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1 = newTemp(Ity_I64);
11802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0 = newTemp(Ity_I64);
11803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d1 = newTemp(Ity_I64);
11804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
11805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
11806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_V128);
11807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   hi = toBool(insn[1] == 0x15);
11808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
11810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
11811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
11813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
11814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
11815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRexRM(pfx,modrm)),
11817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
11818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
11820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
11821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
11822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
11823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  dis_buf,
11824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
11825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) );
11828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( d0, unop(Iop_V128to64,   mkexpr(dV)) );
11829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) );
11830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(sV)) );
11831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (hi) {
11833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_64HLtoV128, mkexpr(s1), mkexpr(d1)) );
11835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
11836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
11837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_64HLtoV128, mkexpr(s0), mkexpr(d0)) );
11838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
11839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 57 = XORPD -- G = G xor E */
11844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x57) {
11846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "xorpd", Iop_XorV128 );
11847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6B = PACKSSDW */
11851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x6B) {
11853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11854b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packssdw",
11855b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin32Sto16Sx8, True );
11856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 63 = PACKSSWB */
11860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x63) {
11862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11863b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packsswb",
11864b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin16Sto8Sx16, True );
11865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 67 = PACKUSWB */
11869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x67) {
11871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11872b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "packuswb",
11873b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 Iop_QNarrowBin16Sto8Ux16, True );
11874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FC = PADDB */
11878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xFC) {
11880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddb", Iop_Add8x16, False );
11882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FE = PADDD */
11886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xFE) {
11888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddd", Iop_Add32x4, False );
11890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
11894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F D4 = PADDQ -- add 64x1 */
11895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
11896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD4) {
11897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
11898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
11899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                vbi, pfx, delta+2, insn[1], "paddq", False );
11900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D4 = PADDQ */
11904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD4) {
11906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddq", Iop_Add64x2, False );
11908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FD = PADDW */
11912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xFD) {
11914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddw", Iop_Add16x8, False );
11916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EC = PADDSB */
11920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEC) {
11922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddsb", Iop_QAdd8Sx16, False );
11924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F ED = PADDSW */
11928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xED) {
11930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddsw", Iop_QAdd16Sx8, False );
11932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DC = PADDUSB */
11936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDC) {
11938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddusb", Iop_QAdd8Ux16, False );
11940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DD = PADDUSW */
11944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDD) {
11946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "paddusw", Iop_QAdd16Ux8, False );
11948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DB = PAND */
11952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDB) {
11954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "pand", Iop_AndV128 );
11955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DF = PANDN */
11959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDF) {
11961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all_invG( vbi, pfx, delta+2, "pandn", Iop_AndV128 );
11962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E0 = PAVGB */
11966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE0) {
11968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pavgb", Iop_Avg8Ux16, False );
11970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E3 = PAVGW */
11974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE3) {
11976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pavgw", Iop_Avg16Ux8, False );
11978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 74 = PCMPEQB */
11982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x74) {
11984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqb", Iop_CmpEQ8x16, False );
11986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 76 = PCMPEQD */
11990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x76) {
11992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
11993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqd", Iop_CmpEQ32x4, False );
11994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
11995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
11996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
11997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 75 = PCMPEQW */
11998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
11999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x75) {
12000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpeqw", Iop_CmpEQ16x8, False );
12002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 64 = PCMPGTB */
12006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x64) {
12008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtb", Iop_CmpGT8Sx16, False );
12010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 66 = PCMPGTD */
12014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x66) {
12016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtd", Iop_CmpGT32Sx4, False );
12018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 65 = PCMPGTW */
12022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x65) {
12024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtw", Iop_CmpGT16Sx8, False );
12026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C5 = PEXTRW -- extract 16-bit field from xmm(E) and put
12030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      zero-extend of it in ireg(G). */
12031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
12032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
12033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC5) {
12034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_V128);
12037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t4 = newTemp(Ity_I16);
12038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t5, getXMMReg(eregOfRexRM(pfx,modrm)));
12039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         breakup128to32s( t5, &t3, &t2, &t1, &t0 );
12040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (insn[3] & 7) {
12041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0:  assign(t4, unop(Iop_32to16,   mkexpr(t0))); break;
12042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1:  assign(t4, unop(Iop_32HIto16, mkexpr(t0))); break;
12043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 2:  assign(t4, unop(Iop_32to16,   mkexpr(t1))); break;
12044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 3:  assign(t4, unop(Iop_32HIto16, mkexpr(t1))); break;
12045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 4:  assign(t4, unop(Iop_32to16,   mkexpr(t2))); break;
12046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 5:  assign(t4, unop(Iop_32HIto16, mkexpr(t2))); break;
12047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 6:  assign(t4, unop(Iop_32to16,   mkexpr(t3))); break;
12048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 7:  assign(t4, unop(Iop_32HIto16, mkexpr(t3))); break;
12049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0);
12050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
12051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_16Uto32, mkexpr(t4)));
12052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pextrw $%d,%s,%s\n",
12053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (Int)insn[3], nameXMMReg(eregOfRexRM(pfx,modrm)),
12054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           nameIReg32(gregOfRexRM(pfx,modrm)));
12055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
12056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
12057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
12059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* note, if memory case is ever filled in, there is 1 byte after
12060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         amode */
12061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F C4 = PINSRW -- get 16 bits from E(mem or low half ireg) and
12064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      put it into the specified lane of xmm(G). */
12065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
12066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
12067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xC4) {
12068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int lane;
12069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I16);
12070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, getIReg16(eregOfRexRM(pfx,modrm)));
12074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+1-1];
12076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
12077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIReg16(eregOfRexRM(pfx,modrm)),
12078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
12079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
12081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           1/*byte after the amode*/ );
12082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
12083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         lane = insn[3+alen-1];
12084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t4, loadLE(Ity_I16, mkexpr(addr)));
12085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pinsrw $%d,%s,%s\n", (Int)lane,
12086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
12087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
12088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
12089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane16( gregOfRexRM(pfx,modrm), lane & 7, mkexpr(t4) );
12091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F5 = PMADDWD -- Multiply and add packed integers from
12095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      E(xmm or mem) to G(xmm) */
12096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF5) {
12098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1V  = newTemp(Ity_V128);
12099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2V  = newTemp(Ity_V128);
12100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV   = newTemp(Ity_V128);
12101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Hi = newTemp(Ity_I64);
12102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Lo = newTemp(Ity_I64);
12103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Hi = newTemp(Ity_I64);
12104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Lo = newTemp(Ity_I64);
12105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi  = newTemp(Ity_I64);
12106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo  = newTemp(Ity_I64);
12107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
12110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
12111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddwd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
12113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
12115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
12116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
12117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddwd %s,%s\n", dis_buf,
12118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
12119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
12121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
12122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
12123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
12124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
12125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, mkIRExprCCall(
12126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
12127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "amd64g_calculate_mmx_pmaddwd",
12128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &amd64g_calculate_mmx_pmaddwd,
12129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
12130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
12131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, mkIRExprCCall(
12132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
12133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "amd64g_calculate_mmx_pmaddwd",
12134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &amd64g_calculate_mmx_pmaddwd,
12135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
12136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
12137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
12138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EE = PMAXSW -- 16x8 signed max */
12143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEE) {
12145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmaxsw", Iop_Max16Sx8, False );
12147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DE = PMAXUB -- 8x16 unsigned max */
12151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDE) {
12153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmaxub", Iop_Max8Ux16, False );
12155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EA = PMINSW -- 16x8 signed min */
12159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEA) {
12161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pminsw", Iop_Min16Sx8, False );
12163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F DA = PMINUB -- 8x16 unsigned min */
12167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xDA) {
12169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pminub", Iop_Min8Ux16, False );
12171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D7 = PMOVMSKB -- extract sign bits from each of 16 lanes in
12175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm(E), turn them into a byte, and put zero-extend of it in
12176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ireg(G).  Doing this directly is just too cumbersome; give up
12177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      therefore and call a helper. */
12178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* UInt x86g_calculate_sse_pmovmskb ( ULong w64hi, ULong w64lo ); */
12179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
12180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
12181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD7) {
12182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t0 = newTemp(Ity_I64);
12185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I64);
12186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t0, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0));
12187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, getXMMRegLane64(eregOfRexRM(pfx,modrm), 1));
12188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t5 = newTemp(Ity_I64);
12189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t5, mkIRExprCCall(
12190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       Ity_I64, 0/*regparms*/,
12191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       "amd64g_calculate_sse_pmovmskb",
12192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &amd64g_calculate_sse_pmovmskb,
12193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkIRExprVec_2( mkexpr(t1), mkexpr(t0) )));
12194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32(gregOfRexRM(pfx,modrm), unop(Iop_64to32,mkexpr(t5)));
12195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmovmskb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIReg32(gregOfRexRM(pfx,modrm)));
12197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3;
12198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
12199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through */
12201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E4 = PMULHUW -- 16x8 hi-half of unsigned widening multiply */
12204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE4) {
12206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmulhuw", Iop_MulHi16Ux8, False );
12208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E5 = PMULHW -- 16x8 hi-half of signed widening multiply */
12212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE5) {
12214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmulhw", Iop_MulHi16Sx8, False );
12216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D5 = PMULHL -- 16x8 multiply */
12220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD5) {
12222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pmullw", Iop_Mul16x8, False );
12224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
12228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
12229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0 to form 64-bit result */
12230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
12231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF4) {
12232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_I64);
12233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_I64);
12234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I32);
12235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I32);
12236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
12240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
12243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
12244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
12245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregLO3ofRM(modrm)));
12246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
12248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
12249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
12250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", dis_buf,
12251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameMMXReg(gregLO3ofRM(modrm)));
12252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, unop(Iop_64to32, mkexpr(dV)) );
12255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_64to32, mkexpr(sV)) );
12256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg( gregLO3ofRM(modrm),
12257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_MullU32, mkexpr(t0), mkexpr(t1) ) );
12258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F4 = PMULUDQ -- unsigned widening multiply of 32-lanes 0 x
12262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
12263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      half */
12264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* This is a really poor translation -- could be improved if
12265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      performance critical */
12266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF4) {
12268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV;
12269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
12270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
12271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
12272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
12273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
12274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I64);
12275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
12277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
12281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
12283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
12285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
12287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmuludq %s,%s\n", dis_buf,
12288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
12289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
12292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, binop( Iop_MullU32, mkexpr(d0), mkexpr(s0)) );
12295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
12296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop( Iop_MullU32, mkexpr(d2), mkexpr(s2)) );
12297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
12298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EB = POR */
12302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEB) {
12304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "por", Iop_OrV128 );
12305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F6 = PSADBW -- 2 x (8x8 -> 48 zeroes ++ u16) Sum Abs Diffs
12309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      from E(xmm or mem) to G(xmm) */
12310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF6) {
12312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1V  = newTemp(Ity_V128);
12313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2V  = newTemp(Ity_V128);
12314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV   = newTemp(Ity_V128);
12315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Hi = newTemp(Ity_I64);
12316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s1Lo = newTemp(Ity_I64);
12317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Hi = newTemp(Ity_I64);
12318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s2Lo = newTemp(Ity_I64);
12319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi  = newTemp(Ity_I64);
12320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo  = newTemp(Ity_I64);
12321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, getXMMReg(eregOfRexRM(pfx,modrm)) );
12324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
12325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psadbw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
12327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
12329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( s1V, loadLE(Ity_V128, mkexpr(addr)) );
12330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
12331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psadbw %s,%s\n", dis_buf,
12332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
12333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2V, getXMMReg(gregOfRexRM(pfx,modrm)) );
12335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Hi, unop(Iop_V128HIto64, mkexpr(s1V)) );
12336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s1Lo, unop(Iop_V128to64,   mkexpr(s1V)) );
12337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Hi, unop(Iop_V128HIto64, mkexpr(s2V)) );
12338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s2Lo, unop(Iop_V128to64,   mkexpr(s2V)) );
12339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, mkIRExprCCall(
12340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
12341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "amd64g_calculate_mmx_psadbw",
12342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &amd64g_calculate_mmx_psadbw,
12343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Hi), mkexpr(s2Hi))
12344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
12345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, mkIRExprCCall(
12346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      Ity_I64, 0/*regparms*/,
12347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      "amd64g_calculate_mmx_psadbw",
12348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      &amd64g_calculate_mmx_psadbw,
12349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkIRExprVec_2( mkexpr(s1Lo), mkexpr(s2Lo))
12350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
12351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(dHi), mkexpr(dLo))) ;
12352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
12357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x70) {
12359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
12360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, s3, s2, s1, s0;
12361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
12362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV = newTemp(Ity_V128);
12363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV = newTemp(Ity_V128);
12364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
12368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufd $%d,%s,%s\n", order,
12370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(eregOfRexRM(pfx,modrm)),
12371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
12372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
12374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           1/*byte after the amode*/ );
12375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[2+alen];
12377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen+1;
12378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufd $%d,%s,%s\n", order,
12379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
12380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
12381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
12385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV,
12387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
12388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           SEL((order>>2)&3), SEL((order>>0)&3) )
12389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
12392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
12396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mem) to G(xmm), and copy lower half */
12397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
12398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x70) {
12399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
12400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
12401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
12402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV   = newTemp(Ity_V128);
12403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV   = newTemp(Ity_V128);
12404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sVhi = newTemp(Ity_I64);
12405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dVhi = newTemp(Ity_I64);
12406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
12410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufhw $%d,%s,%s\n", order,
12412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRexRM(pfx,modrm)),
12413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
12414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
12416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           1/*byte after the amode*/ );
12417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[2+alen];
12419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen+1;
12420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufhw $%d,%s,%s\n", order,
12421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
12422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
12423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVhi, unop(Iop_V128HIto64, mkexpr(sV)) );
12425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
12426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
12428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dVhi,
12430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
12431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
12432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV, binop( Iop_64HLtoV128,
12434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(dVhi),
12435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_V128to64, mkexpr(sV))) );
12436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
12438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
12442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mem) to G(xmm), and copy upper half */
12443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
12444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x70) {
12445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int order;
12446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
12447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
12448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV   = newTemp(Ity_V128);
12449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV   = newTemp(Ity_V128);
12450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sVlo = newTemp(Ity_I64);
12451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dVlo = newTemp(Ity_I64);
12452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
12455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         order = (Int)insn[3];
12456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
12457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshuflw $%d,%s,%s\n", order,
12458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRexRM(pfx,modrm)),
12459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
12460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf,
12462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           1/*byte after the amode*/ );
12463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 order = (Int)insn[2+alen];
12465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen+1;
12466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshuflw $%d,%s,%s\n", order,
12467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
12468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
12469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVlo, unop(Iop_V128to64, mkexpr(sV)) );
12471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
12472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     define SEL(n) \
12474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
12475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dVlo,
12476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
12477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          SEL((order>>2)&3), SEL((order>>0)&3) )
12478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
12479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(dV, binop( Iop_64HLtoV128,
12480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop(Iop_V128HIto64, mkexpr(sV)),
12481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(dVlo) ) );
12482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(gregOfRexRM(pfx,modrm), mkexpr(dV));
12483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#     undef SEL
12484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /6 ib = PSLLD by immediate */
12488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x72
12490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 6) {
12492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "pslld", Iop_ShlN32x4 );
12493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F2 = PSLLD by E */
12497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF2) {
12499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "pslld", Iop_ShlN32x4 );
12500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /7 ib = PSLLDQ by immediate */
12504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* note, if mem case ever filled in, 1 byte after amode */
12505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x73
12507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 7) {
12509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
12510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = (Int)insn[3];
12511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    reg = eregOfRexRM(pfx,insn[2]);
12512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pslldq $%d,%s\n", imm, nameXMMReg(reg));
12513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm >= 0 && imm <= 255);
12514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 4;
12515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV    = newTemp(Ity_V128);
12517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV    = newTemp(Ity_V128);
12518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64  = newTemp(Ity_I64);
12519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64  = newTemp(Ity_I64);
12520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64r = newTemp(Ity_I64);
12521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64r = newTemp(Ity_I64);
12522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm >= 16) {
12524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(reg, mkV128(0x0000));
12525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
12526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sV, getXMMReg(reg) );
12529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
12530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
12531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 0) {
12533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(lo64) );
12534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(hi64) );
12535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 8) {
12538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkU64(0) );
12539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(lo64) );
12540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm > 8) {
12543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkU64(0) );
12544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, binop( Iop_Shl64,
12545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(lo64),
12546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8( 8*(imm-8) ) ));
12547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, binop( Iop_Shl64,
12549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(lo64),
12550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8 * imm) ));
12551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r,
12552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Or64,
12553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, mkexpr(hi64),
12554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * imm)),
12555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shr64, mkexpr(lo64),
12556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * (8 - imm)) )
12557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
12558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
12559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
12561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(reg, mkexpr(dV));
12562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /6 ib = PSLLQ by immediate */
12566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x73
12568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 6) {
12570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllq", Iop_ShlN64x2 );
12571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F3 = PSLLQ by E */
12575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF3) {
12577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psllq", Iop_ShlN64x2 );
12578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /6 ib = PSLLW by immediate */
12582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x71
12584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 6) {
12586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psllw", Iop_ShlN16x8 );
12587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F1 = PSLLW by E */
12591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF1) {
12593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psllw", Iop_ShlN16x8 );
12594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /4 ib = PSRAD by immediate */
12598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x72
12600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 4) {
12602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrad", Iop_SarN32x4 );
12603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E2 = PSRAD by E */
12607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE2) {
12609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrad", Iop_SarN32x4 );
12610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /4 ib = PSRAW by immediate */
12614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x71
12616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 4) {
12618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psraw", Iop_SarN16x8 );
12619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E1 = PSRAW by E */
12623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE1) {
12625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psraw", Iop_SarN16x8 );
12626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 72 /2 ib = PSRLD by immediate */
12630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x72
12632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 2) {
12634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrld", Iop_ShrN32x4 );
12635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D2 = PSRLD by E */
12639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD2) {
12641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrld", Iop_ShrN32x4 );
12642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /3 ib = PSRLDQ by immediate */
12646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* note, if mem case ever filled in, 1 byte after amode */
12647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x73
12649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 3) {
12651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV, dV, hi64, lo64, hi64r, lo64r;
12652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = (Int)insn[3];
12653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    reg = eregOfRexRM(pfx,insn[2]);
12654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("psrldq $%d,%s\n", imm, nameXMMReg(reg));
12655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm >= 0 && imm <= 255);
12656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 4;
12657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sV    = newTemp(Ity_V128);
12659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dV    = newTemp(Ity_V128);
12660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64  = newTemp(Ity_I64);
12661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64  = newTemp(Ity_I64);
12662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      hi64r = newTemp(Ity_I64);
12663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      lo64r = newTemp(Ity_I64);
12664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm >= 16) {
12666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg(reg, mkV128(0x0000));
12667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_success;
12668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sV, getXMMReg(reg) );
12671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( hi64, unop(Iop_V128HIto64, mkexpr(sV)) );
12672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( lo64, unop(Iop_V128to64, mkexpr(sV)) );
12673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 0) {
12675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(lo64) );
12676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkexpr(hi64) );
12677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm == 8) {
12680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkU64(0) );
12681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, mkexpr(hi64) );
12682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
12684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm > 8) {
12685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, mkU64(0) );
12686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r, binop( Iop_Shr64,
12687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(hi64),
12688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8( 8*(imm-8) ) ));
12689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( hi64r, binop( Iop_Shr64,
12691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(hi64),
12692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8 * imm) ));
12693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( lo64r,
12694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Or64,
12695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shr64, mkexpr(lo64),
12696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * imm)),
12697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Shl64, mkexpr(hi64),
12698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU8(8 * (8 - imm)) )
12699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      )
12700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               );
12701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, binop(Iop_64HLtoV128, mkexpr(hi64r), mkexpr(lo64r)) );
12704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(reg, mkexpr(dV));
12705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 73 /2 ib = PSRLQ by immediate */
12709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x73
12711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 2) {
12713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlq", Iop_ShrN64x2 );
12714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D3 = PSRLQ by E */
12718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD3) {
12720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrlq", Iop_ShrN64x2 );
12721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 71 /2 ib = PSRLW by immediate */
12725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x71
12727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && epartIsReg(insn[2])
12728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && gregLO3ofRM(insn[2]) == 2) {
12729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftE_imm( pfx, delta+2, "psrlw", Iop_ShrN16x8 );
12730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D1 = PSRLW by E */
12734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD1) {
12736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_shiftG_byE( vbi, pfx, delta+2, "psrlw", Iop_ShrN16x8 );
12737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F8 = PSUBB */
12741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF8) {
12743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubb", Iop_Sub8x16, False );
12745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FA = PSUBD */
12749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xFA) {
12751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubd", Iop_Sub32x4, False );
12753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
12757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F FB = PSUBQ -- sub 64x1 */
12758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
12759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xFB) {
12760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
12761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_MMXop_regmem_to_reg (
12762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                vbi, pfx, delta+2, insn[1], "psubq", False );
12763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F FB = PSUBQ */
12767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xFB) {
12769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubq", Iop_Sub64x2, False );
12771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F F9 = PSUBW */
12775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF9) {
12777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubw", Iop_Sub16x8, False );
12779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E8 = PSUBSB */
12783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE8) {
12785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubsb", Iop_QSub8Sx16, False );
12787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F E9 = PSUBSW */
12791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xE9) {
12793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubsw", Iop_QSub16Sx8, False );
12795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D8 = PSUBSB */
12799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD8) {
12801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubusb", Iop_QSub8Ux16, False );
12803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D9 = PSUBSW */
12807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD9) {
12809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "psubusw", Iop_QSub16Ux8, False );
12811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 68 = PUNPCKHBW */
12815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x68) {
12817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhbw",
12819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI8x16, True );
12820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6A = PUNPCKHDQ */
12824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x6A) {
12826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhdq",
12828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI32x4, True );
12829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6D = PUNPCKHQDQ */
12833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x6D) {
12835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhqdq",
12837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI64x2, True );
12838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 69 = PUNPCKHWD */
12842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x69) {
12844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckhwd",
12846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveHI16x8, True );
12847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 60 = PUNPCKLBW */
12851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x60) {
12853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklbw",
12855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO8x16, True );
12856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 62 = PUNPCKLDQ */
12860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x62) {
12862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpckldq",
12864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO32x4, True );
12865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 6C = PUNPCKLQDQ */
12869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x6C) {
12871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklqdq",
12873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO64x2, True );
12874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 61 = PUNPCKLWD */
12878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x61) {
12880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+2,
12881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "punpcklwd",
12882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 Iop_InterleaveLO16x8, True );
12883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F EF = PXOR */
12887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
12888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xEF) {
12889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSE_E_to_G_all( vbi, pfx, delta+2, "pxor", Iop_XorV128 );
12890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
12894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    if (insn[0] == 0x0F && insn[1] == 0xAE
12895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--        && (!epartIsReg(insn[2]))
12896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--        && (gregOfRM(insn[2]) == 1 || gregOfRM(insn[2]) == 0) ) {
12897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       Bool store = gregOfRM(insn[2]) == 0;
12898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       vg_assert(sz == 4);
12899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       pair = disAMode ( cb, sorb, eip+2, dis_buf );
12900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       t1   = LOW24(pair);
12901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       eip += 2+HI8(pair);
12902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr3(cb, store ? SSE2a_MemWr : SSE2a_MemRd, 512,
12903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--                   Lit16, (((UShort)insn[0]) << 8) | (UShort)insn[1],
12904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--                   Lit16, (UShort)insn[2],
12905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--                   TempReg, t1 );
12906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       DIP("fx%s %s\n", store ? "save" : "rstor", dis_buf );
12907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       goto decode_success;
12908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    }
12909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F AE /7 = CLFLUSH -- flush cache line */
12911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
12912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xAE
12913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && !epartIsReg(insn[2]) && gregLO3ofRM(insn[2]) == 7) {
12914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is something of a hack.  We need to know the size of the
12916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         cache line containing addr.  Since we don't (easily), assume
12917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         256 on the basis that no real cache would have a line that
12918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         big.  It's safe to invalidate more stuff than we need, just
12919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         inefficient. */
12920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ULong lineszB = 256ULL;
12921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
12923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2+alen;
12924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Round addr down to the start of the containing block. */
12926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
12927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_TISTART,
12928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop( Iop_And64,
12929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkexpr(addr),
12930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU64( ~(lineszB-1) ))) );
12931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(OFFB_TILEN, mkU64(lineszB) ) );
12933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->jumpkind = Ijk_TInval;
12935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      irsb->next     = mkU64(guest_RIP_bbstart+delta);
12936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext  = Dis_StopHere;
12937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("clflush %s\n", dis_buf);
12939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE/SSE2 decoder.                 --- */
12944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE3 decoder.                   --- */
12948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
12949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 12 = MOVSLDUP -- move from E (mem or xmm) to G (xmm),
12951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (2:2:0:0). */
12952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F 16 = MOVSHDUP -- move from E (mem or xmm) to G (xmm),
12953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (3:3:1:1). */
12954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3no66noF2(pfx) && sz == 4
12955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x12 || insn[1] == 0x16)) {
12956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s3, s2, s1, s0;
12957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
12958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isH = insn[1] == 0x16;
12959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s3 = s2 = s1 = s0 = IRTemp_INVALID;
12960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(eregOfRexRM(pfx,modrm)),
12966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
12967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
12968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
12969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
12970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
12971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
12972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movs%cdup %s,%s\n", isH ? 'h' : 'l',
12973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     dis_buf,
12974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameXMMReg(gregOfRexRM(pfx,modrm)));
12975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
12976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
12977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
12979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm),
12980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isH ? mk128from32s( s3, s3, s1, s1 )
12981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : mk128from32s( s2, s2, s0, s0 ) );
12982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
12983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
12984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 12 = MOVDDUP -- move from E (mem or xmm) to G (xmm),
12986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      duplicating some lanes (0:1:0:1). */
12987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx)
12988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 4 || /* ignore redundant REX.W */ sz == 8)
12989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x12) {
12990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_V128);
12991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp d0 = newTemp(Ity_I64);
12992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
12994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
12995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
12996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movddup %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
12997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
12998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
12999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign ( d0, unop(Iop_V128to64, mkexpr(sV)) );
13000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
13002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( d0, loadLE(Ity_I64, mkexpr(addr)) );
13003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movddup %s,%s\n", dis_buf,
13004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameXMMReg(gregOfRexRM(pfx,modrm)));
13005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
13006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm),
13009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_64HLtoV128,mkexpr(d0),mkexpr(d0)) );
13010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F D0 = ADDSUBPS -- 32x4 +/-/+/- from E (mem or xmm) to G (xmm). */
13014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
13015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD0) {
13016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp a3, a2, a1, a0, s3, s2, s1, s0;
13017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV   = newTemp(Ity_V128);
13018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV   = newTemp(Ity_V128);
13019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addV = newTemp(Ity_V128);
13020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp subV = newTemp(Ity_V128);
13021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a3 = a2 = a1 = a0 = s3 = s2 = s1 = s0 = IRTemp_INVALID;
13022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
13024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubps %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
13028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
13029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
13031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
13032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubps %s,%s\n", dis_buf,
13033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
13034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
13035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addV, binop(Iop_Add32Fx4, mkexpr(gV), mkexpr(eV)) );
13040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( subV, binop(Iop_Sub32Fx4, mkexpr(gV), mkexpr(eV)) );
13041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( addV, &a3, &a2, &a1, &a0 );
13043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( subV, &s3, &s2, &s1, &s0 );
13044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm), mk128from32s( a3, s2, a1, s0 ));
13046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F D0 = ADDSUBPD -- 64x4 +/- from E (mem or xmm) to G (xmm). */
13050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
13051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xD0) {
13052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV   = newTemp(Ity_V128);
13053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV   = newTemp(Ity_V128);
13054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp addV = newTemp(Ity_V128);
13055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp subV = newTemp(Ity_V128);
13056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp a1     = newTemp(Ity_I64);
13057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp s0     = newTemp(Ity_I64);
13058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
13060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubpd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
13064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
13065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
13067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
13068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("addsubpd %s,%s\n", dis_buf,
13069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
13070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
13071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addV, binop(Iop_Add64Fx2, mkexpr(gV), mkexpr(eV)) );
13076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( subV, binop(Iop_Sub64Fx2, mkexpr(gV), mkexpr(eV)) );
13077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( a1, unop(Iop_V128HIto64, mkexpr(addV) ));
13079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( s0, unop(Iop_V128to64,   mkexpr(subV) ));
13080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm),
13082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(Iop_64HLtoV128, mkexpr(a1), mkexpr(s0)) );
13083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 7D = HSUBPS -- 32x4 sub across from E (mem or xmm) to G (xmm). */
13087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F 7C = HADDPS -- 32x4 add across from E (mem or xmm) to G (xmm). */
13088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
13089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
13090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e3, e2, e1, e0, g3, g2, g1, g0;
13091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV     = newTemp(Ity_V128);
13092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV     = newTemp(Ity_V128);
13093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp leftV  = newTemp(Ity_V128);
13094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rightV = newTemp(Ity_V128);
13095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isAdd  = insn[1] == 0x7C;
13096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = isAdd ? "add" : "sub";
13097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      e3 = e2 = e1 = e0 = g3 = g2 = g1 = g0 = IRTemp_INVALID;
13098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
13100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%sps %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
13104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
13105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
13107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
13108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%sps %s,%s\n", str, dis_buf,
13109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
13110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
13111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( eV, &e3, &e2, &e1, &e0 );
13116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( gV, &g3, &g2, &g1, &g0 );
13117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( leftV,  mk128from32s( e2, e0, g2, g0 ) );
13119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rightV, mk128from32s( e3, e1, g3, g1 ) );
13120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm),
13122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(isAdd ? Iop_Add32Fx4 : Iop_Sub32Fx4,
13123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(leftV), mkexpr(rightV) ) );
13124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7D = HSUBPD -- 64x2 sub across from E (mem or xmm) to G (xmm). */
13128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 7C = HADDPD -- 64x2 add across from E (mem or xmm) to G (xmm). */
13129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx) && sz == 2
13130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && (insn[1] == 0x7C || insn[1] == 0x7D)) {
13131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e1     = newTemp(Ity_I64);
13132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp e0     = newTemp(Ity_I64);
13133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp g1     = newTemp(Ity_I64);
13134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp g0     = newTemp(Ity_I64);
13135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp eV     = newTemp(Ity_V128);
13136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp gV     = newTemp(Ity_V128);
13137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp leftV  = newTemp(Ity_V128);
13138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rightV = newTemp(Ity_V128);
13139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isAdd  = insn[1] == 0x7C;
13140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = isAdd ? "add" : "sub";
13141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
13143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%spd %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameXMMReg(gregOfRexRM(pfx,modrm)));
13147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
13148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
13150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( eV, loadLE(Ity_V128, mkexpr(addr)) );
13151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("h%spd %s,%s\n", str, dis_buf,
13152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRexRM(pfx,modrm)));
13153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
13154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( gV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e1, unop(Iop_V128HIto64, mkexpr(eV) ));
13159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( e0, unop(Iop_V128to64, mkexpr(eV) ));
13160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( g1, unop(Iop_V128HIto64, mkexpr(gV) ));
13161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( g0, unop(Iop_V128to64, mkexpr(gV) ));
13162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( leftV,  binop(Iop_64HLtoV128, mkexpr(e0),mkexpr(g0)) );
13164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( rightV, binop(Iop_64HLtoV128, mkexpr(e1),mkexpr(g1)) );
13165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm),
13167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(isAdd ? Iop_Add64Fx2 : Iop_Sub64Fx2,
13168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       mkexpr(leftV), mkexpr(rightV) ) );
13169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F2 0F F0 = LDDQU -- move from E (mem or xmm) to G (xmm). */
13173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF2no66noF3(pfx) && sz == 4
13174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xF0) {
13175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
13176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
13178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+2, dis_buf, 0 );
13180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMReg( gregOfRexRM(pfx,modrm),
13181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    loadLE(Ity_V128, mkexpr(addr)) );
13182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lddqu %s,%s\n", dis_buf,
13183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameXMMReg(gregOfRexRM(pfx,modrm)));
13184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
13185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
13190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE3 decoder.                     --- */
13191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
13192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
13194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSSE3 decoder.                  --- */
13195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
13196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
13198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unsigned Bytes (MMX) */
13199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
13200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4
13201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
13202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV        = newTemp(Ity_I64);
13203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV        = newTemp(Ity_I64);
13204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVoddsSX  = newTemp(Ity_I64);
13205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVevensSX = newTemp(Ity_I64);
13206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVoddsZX  = newTemp(Ity_I64);
13207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVevensZX = newTemp(Ity_I64);
13208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregLO3ofRM(modrm)));
13218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", dis_buf,
13223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregLO3ofRM(modrm)));
13224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* compute dV unsigned x sV signed */
13227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVoddsSX,
13228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x4, mkexpr(sV), mkU8(8)) );
13229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVevensSX,
13230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x4,
13231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x4, mkexpr(sV), mkU8(8)),
13232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
13233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVoddsZX,
13234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x4, mkexpr(dV), mkU8(8)) );
13235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVevensZX,
13236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x4,
13237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x4, mkexpr(dV), mkU8(8)),
13238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
13239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
13241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregLO3ofRM(modrm),
13242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_QAdd16Sx4,
13243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x4, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
13244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x4, mkexpr(sVevensSX), mkexpr(dVevensZX))
13245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 04 = PMADDUBSW -- Multiply and Add Packed Signed and
13251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Unsigned Bytes (XMM) */
13252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x04) {
13255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV        = newTemp(Ity_V128);
13256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV        = newTemp(Ity_V128);
13257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVoddsSX  = newTemp(Ity_V128);
13258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sVevensSX = newTemp(Ity_V128);
13259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVoddsZX  = newTemp(Ity_V128);
13260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dVevensZX = newTemp(Ity_V128);
13261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
13270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmaddubsw %s,%s\n", dis_buf,
13276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
13277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* compute dV unsigned x sV signed */
13280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVoddsSX,
13281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x8, mkexpr(sV), mkU8(8)) );
13282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sVevensSX,
13283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_SarN16x8,
13284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x8, mkexpr(sV), mkU8(8)),
13285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
13286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVoddsZX,
13287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x8, mkexpr(dV), mkU8(8)) );
13288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dVevensZX,
13289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_ShrN16x8,
13290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_ShlN16x8, mkexpr(dV), mkU8(8)),
13291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(8)) );
13292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
13294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
13295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_QAdd16Sx8,
13296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x8, mkexpr(sVoddsSX), mkexpr(dVoddsZX)),
13297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Mul16x8, mkexpr(sVevensSX), mkexpr(dVevensZX))
13298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ***--- these are MMX class insns introduced in SSSE3 ---*** */
13304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 03 = PHADDSW -- 16x4 signed qadd across from E (mem or
13305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx) and G to G (mmx). */
13306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 07 = PHSUBSW -- 16x4 signed qsub across from E (mem or
13307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mmx) and G to G (mmx). */
13308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 01 = PHADDW -- 16x4 add across from E (mem or mmx) and G
13309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
13310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 05 = PHSUBW -- 16x4 sub across from E (mem or mmx) and G
13311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
13312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 02 = PHADDD -- 32x2 add across from E (mem or mmx) and G
13313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
13314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 06 = PHSUBD -- 32x2 sub across from E (mem or mmx) and G
13315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      to G (mmx). */
13316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
13318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4
13319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
13320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
13321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
13322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = "???";
13323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opV64  = Iop_INVALID;
13324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatO = Iop_CatOddLanes16x4;
13325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatE = Iop_CatEvenLanes16x4;
13326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV     = newTemp(Ity_I64);
13327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV     = newTemp(Ity_I64);
13328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
13332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
13333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
13334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
13335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
13336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
13337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
13338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
13339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn[2] == 0x02 || insn[2] == 0x06) {
13341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatO = Iop_InterleaveHI32x2;
13342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatE = Iop_InterleaveLO32x2;
13343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregLO3ofRM(modrm)));
13353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, dis_buf,
13358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameMMXReg(gregLO3ofRM(modrm)));
13359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
13362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregLO3ofRM(modrm),
13363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(opV64,
13364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opCatE,mkexpr(sV),mkexpr(dV)),
13365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opCatO,mkexpr(sV),mkexpr(dV))
13366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 03 = PHADDSW -- 16x8 signed qadd across from E (mem or
13372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm) and G to G (xmm). */
13373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 07 = PHSUBSW -- 16x8 signed qsub across from E (mem or
13374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      xmm) and G to G (xmm). */
13375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 01 = PHADDW -- 16x8 add across from E (mem or xmm) and
13376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
13377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 05 = PHSUBW -- 16x8 sub across from E (mem or xmm) and
13378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
13379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 02 = PHADDD -- 32x4 add across from E (mem or xmm) and
13380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
13381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 06 = PHSUBD -- 32x4 sub across from E (mem or xmm) and
13382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      G to G (xmm). */
13383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
13387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x03 || insn[2] == 0x07 || insn[2] == 0x01
13388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || insn[2] == 0x05 || insn[2] == 0x02 || insn[2] == 0x06)) {
13389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str    = "???";
13390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opV64  = Iop_INVALID;
13391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatO = Iop_CatOddLanes16x4;
13392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IROp   opCatE = Iop_CatEvenLanes16x4;
13393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV     = newTemp(Ity_V128);
13394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV     = newTemp(Ity_V128);
13395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi    = newTemp(Ity_I64);
13396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo    = newTemp(Ity_I64);
13397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi    = newTemp(Ity_I64);
13398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo    = newTemp(Ity_I64);
13399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
13403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x03: opV64 = Iop_QAdd16Sx4; str = "addsw"; break;
13404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x07: opV64 = Iop_QSub16Sx4; str = "subsw"; break;
13405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x01: opV64 = Iop_Add16x4;   str = "addw";  break;
13406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x05: opV64 = Iop_Sub16x4;   str = "subw";  break;
13407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: opV64 = Iop_Add32x2;   str = "addd";  break;
13408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x06: opV64 = Iop_Sub32x2;   str = "subd";  break;
13409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
13410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (insn[2] == 0x02 || insn[2] == 0x06) {
13412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatO = Iop_InterleaveHI32x2;
13413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         opCatE = Iop_InterleaveLO32x2;
13414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg( eregOfRexRM(pfx,modrm)) );
13420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameXMMReg(gregOfRexRM(pfx,modrm)));
13422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("ph%s %s,%s\n", str, dis_buf,
13428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             nameXMMReg(gregOfRexRM(pfx,modrm)));
13429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
13434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
13436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This isn't a particularly efficient way to compute the
13438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         result, but at least it avoids a proliferation of IROps,
13439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         hence avoids complication all the backends. */
13440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
13441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
13442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
13443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opV64,
13444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatE,mkexpr(sHi),mkexpr(sLo)),
13445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatO,mkexpr(sHi),mkexpr(sLo))
13446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               ),
13447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(opV64,
13448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatE,mkexpr(dHi),mkexpr(dLo)),
13449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop(opCatO,mkexpr(dHi),mkexpr(dLo))
13450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )
13451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and Scale
13457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (MMX) */
13458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
13459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4
13460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
13461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV = newTemp(Ity_I64);
13462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV = newTemp(Ity_I64);
13463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg(gregLO3ofRM(modrm)));
13473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", dis_buf,
13478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameMMXReg(gregLO3ofRM(modrm)));
13479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
13482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregLO3ofRM(modrm),
13483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PMULHRSW_helper( mkexpr(sV), mkexpr(dV) )
13484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 0B = PMULHRSW -- Packed Multiply High with Round and
13489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Scale (XMM) */
13490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x0B) {
13493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
13494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_V128);
13495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi = newTemp(Ity_I64);
13496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo = newTemp(Ity_I64);
13497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi = newTemp(Ity_I64);
13498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo = newTemp(Ity_I64);
13499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
13508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pmulhrsw %s,%s\n", dis_buf,
13514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameXMMReg(gregOfRexRM(pfx,modrm)));
13515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
13519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
13521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
13523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
13524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
13525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PMULHRSW_helper( mkexpr(sHi), mkexpr(dHi) ),
13526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PMULHRSW_helper( mkexpr(sLo), mkexpr(dLo) )
13527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 08 = PSIGNB -- Packed Sign 8x8  (MMX) */
13533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 09 = PSIGNW -- Packed Sign 16x4 (MMX) */
13534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 09 = PSIGND -- Packed Sign 32x2 (MMX) */
13535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
13536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4
13537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
13538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
13539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
13540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_I64);
13541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
13542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
13543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
13545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x08: laneszB = 1; str = "b"; break;
13546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x09: laneszB = 2; str = "w"; break;
13547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x0A: laneszB = 4; str = "d"; break;
13548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
13549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregLO3ofRM(modrm)));
13560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, dis_buf,
13565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregLO3ofRM(modrm)));
13566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
13569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregLO3ofRM(modrm),
13570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PSIGN_helper( mkexpr(sV), mkexpr(dV), laneszB )
13571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 08 = PSIGNB -- Packed Sign 8x16 (XMM) */
13576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 09 = PSIGNW -- Packed Sign 16x8 (XMM) */
13577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 09 = PSIGND -- Packed Sign 32x4 (XMM) */
13578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
13581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x08 || insn[2] == 0x09 || insn[2] == 0x0A)) {
13582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_V128);
13583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_V128);
13584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi     = newTemp(Ity_I64);
13585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo     = newTemp(Ity_I64);
13586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi     = newTemp(Ity_I64);
13587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo     = newTemp(Ity_I64);
13588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
13589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
13590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
13592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x08: laneszB = 1; str = "b"; break;
13593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x09: laneszB = 2; str = "w"; break;
13594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x0A: laneszB = 4; str = "d"; break;
13595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
13596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRexRM(pfx,modrm)));
13606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("psign%s %s,%s\n", str, dis_buf,
13612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameXMMReg(gregOfRexRM(pfx,modrm)));
13613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
13617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
13619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
13621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
13622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
13623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PSIGN_helper( mkexpr(sHi), mkexpr(dHi), laneszB ),
13624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PSIGN_helper( mkexpr(sLo), mkexpr(dLo), laneszB )
13625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1C = PABSB -- Packed Absolute Value 8x8  (MMX) */
13631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1D = PABSW -- Packed Absolute Value 16x4 (MMX) */
13632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 1E = PABSD -- Packed Absolute Value 32x2 (MMX) */
13633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
13634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4
13635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
13636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
13637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
13638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
13639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
13640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
13642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1C: laneszB = 1; str = "b"; break;
13643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1D: laneszB = 2; str = "w"; break;
13644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1E: laneszB = 4; str = "d"; break;
13645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
13646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, nameMMXReg(eregLO3ofRM(modrm)),
13655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameMMXReg(gregLO3ofRM(modrm)));
13656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, dis_buf,
13661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameMMXReg(gregLO3ofRM(modrm)));
13662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
13665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregLO3ofRM(modrm),
13666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_PABS_helper( mkexpr(sV), laneszB )
13667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1C = PABSB -- Packed Absolute Value 8x16 (XMM) */
13672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1D = PABSW -- Packed Absolute Value 16x8 (XMM) */
13673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 1E = PABSD -- Packed Absolute Value 32x4 (XMM) */
13674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38
13677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x1C || insn[2] == 0x1D || insn[2] == 0x1E)) {
13678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_V128);
13679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi     = newTemp(Ity_I64);
13680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo     = newTemp(Ity_I64);
13681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* str     = "???";
13682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    laneszB = 0;
13683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (insn[2]) {
13685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1C: laneszB = 1; str = "b"; break;
13686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1D: laneszB = 2; str = "w"; break;
13687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x1E: laneszB = 4; str = "d"; break;
13688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
13689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, nameXMMReg(eregOfRexRM(pfx,modrm)),
13697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
13698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pabs%s %s,%s\n", str, dis_buf,
13704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
13705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
13709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
13711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
13712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128,
13713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PABS_helper( mkexpr(sHi), laneszB ),
13714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               dis_PABS_helper( mkexpr(sLo), laneszB )
13715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 3A 0F = PALIGNR -- Packed Align Right (MMX) */
13721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx) && sz == 4
13722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
13723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_I64);
13724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_I64);
13725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(Ity_I64);
13726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = (Long)insn[3+1];
13734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
13735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n",  (Int)d64,
13736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(eregLO3ofRM(modrm)),
13737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     nameMMXReg(gregLO3ofRM(modrm)));
13738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 1 );
13740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = (Long)insn[3+alen];
13742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
13743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d%s,%s\n", (Int)d64,
13744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   dis_buf,
13745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameMMXReg(gregLO3ofRM(modrm)));
13746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d64 == 0) {
13749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, mkexpr(sV) );
13750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 1 && d64 <= 7) {
13752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(res,
13753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                binop(Iop_Or64,
13754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shr64, mkexpr(sV), mkU8(8*d64)),
13755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      binop(Iop_Shl64, mkexpr(dV), mkU8(8*(8-d64))
13756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     )));
13757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 == 8) {
13759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        assign( res, mkexpr(dV) );
13760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 9 && d64 <= 15) {
13762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, binop(Iop_Shr64, mkexpr(dV), mkU8(8*(d64-8))) );
13763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 16 && d64 <= 255) {
13765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( res, mkU64(0) );
13766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
13768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
13769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg( gregLO3ofRM(modrm), mkexpr(res) );
13771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0F = PALIGNR -- Packed Align Right (XMM) */
13775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0F) {
13778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV  = newTemp(Ity_V128);
13779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV  = newTemp(Ity_V128);
13780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi = newTemp(Ity_I64);
13781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo = newTemp(Ity_I64);
13782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi = newTemp(Ity_I64);
13783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo = newTemp(Ity_I64);
13784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rHi = newTemp(Ity_I64);
13785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rLo = newTemp(Ity_I64);
13786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = (Long)insn[3+1];
13793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
13794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n", (Int)d64,
13795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(eregOfRexRM(pfx,modrm)),
13796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
13797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 1 );
13799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = (Long)insn[3+alen];
13802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
13803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("palignr $%d,%s,%s\n", (Int)d64,
13804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    dis_buf,
13805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    nameXMMReg(gregOfRexRM(pfx,modrm)));
13806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
13810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
13812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (d64 == 0) {
13814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(sHi) );
13815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(sLo) );
13816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 1 && d64 <= 7) {
13818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, dis_PALIGNR_XMM_helper(dLo, sHi, d64) );
13819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(sHi, sLo, d64) );
13820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 == 8) {
13822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(dLo) );
13823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(sHi) );
13824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 9 && d64 <= 15) {
13826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, dis_PALIGNR_XMM_helper(dHi, dLo, d64-8) );
13827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(dLo, sHi, d64-8) );
13828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 == 16) {
13830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkexpr(dHi) );
13831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(dLo) );
13832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 17 && d64 <= 23) {
13834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d64-16))) );
13835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, dis_PALIGNR_XMM_helper(dHi, dLo, d64-16) );
13836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 == 24) {
13838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
13839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkexpr(dHi) );
13840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 25 && d64 <= 31) {
13842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
13843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, binop(Iop_Shr64, mkexpr(dHi), mkU8(8*(d64-24))) );
13844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else if (d64 >= 32 && d64 <= 255) {
13846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rHi, mkU64(0) );
13847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( rLo, mkU64(0) );
13848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
13850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(0);
13851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
13853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
13854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
13855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x8 (MMX) */
13860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveNo66noF2noF3(pfx)
13861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 4
13862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
13863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV      = newTemp(Ity_I64);
13864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV      = newTemp(Ity_I64);
13865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      do_MMX_preamble();
13868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getMMXReg(gregLO3ofRM(modrm)) );
13869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getMMXReg(eregLO3ofRM(modrm)) );
13872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", nameMMXReg(eregLO3ofRM(modrm)),
13874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregLO3ofRM(modrm)));
13875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
13878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", dis_buf,
13880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameMMXReg(gregLO3ofRM(modrm)));
13881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putMMXReg(
13884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregLO3ofRM(modrm),
13885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
13886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_And64,
13887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* permute the lanes */
13888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(
13889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Iop_Perm8x8,
13890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkexpr(dV),
13891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64, mkexpr(sV), mkU64(0x0707070707070707ULL))
13892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            ),
13893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* mask off lanes which have (index & 0x80) == 0x80 */
13894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unop(Iop_Not64, binop(Iop_SarN8x8, mkexpr(sV), mkU8(7)))
13895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
13896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
13897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
13898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
13899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 00 = PSHUFB -- Packed Shuffle Bytes 8x16 (XMM) */
13901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
13902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (sz == 2 || /*redundant REX.W*/ sz == 8)
13903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x00) {
13904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sV         = newTemp(Ity_V128);
13905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dV         = newTemp(Ity_V128);
13906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sHi        = newTemp(Ity_I64);
13907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sLo        = newTemp(Ity_I64);
13908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dHi        = newTemp(Ity_I64);
13909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dLo        = newTemp(Ity_I64);
13910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rHi        = newTemp(Ity_I64);
13911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp rLo        = newTemp(Ity_I64);
13912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sevens     = newTemp(Ity_I64);
13913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask0x80hi = newTemp(Ity_I64);
13914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp mask0x80lo = newTemp(Ity_I64);
13915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp maskBit3hi = newTemp(Ity_I64);
13916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp maskBit3lo = newTemp(Ity_I64);
13917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sAnd7hi    = newTemp(Ity_I64);
13918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sAnd7lo    = newTemp(Ity_I64);
13919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp permdHi    = newTemp(Ity_I64);
13920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp permdLo    = newTemp(Ity_I64);
13921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
13923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
13924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
13926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
13927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
13928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
13929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
13930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
13931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
13932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
13933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
13934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
13935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pshufb %s,%s\n", dis_buf,
13936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               nameXMMReg(gregOfRexRM(pfx,modrm)));
13937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
13938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dHi, unop(Iop_V128HIto64, mkexpr(dV)) );
13940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dLo, unop(Iop_V128to64,   mkexpr(dV)) );
13941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sHi, unop(Iop_V128HIto64, mkexpr(sV)) );
13942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sLo, unop(Iop_V128to64,   mkexpr(sV)) );
13943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sevens, mkU64(0x0707070707070707ULL) );
13945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*
13947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      mask0x80hi = Not(SarN8x8(sHi,7))
13948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      maskBit3hi = SarN8x8(ShlN8x8(sHi,4),7)
13949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sAnd7hi    = And(sHi,sevens)
13950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      permdHi    = Or( And(Perm8x8(dHi,sAnd7hi),maskBit3hi),
13951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       And(Perm8x8(dLo,sAnd7hi),Not(maskBit3hi)) )
13952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rHi        = And(permdHi,mask0x80hi)
13953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
13954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
13955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask0x80hi,
13956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sHi),mkU8(7))));
13957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
13959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maskBit3hi,
13960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_SarN8x8,
13961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_ShlN8x8,mkexpr(sHi),mkU8(4)),
13962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(7)));
13963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(sAnd7hi, binop(Iop_And64,mkexpr(sHi),mkexpr(sevens)));
13965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
13967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         permdHi,
13968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
13969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Or64,
13970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
13971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7hi)),
13972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(maskBit3hi)),
13973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
13974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7hi)),
13975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_Not64,mkexpr(maskBit3hi))) ));
13976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rHi, binop(Iop_And64,mkexpr(permdHi),mkexpr(mask0x80hi)) );
13978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And the same for the lower half of the result.  What fun. */
13980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
13982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask0x80lo,
13983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_Not64, binop(Iop_SarN8x8,mkexpr(sLo),mkU8(7))));
13984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
13986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         maskBit3lo,
13987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_SarN8x8,
13988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_ShlN8x8,mkexpr(sLo),mkU8(4)),
13989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               mkU8(7)));
13990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(sAnd7lo, binop(Iop_And64,mkexpr(sLo),mkexpr(sevens)));
13992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
13994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         permdLo,
13995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(
13996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            Iop_Or64,
13997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
13998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dHi),mkexpr(sAnd7lo)),
13999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkexpr(maskBit3lo)),
14000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_And64,
14001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Perm8x8,mkexpr(dLo),mkexpr(sAnd7lo)),
14002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_Not64,mkexpr(maskBit3lo))) ));
14003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(rLo, binop(Iop_And64,mkexpr(permdLo),mkexpr(mask0x80lo)) );
14005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg(
14007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gregOfRexRM(pfx,modrm),
14008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_64HLtoV128, mkexpr(rHi), mkexpr(rLo))
14009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
14010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
14014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSSE3 decoder.                    --- */
14015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
14016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
14018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- start of the SSE4 decoder                    --- */
14019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
14020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0D /r ib = BLENDPD xmm1, xmm2/m128, imm8
14022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Blend Packed Double Precision Floating-Point Values (XMM) */
14023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0D ) {
14026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8;
14028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort imm8_mask_16;
14029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_vec = newTemp(Ity_V128);
14031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_vec = newTemp(Ity_V128);
14032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp imm8_mask = newTemp(Ity_V128);
14033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[4];
14039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "blendpd $%d, %s,%s\n", imm8,
14042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          1/* imm8 is 1 byte after the amode */ );
14047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
14048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[2+alen+1];
14050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "blendpd $%d, %s,%s\n",
14052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch( imm8 & 3 ) {
14056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  imm8_mask_16 = 0x0000; break;
14057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  imm8_mask_16 = 0x00FF; break;
14058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  imm8_mask_16 = 0xFF00; break;
14059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  imm8_mask_16 = 0xFFFF; break;
14060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);            break;
14061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( imm8_mask, mkV128( imm8_mask_16 ) );
14063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_OrV128,
14066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm8_mask) ),
14067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128, mkexpr(dst_vec),
14068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
14069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0C /r ib = BLENDPS xmm1, xmm2/m128, imm8
14075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Blend Packed Single Precision Floating-Point Values (XMM) */
14076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0C ) {
14079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8;
14081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_vec = newTemp(Ity_V128);
14082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_vec = newTemp(Ity_V128);
14083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[3+1];
14090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "blendps $%d, %s,%s\n", imm8,
14093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          1/* imm8 is 1 byte after the amode */ );
14098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
14099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[3+alen];
14101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "blendpd $%d, %s,%s\n",
14103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort imm8_perms[16] = { 0x0000, 0x000F, 0x00F0, 0x00FF, 0x0F00, 0x0F0F,
14107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0x0FF0, 0x0FFF, 0xF000, 0xF00F, 0xF0F0, 0xF0FF,
14108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0xFF00, 0xFF0F, 0xFFF0, 0xFFFF };
14109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp imm8_mask = newTemp(Ity_V128);
14110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( imm8_mask, mkV128( imm8_perms[ (imm8 & 15) ] ) );
14111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_OrV128,
14114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm8_mask) ),
14115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128, mkexpr(dst_vec),
14116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               unop( Iop_NotV128, mkexpr(imm8_mask) ) ) ) );
14117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14122f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* 66 0F 3A 0E /r ib = PBLENDW xmm1, xmm2/m128, imm8
14123f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Blend Packed Words (XMM) */
14124f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if ( have66noF2noF3( pfx )
14125f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root        && sz == 2
14126f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x0E ) {
14127f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14128f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Int imm8;
14129f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp dst_vec = newTemp(Ity_V128);
14130f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src_vec = newTemp(Ity_V128);
14131f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14132f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = insn[3];
14133f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14134f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14135f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14136f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if ( epartIsReg( modrm ) ) {
14137f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm8 = (Int)insn[3+1];
14138f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14139f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+1+1;
14140f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "pblendw $%d, %s,%s\n", imm8,
14141f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14142f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14143f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
14144f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14145f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                          1/* imm8 is 1 byte after the amode */ );
14146f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         gen_SEGV_if_not_16_aligned( addr );
14147f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14148f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm8 = (Int)insn[3+alen];
14149f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+alen+1;
14150f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "pblendw $%d, %s,%s\n",
14151f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14152f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
14153f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14154f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Make w be a 16-bit version of imm8, formed by duplicating each
14155f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         bit in imm8. */
14156f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Int i;
14157f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      UShort imm16 = 0;
14158f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      for (i = 0; i < 8; i++) {
14159f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         if (imm8 & (1 << i))
14160f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             imm16 |= (3 << (2*i));
14161f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
14162f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp imm16_mask = newTemp(Ity_V128);
14163f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign( imm16_mask, mkV128( imm16 ));
14164f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14165f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMReg( gregOfRexRM(pfx, modrm),
14166f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 binop( Iop_OrV128,
14167f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        binop( Iop_AndV128, mkexpr(src_vec), mkexpr(imm16_mask) ),
14168f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        binop( Iop_AndV128, mkexpr(dst_vec),
14169f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                               unop( Iop_NotV128, mkexpr(imm16_mask) ) ) ) );
14170f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14171f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
14172f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
14173f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14174f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 44 /r ib = PCLMULQDQ xmm1, xmm2/m128, imm8
14176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * Carry-less multiplication of selected XMM quadwords into XMM
14177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    * registers (a.k.a multiplication of polynomials over GF(2))
14178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
14179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x44 ) {
14182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8;
14184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp svec = newTemp(Ity_V128);
14185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dvec = newTemp(Ity_V128);
14186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dvec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[4];
14193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( svec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pclmulqdq $%d, %s,%s\n", imm8,
14196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          1/* imm8 is 1 byte after the amode */ );
14201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
14202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( svec, loadLE( Ity_V128, mkexpr(addr) ) );
14203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[2+alen+1];
14204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pclmulqdq $%d, %s,%s\n",
14206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I64);
14210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
14211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t0, unop((imm8&1)? Iop_V128HIto64 : Iop_V128to64, mkexpr(dvec)));
14212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop((imm8&16) ? Iop_V128HIto64 : Iop_V128to64, mkexpr(svec)));
14213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
14215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I64);
14216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr** args;
14218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      args = mkIRExprVec_3(mkexpr(t0), mkexpr(t1), mkU64(0));
14220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2,
14221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(Ity_I64,0, "amd64g_calculate_pclmul",
14222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       &amd64g_calculate_pclmul, args));
14223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      args = mkIRExprVec_3(mkexpr(t0), mkexpr(t1), mkU64(1));
14224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t3,
14225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              mkIRExprCCall(Ity_I64,0, "amd64g_calculate_pclmul",
14226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                       &amd64g_calculate_pclmul, args));
14227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res     = newTemp(Ity_V128);
14229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(Iop_64HLtoV128, mkexpr(t3), mkexpr(t2)));
14230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx,modrm), mkexpr(res) );
14231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 41 /r ib = DPPD xmm1, xmm2/m128, imm8
14236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Dot Product of Packed Double Precision Floating-Point Values (XMM) */
14237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x41 ) {
14240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8;
14242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_vec = newTemp(Ity_V128);
14243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_vec = newTemp(Ity_V128);
14244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp and_vec = newTemp(Ity_V128);
14245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sum_vec = newTemp(Ity_V128);
14246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dst_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[4];
14253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "dppd $%d, %s,%s\n", imm8,
14256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          1/* imm8 is 1 byte after the amode */ );
14261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
14262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[2+alen+1];
14264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "dppd $%d, %s,%s\n",
14266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort imm8_perms[4] = { 0x0000, 0x00FF, 0xFF00, 0xFFFF };
14270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( and_vec, binop( Iop_AndV128,
14272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_Mul64Fx2,
14273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(dst_vec), mkexpr(src_vec) ),
14274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkV128( imm8_perms[ ((imm8 >> 4) & 3) ] ) ) );
14275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sum_vec, binop( Iop_Add64F0x2,
14277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_InterleaveHI64x2,
14278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(and_vec), mkexpr(and_vec) ),
14279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_InterleaveLO64x2,
14280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(and_vec), mkexpr(and_vec) ) ) );
14281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM( pfx, modrm ),
14283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_AndV128,
14284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_InterleaveLO64x2,
14285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(sum_vec), mkexpr(sum_vec) ),
14286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkV128( imm8_perms[ (imm8 & 3) ] ) ) );
14287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 40 /r ib = DPPS xmm1, xmm2/m128, imm8
14293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Dot Product of Packed Single Precision Floating-Point Values (XMM) */
14294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F
14297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[1] == 0x3A
14298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[2] == 0x40 ) {
14299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8;
14301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp xmm1_vec     = newTemp(Ity_V128);
14302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp xmm2_vec     = newTemp(Ity_V128);
14303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tmp_prod_vec = newTemp(Ity_V128);
14304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp prod_vec     = newTemp(Ity_V128);
14305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp sum_vec      = newTemp(Ity_V128);
14306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp v3, v2, v1, v0;
14307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      v3 = v2 = v1 = v0   = IRTemp_INVALID;
14308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( xmm1_vec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[4];
14315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( xmm2_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "dpps $%d, %s,%s\n", imm8,
14318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          1/* imm8 is 1 byte after the amode */ );
14323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
14324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( xmm2_vec, loadLE( Ity_V128, mkexpr(addr) ) );
14325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[2+alen+1];
14326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "dpps $%d, %s,%s\n",
14328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort imm8_perms[16] = { 0x0000, 0x000F, 0x00F0, 0x00FF, 0x0F00,
14332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0x0F0F, 0x0FF0, 0x0FFF, 0xF000, 0xF00F,
14333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                0xF0F0, 0xF0FF, 0xFF00, 0xFF0F, 0xFFF0, 0xFFFF };
14334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( tmp_prod_vec,
14336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop( Iop_AndV128,
14337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     binop( Iop_Mul32Fx4, mkexpr(xmm1_vec), mkexpr(xmm2_vec) ),
14338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkV128( imm8_perms[((imm8 >> 4)& 15)] ) ) );
14339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( tmp_prod_vec, &v3, &v2, &v1, &v0 );
14340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( prod_vec, mk128from32s( v3, v1, v2, v0 ) );
14341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( sum_vec, binop( Iop_Add32Fx4,
14343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_InterleaveHI32x4,
14344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(prod_vec), mkexpr(prod_vec) ),
14345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop( Iop_InterleaveLO32x4,
14346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     mkexpr(prod_vec), mkexpr(prod_vec) ) ) );
14347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_AndV128,
14350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_Add32Fx4,
14351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop( Iop_InterleaveHI32x4,
14352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(sum_vec), mkexpr(sum_vec) ),
14353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop( Iop_InterleaveLO32x4,
14354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(sum_vec), mkexpr(sum_vec) ) ),
14355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkV128( imm8_perms[ (imm8 & 15) ] ) ) );
14356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 21 /r ib = INSERTPS xmm1, xmm2/m32, imm8
14362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Insert Packed Single Precision Floating-Point Value (XMM) */
14363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x21 ) {
14366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8;
14368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_count_s;
14369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_count_d;
14370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_zmask;
14371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dstVec   = newTemp(Ity_V128);
14372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcDWord = newTemp(Ity_I32);
14373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( dstVec, getXMMReg( gregOfRexRM(pfx, modrm) ) );
14377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src_vec = newTemp(Ity_V128);
14380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src_lane_0 = IRTemp_INVALID;
14383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src_lane_1 = IRTemp_INVALID;
14384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src_lane_2 = IRTemp_INVALID;
14385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp src_lane_3 = IRTemp_INVALID;
14386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         breakup128to32s( src_vec,
14387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &src_lane_3, &src_lane_2, &src_lane_1, &src_lane_0 );
14388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[4];
14390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_count_s = ((imm8 >> 6) & 3);
14391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch( imm8_count_s ) {
14392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           case 0:  assign( srcDWord, mkexpr(src_lane_0) ); break;
14393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           case 1:  assign( srcDWord, mkexpr(src_lane_1) ); break;
14394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           case 2:  assign( srcDWord, mkexpr(src_lane_2) ); break;
14395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           case 3:  assign( srcDWord, mkexpr(src_lane_3) ); break;
14396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           default: vassert(0);                             break;
14397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
14398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "insertps $%d, %s,%s\n", imm8,
14401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf,
14405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          1/* const imm8 is 1 byte after the amode */ );
14406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcDWord, loadLE( Ity_I32, mkexpr(addr) ) );
14407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)insn[2+alen+1];
14408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_count_s = 0;
14409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "insertps $%d, %s,%s\n",
14411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_lane_0 = IRTemp_INVALID;
14415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_lane_1 = IRTemp_INVALID;
14416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_lane_2 = IRTemp_INVALID;
14417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp dst_lane_3 = IRTemp_INVALID;
14418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( dstVec,
14419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       &dst_lane_3, &dst_lane_2, &dst_lane_1, &dst_lane_0 );
14420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8_count_d = ((imm8 >> 4) & 3);
14422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch( imm8_count_d ) {
14423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  dst_lane_0 = srcDWord; break;
14424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  dst_lane_1 = srcDWord; break;
14425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  dst_lane_2 = srcDWord; break;
14426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  dst_lane_3 = srcDWord; break;
14427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);            break;
14428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      imm8_zmask = (imm8 & 15);
14431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp zero_32 = newTemp(Ity_I32);
14432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( zero_32, mkU32(0) );
14433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* ire_vec_128 = mk128from32s(
14435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               ((imm8_zmask & 8) == 8) ? zero_32 : dst_lane_3,
14436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               ((imm8_zmask & 4) == 4) ? zero_32 : dst_lane_2,
14437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               ((imm8_zmask & 2) == 2) ? zero_32 : dst_lane_1,
14438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               ((imm8_zmask & 1) == 1) ? zero_32 : dst_lane_0 );
14439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm), ire_vec_128 );
14441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* 66 0F 3A 14 /r ib = PEXTRB r/m16, xmm, imm8
14447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Extract Byte from xmm, store in mem or zero-extend + store in gen.reg. (XMM) */
14448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if ( have66noF2noF3( pfx )
14449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 2
14450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x14 ) {
14451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     Int imm8;
14453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp xmm_vec  = newTemp(Ity_V128);
14454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp sel_lane = newTemp(Ity_I32);
14455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     IRTemp shr_lane = newTemp(Ity_I32);
14456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     modrm = insn[3];
14458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ( epartIsReg( modrm ) ) {
14462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        imm8 = (Int)insn[3+1];
14463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
14464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        imm8 = (Int)insn[3+alen];
14466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
14467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     switch( (imm8 >> 2) & 3 ) {
14468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 0:  assign( sel_lane, mkexpr(t0) ); break;
14469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 1:  assign( sel_lane, mkexpr(t1) ); break;
14470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 2:  assign( sel_lane, mkexpr(t2) ); break;
14471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        case 3:  assign( sel_lane, mkexpr(t3) ); break;
14472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        default: vassert(0);
14473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
14474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     assign( shr_lane,
14475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop( Iop_Shr32, mkexpr(sel_lane), mkU8(((imm8 & 3)*8)) ) );
14476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     if ( epartIsReg( modrm ) ) {
14478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        putIReg64( eregOfRexRM(pfx,modrm),
14479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   unop( Iop_32Uto64,
14480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         binop(Iop_And32, mkexpr(shr_lane), mkU32(255)) ) );
14481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        delta += 3+1+1;
14483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "pextrb $%d, %s,%s\n", imm8,
14484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameXMMReg( gregOfRexRM(pfx, modrm) ),
14485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIReg64( eregOfRexRM(pfx, modrm) ) );
14486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     } else {
14487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(addr), unop(Iop_32to8, mkexpr(shr_lane) ) );
14488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        delta += 3+alen+1;
14489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        DIP( "$%d, pextrb %s,%s\n",
14490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             imm8, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
14491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     }
14492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown     goto decode_success;
14494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
14495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 16 /r ib = PEXTRD reg/mem32, xmm2, imm8
14498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Extract Doubleword int from xmm reg and store in gen.reg or mem. (XMM)
14499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Note that this insn has the same opcodes as PEXTRQ, but
14500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      here the REX.W bit is _not_ present */
14501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2  /* REX.W is _not_ present */
14503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x16 ) {
14504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_10;
14506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp xmm_vec   = newTemp(Ity_V128);
14507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_dword = newTemp(Ity_I32);
14508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_10 = (Int)(insn[3+1] & 3);
14515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_10 = (Int)(insn[3+alen] & 3);
14518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch ( imm8_10 ) {
14521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  assign( src_dword, mkexpr(t0) ); break;
14522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  assign( src_dword, mkexpr(t1) ); break;
14523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  assign( src_dword, mkexpr(t2) ); break;
14524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  assign( src_dword, mkexpr(t3) ); break;
14525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
14526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg32( eregOfRexRM(pfx,modrm), mkexpr(src_dword) );
14530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pextrd $%d, %s,%s\n", imm8_10,
14532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ),
14533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameIReg32( eregOfRexRM(pfx, modrm) ) );
14534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(src_dword) );
14536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pextrd $%d, %s,%s\n",
14538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8_10, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
14539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 REX.W 0F 3A 16 /r ib = PEXTRQ reg/mem64, xmm2, imm8
14546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Extract Quadword int from xmm reg and store in gen.reg or mem. (XMM)
14547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Note that this insn has the same opcodes as PEXTRD, but
14548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      here the REX.W bit is present */
14549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 8  /* REX.W is present */
14551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x16 ) {
14552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_0;
14554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp xmm_vec   = newTemp(Ity_V128);
14555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_qword = newTemp(Ity_I64);
14556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_0 = (Int)(insn[3+1] & 1);
14562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr   = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_0 = (Int)(insn[3+alen] & 1);
14565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch ( imm8_0 ) {
14567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  assign( src_qword, unop(Iop_V128to64,   mkexpr(xmm_vec)) ); break;
14568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  assign( src_qword, unop(Iop_V128HIto64, mkexpr(xmm_vec)) ); break;
14569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
14570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64( eregOfRexRM(pfx,modrm), mkexpr(src_qword) );
14574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pextrq $%d, %s,%s\n", imm8_0,
14576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ),
14577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameIReg64( eregOfRexRM(pfx, modrm) ) );
14578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(src_qword) );
14580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pextrq $%d, %s,%s\n",
14582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8_0, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
14583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 15 /r ib = PEXTRW r/m16, xmm, imm8
14590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Extract Word from xmm, store in mem or zero-extend + store in gen.reg. (XMM) */
14591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x15 ) {
14594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_20;
14596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp xmm_vec = newTemp(Ity_V128);
14597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_word = newTemp(Ity_I16);
14598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_20 = (Int)(insn[3+1] & 7);
14605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_20 = (Int)(insn[3+alen] & 7);
14608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch ( imm8_20 ) {
14611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  assign( src_word, unop(Iop_32to16,   mkexpr(t0)) ); break;
14612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  assign( src_word, unop(Iop_32HIto16, mkexpr(t0)) ); break;
14613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  assign( src_word, unop(Iop_32to16,   mkexpr(t1)) ); break;
14614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  assign( src_word, unop(Iop_32HIto16, mkexpr(t1)) ); break;
14615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 4:  assign( src_word, unop(Iop_32to16,   mkexpr(t2)) ); break;
14616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 5:  assign( src_word, unop(Iop_32HIto16, mkexpr(t2)) ); break;
14617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 6:  assign( src_word, unop(Iop_32to16,   mkexpr(t3)) ); break;
14618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 7:  assign( src_word, unop(Iop_32HIto16, mkexpr(t3)) ); break;
14619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
14620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64( eregOfRexRM(pfx,modrm), unop(Iop_16Uto64, mkexpr(src_word)) );
14624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pextrw $%d, %s,%s\n", imm8_20,
14626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ),
14627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameIReg64( eregOfRexRM(pfx, modrm) ) );
14628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE( mkexpr(addr), mkexpr(src_word) );
14630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pextrw $%d, %s,%s\n",
14632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8_20, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
14633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 REX.W 0F 3A 22 /r ib = PINSRQ xmm1, r/m64, imm8
14640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Extract Quadword int from gen.reg/mem64 and insert into xmm1 */
14641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 8  /* REX.W is present */
14643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x22 ) {
14644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_0;
14646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_elems = newTemp(Ity_I64);
14647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_vec   = newTemp(Ity_V128);
14648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_0 = (Int)(insn[3+1] & 1);
14653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_elems, getIReg64( eregOfRexRM(pfx,modrm) ) );
14654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pinsrq $%d, %s,%s\n", imm8_0,
14656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameIReg64( eregOfRexRM(pfx, modrm) ),
14657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_0 = (Int)(insn[3+alen] & 1);
14661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_elems, loadLE( Ity_I64, mkexpr(addr) ) );
14662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pinsrq $%d, %s,%s\n",
14664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8_0, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort mask = 0;
14668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( imm8_0 == 0 ) {
14669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask = 0xFF00;
14670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec,  binop( Iop_64HLtoV128, mkU64(0), mkexpr(src_elems) ) );
14671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mask = 0x00FF;
14673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_vec, binop( Iop_64HLtoV128, mkexpr(src_elems), mkU64(0) ) );
14674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_OrV128, mkexpr(src_vec),
14678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128,
14679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getXMMReg( gregOfRexRM(pfx, modrm) ),
14680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkV128(mask) ) ) );
14681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 no-REX.W 0F 3A 22 /r ib = PINSRD xmm1, r/m32, imm8
14687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Extract Doubleword int from gen.reg/mem32 and insert into xmm1 */
14688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2 /* REX.W is NOT present */
14690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x22 ) {
14691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int imm8_10;
14693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_elems = newTemp(Ity_I32);
14694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src_vec   = newTemp(Ity_V128);
14695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp z32       = newTemp(Ity_I32);
14696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_10 = (Int)(insn[3+1] & 3);
14701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_elems, getIReg32( eregOfRexRM(pfx,modrm) ) );
14702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pinsrd $%d, %s,%s\n", imm8_10,
14704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameIReg32( eregOfRexRM(pfx, modrm) ),
14705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8_10 = (Int)(insn[3+alen] & 3);
14709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src_elems, loadLE( Ity_I32, mkexpr(addr) ) );
14710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pinsrd $%d, %s,%s\n",
14712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8_10, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(z32, mkU32(0));
14716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort mask = 0;
14718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm8_10) {
14719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 3:  mask = 0x0FFF;
14720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(src_vec, mk128from32s(src_elems, z32, z32, z32));
14721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
14722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 2:  mask = 0xF0FF;
14723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(src_vec, mk128from32s(z32, src_elems, z32, z32));
14724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
14725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 1:  mask = 0xFF0F;
14726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(src_vec, mk128from32s(z32, z32, src_elems, z32));
14727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
14728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0:  mask = 0xFFF0;
14729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  assign(src_vec, mk128from32s(z32, z32, z32, src_elems));
14730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  break;
14731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: vassert(0);
14732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_OrV128, mkexpr(src_vec),
14736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128,
14737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getXMMReg( gregOfRexRM(pfx, modrm) ),
14738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkV128(mask) ) ) );
14739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 20 /r ib = PINSRB xmm1, r32/m8, imm8
14744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Extract byte from r32/m8 and insert into xmm1 */
14745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x20 ) {
14748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm8;
14750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp new8 = newTemp(Ity_I64);
14751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)(insn[3+1] & 0xF);
14756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( new8, binop(Iop_And64,
14757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_32Uto64,
14758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  getIReg32(eregOfRexRM(pfx,modrm))),
14759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU64(0xFF)));
14760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
14761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pinsrb $%d,%s,%s\n", imm8,
14762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameIReg32( eregOfRexRM(pfx, modrm) ),
14763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm8 = (Int)(insn[3+alen] & 0xF);
14767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( new8, unop(Iop_8Uto64, loadLE( Ity_I8, mkexpr(addr) )));
14768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
14769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pinsrb $%d,%s,%s\n",
14770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm8, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Create a V128 value which has the selected byte in the
14774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // specified lane, and zeroes everywhere else.
14775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp tmp128 = newTemp(Ity_V128);
14776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp halfshift = newTemp(Ity_I64);
14777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(halfshift, binop(Iop_Shl64,
14778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(new8), mkU8(8 * (imm8 & 7))));
14779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(imm8 >= 0 && imm8 <= 15);
14780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (imm8 < 8) {
14781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp128, binop(Iop_64HLtoV128, mkU64(0), mkexpr(halfshift)));
14782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(tmp128, binop(Iop_64HLtoV128, mkexpr(halfshift), mkU64(0)));
14784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UShort mask = ~(1 << imm8);
14787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_OrV128,
14790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(tmp128),
14791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_AndV128,
14792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               getXMMReg( gregOfRexRM(pfx, modrm) ),
14793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkV128(mask) ) ) );
14794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14798f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14799f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* 66 0F 3A 17 /r ib = EXTRACTPS reg/mem32, xmm2, imm8 Extract
14800f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      float from xmm reg and store in gen.reg or mem.  This is
14801f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      identical to PEXTRD, except that REX.W appears to be ignored.
14802f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   */
14803f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if ( have66noF2noF3( pfx )
14804f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root        && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
14805f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root        && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x17 ) {
14806f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14807f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Int imm8_10;
14808f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp xmm_vec   = newTemp(Ity_V128);
14809f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src_dword = newTemp(Ity_I32);
14810f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14811f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = insn[3];
14812f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign( xmm_vec, getXMMReg( gregOfRexRM(pfx,modrm) ) );
14813f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      breakup128to32s( xmm_vec, &t3, &t2, &t1, &t0 );
14814f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14815f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if ( epartIsReg( modrm ) ) {
14816f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm8_10 = (Int)(insn[3+1] & 3);
14817f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
14818f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 1 );
14819f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm8_10 = (Int)(insn[3+alen] & 3);
14820f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
14821f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14822f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      switch ( imm8_10 ) {
14823f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 0:  assign( src_dword, mkexpr(t0) ); break;
14824f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 1:  assign( src_dword, mkexpr(t1) ); break;
14825f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 2:  assign( src_dword, mkexpr(t2) ); break;
14826f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 3:  assign( src_dword, mkexpr(t3) ); break;
14827f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         default: vassert(0);
14828f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
14829f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14830f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if ( epartIsReg( modrm ) ) {
14831f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         putIReg32( eregOfRexRM(pfx,modrm), mkexpr(src_dword) );
14832f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+1+1;
14833f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "extractps $%d, %s,%s\n", imm8_10,
14834f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              nameXMMReg( gregOfRexRM(pfx, modrm) ),
14835f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              nameIReg32( eregOfRexRM(pfx, modrm) ) );
14836f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
14837f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         storeLE( mkexpr(addr), mkexpr(src_dword) );
14838f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+alen+1;
14839f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "extractps $%d, %s,%s\n",
14840f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              imm8_10, nameXMMReg( gregOfRexRM(pfx, modrm) ), dis_buf );
14841f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
14842f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14843f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
14844f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
14845f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14846f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
14847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 37 = PCMPGTQ
14848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      64x2 comparison (signed, presumably; the Intel docs don't say :-)
14849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
14850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx ) && sz == 2
14851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x37) {
14852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME: this needs an alignment check */
14853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G( vbi, pfx, delta+3,
14854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 "pcmpgtq", Iop_CmpGT64Sx2, False );
14855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 3D /r = PMAXSD xmm1, xmm2/m128
14859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Maximum of Packed Signed Double Word Integers (XMM)
14860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 38 39 /r = PMINSD xmm1, xmm2/m128
14861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Minimum of Packed Signed Double Word Integers (XMM) */
14862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx ) && sz == 2
14863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38
14864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (insn[2] == 0x3D || insn[2] == 0x39)) {
14865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME: this needs an alignment check */
14866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isMAX = insn[2] == 0x3D;
14867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G(
14868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+3,
14869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? "pmaxsd" : "pminsd",
14870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? Iop_Max32Sx4 : Iop_Min32Sx4,
14871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 False
14872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
14873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 3F /r = PMAXUD xmm1, xmm2/m128
14877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Maximum of Packed Unsigned Doubleword Integers (XMM)
14878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 38 3B /r = PMINUD xmm1, xmm2/m128
14879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Minimum of Packed Unsigned Doubleword Integers (XMM) */
14880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx ) && sz == 2
14881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38
14882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (insn[2] == 0x3F || insn[2] == 0x3B)) {
14883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME: this needs an alignment check */
14884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isMAX = insn[2] == 0x3F;
14885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G(
14886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+3,
14887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? "pmaxud" : "pminud",
14888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? Iop_Max32Ux4 : Iop_Min32Ux4,
14889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 False
14890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
14891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 3E /r = PMAXUW xmm1, xmm2/m128
14895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Maximum of Packed Unsigned Word Integers (XMM)
14896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 38 3A /r = PMINUW xmm1, xmm2/m128
14897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Minimum of Packed Unsigned Word Integers (XMM)
14898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
14899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx ) && sz == 2
14900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38
14901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (insn[2] == 0x3E || insn[2] == 0x3A)) {
14902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME: this needs an alignment check */
14903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isMAX = insn[2] == 0x3E;
14904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G(
14905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+3,
14906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? "pmaxuw" : "pminuw",
14907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? Iop_Max16Ux8 : Iop_Min16Ux8,
14908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 False
14909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
14910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 38 3C /r = PMAXSB xmm1, xmm2/m128
14914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      8Sx16 (signed) max
14915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 38 38 /r = PMINSB xmm1, xmm2/m128
14916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      8Sx16 (signed) min
14917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
14918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx ) && sz == 2
14919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38
14920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && (insn[2] == 0x3C || insn[2] == 0x38)) {
14921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* FIXME: this needs an alignment check */
14922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool isMAX = insn[2] == 0x3C;
14923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_SSEint_E_to_G(
14924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 vbi, pfx, delta+3,
14925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? "pmaxsb" : "pminsb",
14926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isMAX ? Iop_Max8Sx16 : Iop_Min8Sx16,
14927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 False
14928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
14929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 20 /r = PMOVSXBW xmm1, xmm2/m64
14933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Sign Extend from Byte to Word (XMM) */
14934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x20 ) {
14937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
14941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
14945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxbw %s,%s\n",
14946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
14951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
14952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
14953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxbw %s,%s\n",
14954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_SarN16x8,
14959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_ShlN16x8,
14960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop( Iop_InterleaveLO8x16,
14961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Const( IRConst_V128(0) ),
14962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(srcVec) ),
14963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(8) ),
14964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(8) ) );
14965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
14967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
14968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 21 /r = PMOVSXBD xmm1, xmm2/m32
14971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Sign Extend from Byte to DWord (XMM) */
14972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
14973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
14974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x21 ) {
14975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
14977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
14979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
14981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
14982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
14983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxbd %s,%s\n",
14984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
14985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) )  );
14986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
14987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
14988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
14989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
14990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
14991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxbd %s,%s\n",
14992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
14993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
14994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp zeroVec = newTemp(Ity_V128);
14996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
14997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
14999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_SarN32x4,
15000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_ShlN32x4,
15001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop( Iop_InterleaveLO8x16,
15002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(zeroVec),
15003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      binop( Iop_InterleaveLO8x16,
15004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(zeroVec),
15005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkexpr(srcVec) ) ),
15006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(24) ), mkU8(24) ) );
15007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 22 /r = PMOVSXBQ xmm1, xmm2/m16
15013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Sign Extend from Byte to QWord (XMM) */
15014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3(pfx)
15015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x22 ) {
15017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcBytes = newTemp(Ity_I16);
15021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcBytes, getXMMRegLane16( eregOfRexRM(pfx, modrm), 0 ) );
15024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxbq %s,%s\n",
15026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcBytes, loadLE( Ity_I16, mkexpr(addr) ) );
15031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxbq %s,%s\n",
15033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM( pfx, modrm ),
15037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_64HLtoV128,
15038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_8Sto64,
15039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop( Iop_16HIto8,
15040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                    mkexpr(srcBytes) ) ),
15041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_8Sto64,
15042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop( Iop_16to8, mkexpr(srcBytes) ) ) ) );
15043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 23 /r = PMOVSXWD xmm1, xmm2/m64
15049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Sign Extend from Word to DWord (XMM) */
15050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x23 ) {
15053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxwd %s,%s\n",
15062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
15068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxwd %s,%s\n",
15070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
15074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_SarN32x4,
15075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_ShlN32x4,
15076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop( Iop_InterleaveLO16x8,
15077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      IRExpr_Const( IRConst_V128(0) ),
15078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(srcVec) ),
15079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkU8(16) ),
15080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(16) ) );
15081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 24 /r = PMOVSXWQ xmm1, xmm2/m32
15087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Sign Extend from Word to QWord (XMM) */
15088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x24 ) {
15091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcBytes = newTemp(Ity_I32);
15095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
15097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcBytes, getXMMRegLane32( eregOfRexRM(pfx, modrm), 0 ) );
15098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxwq %s,%s\n",
15100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcBytes, loadLE( Ity_I32, mkexpr(addr) ) );
15105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxwq %s,%s\n",
15107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM( pfx, modrm ),
15111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_64HLtoV128,
15112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_16Sto64,
15113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop( Iop_32HIto16, mkexpr(srcBytes) ) ),
15114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_16Sto64,
15115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop( Iop_32to16, mkexpr(srcBytes) ) ) ) );
15116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 25 /r = PMOVSXDQ xmm1, xmm2/m64
15122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Sign Extend from Double Word to Quad Word (XMM) */
15123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x25 ) {
15126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcBytes = newTemp(Ity_I64);
15130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcBytes, getXMMRegLane64( eregOfRexRM(pfx, modrm), 0 ) );
15133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxdq %s,%s\n",
15135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcBytes, loadLE( Ity_I64, mkexpr(addr) ) );
15140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovsxdq %s,%s\n",
15142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
15146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_64HLtoV128,
15147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_32Sto64,
15148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop( Iop_64HIto32, mkexpr(srcBytes) ) ),
15149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        unop( Iop_32Sto64,
15150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop( Iop_64to32, mkexpr(srcBytes) ) ) ) );
15151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 30 /r = PMOVZXBW xmm1, xmm2/m64
15157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Zero Extend from Byte to Word (XMM) */
15158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3(pfx)
15159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x30 ) {
15161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxbw %s,%s\n",
15170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
15176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxbw %s,%s\n",
15178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
15182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_InterleaveLO8x16,
15183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Const( IRConst_V128(0) ), mkexpr(srcVec) ) );
15184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 31 /r = PMOVZXBD xmm1, xmm2/m32
15190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Zero Extend from Byte to DWord (XMM) */
15191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x31 ) {
15194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxbd %s,%s\n",
15203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
15209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxbd %s,%s\n",
15211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp zeroVec = newTemp(Ity_V128);
15215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
15216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM( pfx, modrm ),
15218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_InterleaveLO8x16,
15219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(zeroVec),
15220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_InterleaveLO8x16,
15221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(zeroVec), mkexpr(srcVec) ) ) );
15222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 32 /r = PMOVZXBQ xmm1, xmm2/m16
15228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Zero Extend from Byte to QWord (XMM) */
15229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x32 ) {
15232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxbq %s,%s\n",
15241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_32UtoV128,
15247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       unop( Iop_16Uto32, loadLE( Ity_I16, mkexpr(addr) ) ) ) );
15248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxbq %s,%s\n",
15250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp zeroVec = newTemp(Ity_V128);
15254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
15255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM( pfx, modrm ),
15257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_InterleaveLO8x16,
15258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(zeroVec),
15259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_InterleaveLO8x16,
15260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(zeroVec),
15261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               binop( Iop_InterleaveLO8x16,
15262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                      mkexpr(zeroVec), mkexpr(srcVec) ) ) ) );
15263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 33 /r = PMOVZXWD xmm1, xmm2/m64
15269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Zero Extend from Word to DWord (XMM) */
15270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x33 ) {
15273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxwd %s,%s\n",
15282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
15288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxwd %s,%s\n",
15290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
15294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_InterleaveLO16x8,
15295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Const( IRConst_V128(0) ),
15296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(srcVec) ) );
15297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 34 /r = PMOVZXWQ xmm1, xmm2/m32
15303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Zero Extend from Word to QWord (XMM) */
15304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x34 ) {
15307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg( modrm ) ) {
15313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxwq %s,%s\n",
15316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_32UtoV128, loadLE( Ity_I32, mkexpr(addr) ) ) );
15322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxwq %s,%s\n",
15324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp zeroVec = newTemp( Ity_V128 );
15328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( zeroVec, IRExpr_Const( IRConst_V128(0) ) );
15329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM( pfx, modrm ),
15331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_InterleaveLO16x8,
15332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(zeroVec),
15333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop( Iop_InterleaveLO16x8,
15334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               mkexpr(zeroVec), mkexpr(srcVec) ) ) );
15335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 35 /r = PMOVZXDQ xmm1, xmm2/m64
15341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Packed Move with Zero Extend from DWord to QWord (XMM) */
15342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x35 ) {
15345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp srcVec = newTemp(Ity_V128);
15349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxdq %s,%s\n",
15354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( srcVec,
15359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 unop( Iop_64UtoV128, loadLE( Ity_I64, mkexpr(addr) ) ) );
15360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmovzxdq %s,%s\n",
15362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
15366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_InterleaveLO32x4,
15367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        IRExpr_Const( IRConst_V128(0) ),
15368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(srcVec) ) );
15369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 40 /r = PMULLD xmm1, xmm2/m128
15375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      32x4 integer multiply from xmm2/m128 to xmm1 */
15376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if ( have66noF2noF3( pfx )
15377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && sz == 2
15378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x40 ) {
15379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argL = newTemp(Ity_V128);
15383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp argR = newTemp(Ity_V128);
15384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, getXMMReg( eregOfRexRM(pfx, modrm) ) );
15387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmulld %s,%s\n",
15389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
15394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( argL, loadLE( Ity_V128, mkexpr(addr) ));
15395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "pmulld %s,%s\n",
15397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(argR, getXMMReg( gregOfRexRM(pfx, modrm) ));
15401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putXMMReg( gregOfRexRM(pfx, modrm),
15403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop( Iop_Mul32x4, mkexpr(argL), mkexpr(argR)) );
15404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F B8  = POPCNT{W,L,Q}
15410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Count the number of 1 bits in a register
15411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    */
15412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3noF2(pfx) /* so both 66 and 48 are possibilities */
15413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xB8) {
15414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4 || sz == 8);
15415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*IRType*/ ty  = szToITy(sz);
15416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp     src = newTemp(ty);
15417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
15418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
15419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, getIRegE(sz, pfx, modrm));
15420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
15421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("popcnt%c %s, %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm),
15422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIRegG(sz, pfx, modrm));
15423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0);
15425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, loadLE(ty, mkexpr(addr)));
15426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
15427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("popcnt%c %s, %s\n", nameISize(sz), dis_buf,
15428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIRegG(sz, pfx, modrm));
15429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp result = gen_POPCOUNT(ty, src);
15432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(sz, pfx, modrm, mkexpr(result));
15433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Update flags.  This is pretty lame .. perhaps can do better
15435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // if this turns out to be performance critical.
15436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // O S A C P are cleared.  Z is set if SRC == 0.
15437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
15438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
15440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1,
15441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Shl64,
15442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_1Uto64,
15443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_CmpEQ64,
15444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             widenUto64(mkexpr(src)),
15445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU64(0))),
15446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU8(AMD64G_CC_SHIFT_Z))));
15447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 0B /r ib = ROUNDSD imm8, xmm2/m64, xmm1
15453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 3A 0A /r ib = ROUNDSS imm8, xmm2/m32, xmm1
15454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
15455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
15456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 2
15457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A
15458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] == 0x0B || insn[2] == 0x0A)) {
15459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool   isD = insn[2] == 0x0B;
15461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src = newTemp(isD ? Ity_F64 : Ity_F32);
15462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = newTemp(isD ? Ity_F64 : Ity_F32);
15463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int    imm = 0;
15464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
15468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src,
15469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 isD ? getXMMRegLane64F( eregOfRexRM(pfx, modrm), 0 )
15470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     : getXMMRegLane32F( eregOfRexRM(pfx, modrm), 0 ) );
15471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+1];
15472b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (imm & ~15) goto decode_failure;
15473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
15474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "rounds%c $%d,%s,%s\n",
15475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              isD ? 'd' : 's',
15476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm, nameXMMReg( eregOfRexRM(pfx, modrm) ),
15477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( src, loadLE( isD ? Ity_F64 : Ity_F32, mkexpr(addr) ));
15481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+alen];
15482b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (imm & ~15) goto decode_failure;
15483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
15484f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "rounds%c $%d,%s,%s\n",
15485f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              isD ? 'd' : 's',
15486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              imm, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
15490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         that encoding is the same as the encoding for IRRoundingMode,
15491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         we can use that value directly in the IR as a rounding
15492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mode. */
15493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res, binop(isD ? Iop_RoundF64toInt : Iop_RoundF32toInt,
15494f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        (imm & 4) ? get_sse_roundingmode()
15495f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                  : mkU32(imm & 3),
15496f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                        mkexpr(src)) );
15497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isD)
15499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane64F( gregOfRexRM(pfx, modrm), 0, mkexpr(res) );
15500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
15501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putXMMRegLane32F( gregOfRexRM(pfx, modrm), 0, mkexpr(res) );
15502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15506f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15507f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* 66 0F 3A 09 /r ib = ROUNDPD imm8, xmm2/m128, xmm1 */
15508f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (have66noF2noF3(pfx)
15509f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && sz == 2
15510f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x09) {
15511f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15512f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src0 = newTemp(Ity_F64);
15513f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src1 = newTemp(Ity_F64);
15514f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp res0 = newTemp(Ity_F64);
15515f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp res1 = newTemp(Ity_F64);
15516f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp rm   = newTemp(Ity_I32);
15517f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Int    imm  = 0;
15518f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15519f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = insn[3];
15520f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15521f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (epartIsReg(modrm)) {
15522f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src0,
15523f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 getXMMRegLane64F( eregOfRexRM(pfx, modrm), 0 ) );
15524f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src1,
15525f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 getXMMRegLane64F( eregOfRexRM(pfx, modrm), 1 ) );
15526f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm = insn[3+1];
15527b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (imm & ~15) goto decode_failure;
15528f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+1+1;
15529f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "roundpd $%d,%s,%s\n",
15530f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              imm, nameXMMReg( eregOfRexRM(pfx, modrm) ),
15531f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                   nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15532f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
15533f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15534f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         gen_SEGV_if_not_16_aligned(addr);
15535f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src0, loadLE(Ity_F64,
15536f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Add64, mkexpr(addr), mkU64(0) )));
15537f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src1, loadLE(Ity_F64,
15538f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Add64, mkexpr(addr), mkU64(8) )));
15539f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm = insn[3+alen];
15540b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (imm & ~15) goto decode_failure;
15541f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+alen+1;
15542f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "roundpd $%d,%s,%s\n",
15543f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              imm, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15544f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
15545f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15546f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
15547f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         that encoding is the same as the encoding for IRRoundingMode,
15548f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         we can use that value directly in the IR as a rounding
15549f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         mode. */
15550f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(rm, (imm & 4) ? get_sse_roundingmode() : mkU32(imm & 3));
15551f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15552f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(res0, binop(Iop_RoundF64toInt, mkexpr(rm), mkexpr(src0)) );
15553f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(res1, binop(Iop_RoundF64toInt, mkexpr(rm), mkexpr(src1)) );
15554f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15555f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMRegLane64F( gregOfRexRM(pfx, modrm), 0, mkexpr(res0) );
15556f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMRegLane64F( gregOfRexRM(pfx, modrm), 1, mkexpr(res1) );
15557f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15558f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
15559f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
15560f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15561f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15562f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* 66 0F 3A 08 /r ib = ROUNDPS imm8, xmm2/m128, xmm1 */
15563f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (have66noF2noF3(pfx)
15564f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && sz == 2
15565f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && insn[0] == 0x0F && insn[1] == 0x3A && insn[2] == 0x08) {
15566f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15567f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src0 = newTemp(Ity_F32);
15568f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src1 = newTemp(Ity_F32);
15569f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src2 = newTemp(Ity_F32);
15570f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp src3 = newTemp(Ity_F32);
15571f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp res0 = newTemp(Ity_F32);
15572f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp res1 = newTemp(Ity_F32);
15573f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp res2 = newTemp(Ity_F32);
15574f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp res3 = newTemp(Ity_F32);
15575f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp rm   = newTemp(Ity_I32);
15576f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Int    imm  = 0;
15577f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15578f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = insn[3];
15579f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15580f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (epartIsReg(modrm)) {
15581f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src0,
15582f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 getXMMRegLane32F( eregOfRexRM(pfx, modrm), 0 ) );
15583f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src1,
15584f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 getXMMRegLane32F( eregOfRexRM(pfx, modrm), 1 ) );
15585f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src2,
15586f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 getXMMRegLane32F( eregOfRexRM(pfx, modrm), 2 ) );
15587f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src3,
15588f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 getXMMRegLane32F( eregOfRexRM(pfx, modrm), 3 ) );
15589f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm = insn[3+1];
15590b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (imm & ~15) goto decode_failure;
15591f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+1+1;
15592f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "roundps $%d,%s,%s\n",
15593f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              imm, nameXMMReg( eregOfRexRM(pfx, modrm) ),
15594f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                   nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15595f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
15596f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15597f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         gen_SEGV_if_not_16_aligned(addr);
15598f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src0, loadLE(Ity_F32,
15599f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Add64, mkexpr(addr), mkU64(0) )));
15600f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src1, loadLE(Ity_F32,
15601f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Add64, mkexpr(addr), mkU64(4) )));
15602f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src2, loadLE(Ity_F32,
15603f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Add64, mkexpr(addr), mkU64(8) )));
15604f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign( src3, loadLE(Ity_F32,
15605f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                              binop(Iop_Add64, mkexpr(addr), mkU64(12) )));
15606f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         imm = insn[3+alen];
15607b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         if (imm & ~15) goto decode_failure;
15608f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+alen+1;
15609f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "roundps $%d,%s,%s\n",
15610f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              imm, dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15611f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
15612f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15613f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* (imm & 3) contains an Intel-encoded rounding mode.  Because
15614f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         that encoding is the same as the encoding for IRRoundingMode,
15615f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         we can use that value directly in the IR as a rounding
15616f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         mode. */
15617f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(rm, (imm & 4) ? get_sse_roundingmode() : mkU32(imm & 3));
15618f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15619f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(res0, binop(Iop_RoundF32toInt, mkexpr(rm), mkexpr(src0)) );
15620f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(res1, binop(Iop_RoundF32toInt, mkexpr(rm), mkexpr(src1)) );
15621f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(res2, binop(Iop_RoundF32toInt, mkexpr(rm), mkexpr(src2)) );
15622f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(res3, binop(Iop_RoundF32toInt, mkexpr(rm), mkexpr(src3)) );
15623f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15624f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMRegLane32F( gregOfRexRM(pfx, modrm), 0, mkexpr(res0) );
15625f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMRegLane32F( gregOfRexRM(pfx, modrm), 1, mkexpr(res1) );
15626f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMRegLane32F( gregOfRexRM(pfx, modrm), 2, mkexpr(res2) );
15627f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMRegLane32F( gregOfRexRM(pfx, modrm), 3, mkexpr(res3) );
15628f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15629f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
15630f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
15631f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15632f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* F3 0F BD -- LZCNT (count leading zeroes.  An AMD extension,
15634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      which we can only decode if we're sure this is an AMD cpu that
15635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      supports LZCNT, since otherwise it's BSR, which behaves
15636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      differently. */
15637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (haveF3noF2(pfx) /* so both 66 and 48 are possibilities */
15638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0xBD
15639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && 0 != (archinfo->hwcaps & VEX_HWCAPS_AMD64_LZCNT)) {
15640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4 || sz == 8);
15641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /*IRType*/ ty  = szToITy(sz);
15642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp     src = newTemp(ty);
15643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[2];
15644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
15645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, getIRegE(sz, pfx, modrm));
15646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+1;
15647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lzcnt%c %s, %s\n", nameISize(sz), nameIRegE(sz, pfx, modrm),
15648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIRegG(sz, pfx, modrm));
15649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+2, dis_buf, 0);
15651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(src, loadLE(ty, mkexpr(addr)));
15652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 2+alen;
15653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("lzcnt%c %s, %s\n", nameISize(sz), dis_buf,
15654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameIRegG(sz, pfx, modrm));
15655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res = gen_LZCNT(ty, src);
15658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG(sz, pfx, modrm, mkexpr(res));
15659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // Update flags.  This is pretty lame .. perhaps can do better
15661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // if this turns out to be performance critical.
15662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // O S A P are cleared.  Z is set if RESULT == 0.
15663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      // C is set if SRC is zero.
15664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp src64 = newTemp(Ity_I64);
15665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp res64 = newTemp(Ity_I64);
15666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(src64, widenUto64(mkexpr(src)));
15667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(res64, widenUto64(mkexpr(res)));
15668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp oszacp = newTemp(Ity_I64);
15670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
15671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         oszacp,
15672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         binop(Iop_Or64,
15673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl64,
15674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto64,
15675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_CmpEQ64, mkexpr(res64), mkU64(0))),
15676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(AMD64G_CC_SHIFT_Z)),
15677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Shl64,
15678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     unop(Iop_1Uto64,
15679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_CmpEQ64, mkexpr(src64), mkU64(0))),
15680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mkU8(AMD64G_CC_SHIFT_C))
15681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
15682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
15683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
15685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
15687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(oszacp) ));
15688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0F 3A 63 /r ib = PCMPISTRI imm8, xmm2/m128, xmm1
15693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 3A 62 /r ib = PCMPISTRM imm8, xmm2/m128, xmm1
15694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 3A 61 /r ib = PCMPESTRI imm8, xmm2/m128, xmm1
15695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      66 0F 3A 60 /r ib = PCMPESTRM imm8, xmm2/m128, xmm1
15696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      (selected special cases that actually occur in glibc,
15697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       not by any means a complete implementation.)
15698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
15699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (have66noF2noF3(pfx)
15700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && sz == 2
15701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x3A
15702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && (insn[2] >= 0x60 && insn[2] <= 0x63)) {
15703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt  isISTRx = insn[2] & 2;
15705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt  isxSTRM = (insn[2] & 1) ^ 1;
15706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt  regNoL = 0;
15707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt  regNoR = 0;
15708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar imm    = 0;
15709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is a nasty kludge.  We need to pass 2 x V128 to the
15711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper (which is clean).  Since we can't do that, use a dirty
15712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper to compute the results directly from the XMM regs in
15713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         the guest state.  That means for the memory case, we need to
15714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         move the left operand into a pseudo-register (XMM16, let's
15715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         call it). */
15716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
15718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regNoL = eregOfRexRM(pfx, modrm);
15719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regNoR = gregOfRexRM(pfx, modrm);
15720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+1];
15721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1+1;
15722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regNoL = 16; /* use XMM16 as an intermediary */
15724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         regNoR = gregOfRexRM(pfx, modrm);
15725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* No alignment check; I guess that makes sense, given that
15727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            these insns are for dealing with C style strings. */
15728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_XMM16, loadLE(Ity_V128, mkexpr(addr)) ));
15729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         imm = insn[3+alen];
15730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen+1;
15731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now we know the XMM reg numbers for the operands, and the
15734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         immediate byte.  Is it one we can actually handle? Throw out
15735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         any cases for which the helper function has not been
15736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         verified. */
15737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (imm) {
15738f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 0x00:
15739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0x02: case 0x08: case 0x0A: case 0x0C: case 0x12:
15740b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         case 0x1A: case 0x38: case 0x3A: case 0x44: case 0x4A:
15741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
15742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
15743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
15744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Who ya gonna call?  Presumably not Ghostbusters. */
15747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      void*  fn = &amd64g_dirtyhelper_PCMPxSTRx;
15748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* nm = "amd64g_dirtyhelper_PCMPxSTRx";
15749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Round up the arguments.  Note that this is a kludge -- the
15751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         use of mkU64 rather than mkIRExpr_HWord implies the
15752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assumption that the host's word size is 64-bit. */
15753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt gstOffL = regNoL == 16 ? OFFB_XMM16 : xmmGuestRegOffset(regNoL);
15754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UInt gstOffR = xmmGuestRegOffset(regNoR);
15755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr*  opc4_and_imm = mkU64((insn[2] << 8) | (imm & 0xFF));
15757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr*  gstOffLe     = mkU64(gstOffL);
15758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr*  gstOffRe     = mkU64(gstOffR);
15759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr*  edxIN        = isISTRx ? mkU64(0) : getIRegRDX(8);
15760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr*  eaxIN        = isISTRx ? mkU64(0) : getIRegRAX(8);
15761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr** args
15762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         = mkIRExprVec_5( opc4_and_imm, gstOffLe, gstOffRe, edxIN, eaxIN );
15763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp   resT = newTemp(Ity_I64);
15765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d    = unsafeIRDirty_1_N( resT, 0/*regparms*/, nm, fn, args );
15766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It's not really a dirty call, but we can't use the clean
15767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         helper mechanism here for the very lame reason that we can't
15768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         pass 2 x V128s by value to a helper, nor get one back.  Hence
15769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         this roundabout scheme. */
15770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->needsBBP = True;
15771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->nFxState = 2;
15772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].fx     = Ifx_Read;
15773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].offset = gstOffL;
15774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[0].size   = sizeof(U128);
15775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].fx     = Ifx_Read;
15776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].offset = gstOffR;
15777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d->fxState[1].size   = sizeof(U128);
15778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (isxSTRM) {
15779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Declare that the helper writes XMM0. */
15780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->nFxState = 3;
15781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].fx     = Ifx_Write;
15782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].offset = xmmGuestRegOffset(0);
15783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].size   = sizeof(U128);
15784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
15787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now resT[15:0] holds the new OSZACP values, so the condition
15789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         codes must be updated. And for a xSTRI case, resT[31:16]
15790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         holds the new ECX value, so stash that too. */
15791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!isxSTRM) {
15792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64(R_RCX, binop(Iop_And64,
15793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shr64, mkexpr(resT), mkU8(16)),
15794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU64(0xFFFF)));
15795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
15798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_CC_DEP1,
15799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_And64, mkexpr(resT), mkU64(0xFFFF))
15800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ));
15801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
15802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
15804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (regNoL == 16) {
15806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pcmp%cstr%c $%x,%s,%s\n",
15807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isISTRx ? 'i' : 'e', isxSTRM ? 'm' : 'i',
15808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (UInt)imm, dis_buf, nameXMMReg(regNoR));
15809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("pcmp%cstr%c $%x,%s,%s\n",
15811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             isISTRx ? 'i' : 'e', isxSTRM ? 'm' : 'i',
15812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (UInt)imm, nameXMMReg(regNoL), nameXMMReg(regNoR));
15813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* 66 0f 38 17 /r = PTEST xmm1, xmm2/m128
15820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Logical compare (set ZF and CF from AND/ANDN of the operands) */
15821b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (have66noF2noF3( pfx )
15822b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       && (sz == 2 || /* ignore redundant REX.W */ sz == 8)
15823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x17) {
15824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = insn[3];
15825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp vecE = newTemp(Ity_V128);
15826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp vecG = newTemp(Ity_V128);
15827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( epartIsReg(modrm) ) {
15829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(vecE, getXMMReg(eregOfRexRM(pfx, modrm)));
15830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+1;
15831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "ptest %s,%s\n",
15832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
15835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         gen_SEGV_if_not_16_aligned( addr );
15837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(vecE, loadLE( Ity_V128, mkexpr(addr) ));
15838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 3+alen;
15839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP( "ptest %s,%s\n",
15840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
15842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(vecG, getXMMReg(gregOfRexRM(pfx, modrm)));
15844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set Z=1 iff (vecE & vecG) == 0
15846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Set C=1 iff (vecE & not vecG) == 0
15847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
15848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* andV, andnV:  vecE & vecG,  vecE and not(vecG) */
15850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp andV  = newTemp(Ity_V128);
15851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp andnV = newTemp(Ity_V128);
15852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(andV,  binop(Iop_AndV128, mkexpr(vecE), mkexpr(vecG)));
15853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(andnV, binop(Iop_AndV128,
15854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkexpr(vecE),
15855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_XorV128, mkexpr(vecG),
15856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                             mkV128(0xFFFF))));
15857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* The same, but reduced to 64-bit values, by or-ing the top
15859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and bottom 64-bits together.  It relies on this trick:
15860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          InterleaveLO64x2([a,b],[c,d]) == [b,d]    hence
15862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          InterleaveLO64x2([a,b],[a,b]) == [b,b]    and similarly
15864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          InterleaveHI64x2([a,b],[a,b]) == [a,a]
15865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          and so the OR of the above 2 exprs produces
15867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          [a OR b, a OR b], from which we simply take the lower half.
15868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
15869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp and64  = newTemp(Ity_I64);
15870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp andn64 = newTemp(Ity_I64);
15871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
15873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         and64,
15874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_V128to64,
15875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_OrV128,
15876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_InterleaveLO64x2, mkexpr(andV), mkexpr(andV)),
15877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_InterleaveHI64x2, mkexpr(andV), mkexpr(andV))
15878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
15879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         )
15880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
15881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(
15883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         andn64,
15884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         unop(Iop_V128to64,
15885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              binop(Iop_OrV128,
15886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_InterleaveLO64x2, mkexpr(andnV), mkexpr(andnV)),
15887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_InterleaveHI64x2, mkexpr(andnV), mkexpr(andnV))
15888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              )
15889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          )
15890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       );
15891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Now convert and64, andn64 to all-zeroes or all-1s, so we can
15893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         slice out the Z and C bits conveniently.  We use the standard
15894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         trick all-zeroes -> all-zeroes, anything-else -> all-ones
15895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         done by "(x | -x) >>s (word-size - 1)".
15896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      */
15897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp z64 = newTemp(Ity_I64);
15898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp c64 = newTemp(Ity_I64);
15899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(z64,
15900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             unop(Iop_Not64,
15901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sar64,
15902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Or64,
15903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Sub64, mkU64(0), mkexpr(and64)),
15904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(and64)
15905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ),
15906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(63)))
15907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
15908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(c64,
15910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             unop(Iop_Not64,
15911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Sar64,
15912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_Or64,
15913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Sub64, mkU64(0), mkexpr(andn64)),
15914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(andn64)
15915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        ),
15916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(63)))
15917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
15918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And finally, slice out the Z and C flags and set the flags
15920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         thunk to COPY for them.  OSAP are set to zero. */
15921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRTemp newOSZACP = newTemp(Ity_I64);
15922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(newOSZACP,
15923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             binop(Iop_Or64,
15924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And64, mkexpr(z64), mkU64(AMD64G_CC_MASK_Z)),
15925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   binop(Iop_And64, mkexpr(c64), mkU64(AMD64G_CC_MASK_C))
15926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             )
15927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      );
15928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(newOSZACP)));
15930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
15931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
15932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
15933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_success;
15935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
15936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15937f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* 66 0F 38 15 /r = BLENDVPD xmm1, xmm2/m128  (double gran)
15938f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      66 0F 38 14 /r = BLENDVPS xmm1, xmm2/m128  (float gran)
15939f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      66 0F 38 10 /r = PBLENDVB xmm1, xmm2/m128  (byte gran)
15940f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      Blend at various granularities, with XMM0 (implicit operand)
15941f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      providing the controlling mask.
15942f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   */
15943f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (have66noF2noF3(pfx) && sz == 2
15944f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && insn[0] == 0x0F && insn[1] == 0x38
15945f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && (insn[2] == 0x15 || insn[2] == 0x14 || insn[2] == 0x10)) {
15946f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = insn[3];
15947f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15948f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      HChar* nm    = NULL;
15949f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      UInt   gran  = 0;
15950f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IROp   opSAR = Iop_INVALID;
15951f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      switch (insn[2]) {
15952f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 0x15:
15953f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            nm = "blendvpd"; gran = 8; opSAR = Iop_SarN64x2;
15954f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            break;
15955f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 0x14:
15956f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            nm = "blendvps"; gran = 4; opSAR = Iop_SarN32x4;
15957f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            break;
15958f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 0x10:
15959f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            nm = "pblendvb"; gran = 1; opSAR = Iop_SarN8x16;
15960f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            break;
15961f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
15962f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      vassert(nm);
15963f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15964f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp vecE = newTemp(Ity_V128);
15965f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp vecG = newTemp(Ity_V128);
15966f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp vec0 = newTemp(Ity_V128);
15967f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15968f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if ( epartIsReg(modrm) ) {
15969f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign(vecE, getXMMReg(eregOfRexRM(pfx, modrm)));
15970f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+1;
15971f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "%s %s,%s\n", nm,
15972f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              nameXMMReg( eregOfRexRM(pfx, modrm) ),
15973f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15974f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
15975f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
15976f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         gen_SEGV_if_not_16_aligned( addr );
15977f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign(vecE, loadLE( Ity_V128, mkexpr(addr) ));
15978f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+alen;
15979f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP( "%s %s,%s\n", nm,
15980f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
15981f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
15982f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15983f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(vecG, getXMMReg(gregOfRexRM(pfx, modrm)));
15984f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(vec0, getXMMReg(0));
15985f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15986f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Now the tricky bit is to convert vec0 into a suitable mask,
15987f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         by copying the most significant bit of each lane into all
15988f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         positions in the lane. */
15989f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp sh = newTemp(Ity_I8);
15990f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(sh, mkU8(8 * gran - 1));
15991f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15992f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp mask = newTemp(Ity_V128);
15993f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(mask, binop(opSAR, mkexpr(vec0), mkexpr(sh)));
15994f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15995f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp notmask = newTemp(Ity_V128);
15996f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(notmask, unop(Iop_NotV128, mkexpr(mask)));
15997f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
15998f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRExpr* res = binop(Iop_OrV128,
15999f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                          binop(Iop_AndV128, mkexpr(vecE), mkexpr(mask)),
16000f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                          binop(Iop_AndV128, mkexpr(vecG), mkexpr(notmask)));
16001f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putXMMReg(gregOfRexRM(pfx, modrm), res);
16002f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16003f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
16004f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
16005f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16006f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   /* F2 0F 38 F0 /r = CRC32 r/m8, r32 (REX.W ok, 66 not ok)
16007f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      F2 0F 38 F1 /r = CRC32 r/m{16,32,64}, r32
16008f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      The decoding on this is a bit unusual.
16009f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   */
16010f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   if (haveF2noF3(pfx)
16011f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && insn[0] == 0x0F && insn[1] == 0x38
16012f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root       && (insn[2] == 0xF1
16013f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root           || (insn[2] == 0xF0 && !have66(pfx)))) {
16014f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      modrm = insn[3];
16015f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16016f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (insn[2] == 0xF0)
16017f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         sz = 1;
16018f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      else
16019f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         vassert(sz == 2 || sz == 4 || sz == 8);
16020f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16021f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRType tyE = szToITy(sz);
16022f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp valE = newTemp(tyE);
16023f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16024f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (epartIsReg(modrm)) {
16025f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign(valE, getIRegE(sz, pfx, modrm));
16026f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+1;
16027f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP("crc32b %s,%s\n", nameIRegE(sz, pfx, modrm),
16028f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             nameIRegG(1==getRexW(pfx) ? 8 : 4 ,pfx, modrm));
16029f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
16030f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
16031f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         assign(valE, loadLE(tyE, mkexpr(addr)));
16032f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         delta += 3+alen;
16033f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         DIP("crc32b %s,%s\n", dis_buf,
16034f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             nameIRegG(1==getRexW(pfx) ? 8 : 4 ,pfx, modrm));
16035f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
16036f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16037f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* Somewhat funny getting/putting of the crc32 value, in order
16038f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         to ensure that it turns into 64-bit gets and puts.  However,
16039f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         mask off the upper 32 bits so as to not get memcheck false
16040f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         +ves around the helper call. */
16041f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp valG0 = newTemp(Ity_I64);
16042f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(valG0, binop(Iop_And64, getIRegG(8, pfx, modrm),
16043f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                          mkU64(0xFFFFFFFF)));
16044f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16045f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      HChar* nm = NULL;
16046f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      void* fn = NULL;
16047f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      switch (sz) {
16048f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 1: nm = "amd64g_calc_crc32b";
16049f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 fn = &amd64g_calc_crc32b; break;
16050f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 2: nm = "amd64g_calc_crc32w";
16051f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 fn = &amd64g_calc_crc32w; break;
16052f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 4: nm = "amd64g_calc_crc32l";
16053f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 fn = &amd64g_calc_crc32l; break;
16054f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         case 8: nm = "amd64g_calc_crc32q";
16055f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                 fn = &amd64g_calc_crc32q; break;
16056f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
16057f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      vassert(nm && fn);
16058f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      IRTemp valG1 = newTemp(Ity_I64);
16059f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      assign(valG1,
16060f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root             mkIRExprCCall(Ity_I64, 0/*regparm*/, nm, fn,
16061f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                           mkIRExprVec_2(mkexpr(valG0),
16062f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                         widenUto64(mkexpr(valE)))));
16063f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root
16064f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      putIRegG(4, pfx, modrm, unop(Iop_64to32, mkexpr(valG1)));
16065f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      goto decode_success;
16066f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root   }
16067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16068b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* 66 0f 38 2B /r = PACKUSDW xmm1, xmm2/m128
16069b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      2x 32x4 S->U saturating narrow from xmm2/m128 to xmm1 */
16070b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if ( have66noF2noF3( pfx )
16071b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        && sz == 2
16072b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x2B ) {
16073b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16074b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      modrm = insn[3];
16075b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16076b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp argL = newTemp(Ity_V128);
16077b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp argR = newTemp(Ity_V128);
16078b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16079b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if ( epartIsReg(modrm) ) {
16080b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign( argL, getXMMReg( eregOfRexRM(pfx, modrm) ) );
16081b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         delta += 3+1;
16082b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP( "packusdw %s,%s\n",
16083b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              nameXMMReg( eregOfRexRM(pfx, modrm) ),
16084b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              nameXMMReg( gregOfRexRM(pfx, modrm) ) );
16085b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else {
16086b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         addr = disAMode( &alen, vbi, pfx, delta+3, dis_buf, 0 );
16087b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         gen_SEGV_if_not_16_aligned( addr );
16088b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign( argL, loadLE( Ity_V128, mkexpr(addr) ));
16089b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         delta += 3+alen;
16090b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP( "packusdw %s,%s\n",
16091b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              dis_buf, nameXMMReg( gregOfRexRM(pfx, modrm) ) );
16092b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
16093b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16094b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign(argR, getXMMReg( gregOfRexRM(pfx, modrm) ));
16095b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16096b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putXMMReg( gregOfRexRM(pfx, modrm),
16097b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                 binop( Iop_QNarrowBin32Sto16Ux8,
16098b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                        mkexpr(argL), mkexpr(argR)) );
16099b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16100b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto decode_success;
16101b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
16102b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16103b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* 66 0F 38 28 = PMULUDQ -- signed widening multiply of 32-lanes 0 x
16104b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      0 to form lower 64-bit half and lanes 2 x 2 to form upper 64-bit
16105b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      half */
16106b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* This is a really poor translation -- could be improved if
16107b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      performance critical.  It's a copy-paste of PMULDQ, too. */
16108b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if (have66noF2noF3(pfx) && sz == 2
16109b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov       && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x28) {
16110b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp sV, dV;
16111b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
16112b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      sV = newTemp(Ity_V128);
16113b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      dV = newTemp(Ity_V128);
16114b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
16115b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      t1 = newTemp(Ity_I64);
16116b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      t0 = newTemp(Ity_I64);
16117b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      modrm = insn[3];
16118b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) );
16119b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16120b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (epartIsReg(modrm)) {
16121b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) );
16122b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         delta += 3+1;
16123b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("pmuldq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)),
16124b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                               nameXMMReg(gregOfRexRM(pfx,modrm)));
16125b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      } else {
16126b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         addr = disAMode ( &alen, vbi, pfx, delta+3, dis_buf, 0 );
16127b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
16128b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         delta += 3+alen;
16129b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         DIP("pmuldq %s,%s\n", dis_buf,
16130b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                               nameXMMReg(gregOfRexRM(pfx,modrm)));
16131b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
16132b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16133b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      breakup128to32s( dV, &d3, &d2, &d1, &d0 );
16134b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
16135b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16136b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( t0, binop( Iop_MullS32, mkexpr(d0), mkexpr(s0)) );
16137b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putXMMRegLane64( gregOfRexRM(pfx,modrm), 0, mkexpr(t0) );
16138b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign( t1, binop( Iop_MullS32, mkexpr(d2), mkexpr(s2)) );
16139b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putXMMRegLane64( gregOfRexRM(pfx,modrm), 1, mkexpr(t1) );
16140b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto decode_success;
16141b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
16142b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16143b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   /* 66 0F 38 29 = PCMPEQQ
16144b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      64x2 equality comparison
16145b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   */
16146b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   if ( have66noF2noF3( pfx ) && sz == 2
16147b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov        && insn[0] == 0x0F && insn[1] == 0x38 && insn[2] == 0x29) {
16148b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* FIXME: this needs an alignment check */
16149b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      delta = dis_SSEint_E_to_G( vbi, pfx, delta+3,
16150b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov                                 "pcmpeqq", Iop_CmpEQ64x2, False );
16151b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      goto decode_success;
16152b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   }
16153b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
16155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* --- end of the SSE4 decoder                      --- */
16156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ---------------------------------------------------- */
16157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /*after_sse_decoders:*/
16159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Get the primary opcode. */
16161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   opc = getUChar(delta); delta++;
16162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We get here if the current insn isn't SSE, or this CPU doesn't
16164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      support SSE. */
16165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   switch (opc) {
16167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Control flow --------------- */
16169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC2: /* RET imm16 */
16171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (have66orF2orF3(pfx)) goto decode_failure;
16172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getUDisp16(delta);
16173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 2;
16174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_ret(vbi, d64);
16175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext = Dis_StopHere;
16176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("ret %lld\n", d64);
16177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC3: /* RET */
16180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (have66orF2(pfx)) goto decode_failure;
16181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* F3 is acceptable on AMD. */
16182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dis_ret(vbi, 0);
16183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext = Dis_StopHere;
16184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
16185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE8: /* CALL J4 */
16188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getSDisp32(delta); delta += 4;
16190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 += (guest_RIP_bbstart+delta);
16191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
16192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
16193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
16194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, mkexpr(t1));
16195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
16196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
16197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, mkU64((Addr64)d64));
16198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      make_redzone_AbiHint(vbi, t1, t2/*nia*/, "call-d32");
16199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
16200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* follow into the call target. */
16201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
16202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = d64;
16203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmp_lit(Ijk_Call,d64);
16205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
16206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("call 0x%llx\n",d64);
16208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0xC8: /* ENTER */
16211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       d32 = getUDisp16(eip); eip += 2;
16212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       abyte = getUChar(delta); delta++;
16213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
16214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       vg_assert(sz == 4);
16215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       vg_assert(abyte == 0);
16216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
16217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       t1 = newTemp(cb); t2 = newTemp(cb);
16218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET,   sz, ArchReg, R_EBP, TempReg, t1);
16219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET,    4, ArchReg, R_ESP, TempReg, t2);
16220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
16221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uLiteral(cb, sz);
16222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
16223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, STORE,  4, TempReg, t1,    TempReg, t2);
16224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_EBP);
16225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       if (d32) {
16226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          uInstr2(cb, SUB,    4, Literal, 0,     TempReg, t2);
16227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          uLiteral(cb, d32);
16228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          uInstr2(cb, PUT,    4, TempReg, t2,    ArchReg, R_ESP);
16229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       }
16230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       DIP("enter 0x%x, 0x%x", d32, abyte);
16231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       break;
16232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16233b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov   case 0xC8: /* ENTER */
16234b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Same comments re operand size as for LEAVE below apply.
16235b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         Also, only handles the case "enter $imm16, $0"; other cases
16236b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         for the second operand (nesting depth) are not handled. */
16237b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (sz != 4)
16238b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto decode_failure;
16239b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      d64 = getUDisp16(delta);
16240b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      delta += 2;
16241b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      vassert(d64 >= 0 && d64 <= 0xFFFF);
16242b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (getUChar(delta) != 0)
16243b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         goto decode_failure;
16244b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      delta++;
16245b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      /* Intel docs seem to suggest:
16246b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           push rbp
16247b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           temp = rsp
16248b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           rbp = temp
16249b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov           rsp = rsp - imm16
16250b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      */
16251b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      t1 = newTemp(Ity_I64);
16252b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign(t1, getIReg64(R_RBP));
16253b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      t2 = newTemp(Ity_I64);
16254b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
16255b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putIReg64(R_RSP, mkexpr(t2));
16256b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      storeLE(mkexpr(t2), mkexpr(t1));
16257b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      putIReg64(R_RBP, mkexpr(t2));
16258b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      if (d64 > 0) {
16259b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov         putIReg64(R_RSP, binop(Iop_Sub64, mkexpr(t2), mkU64(d64)));
16260b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      }
16261b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      DIP("enter $%u, $0\n", (UInt)d64);
16262b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov      break;
16263b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov
16264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC9: /* LEAVE */
16265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* In 64-bit mode this defaults to a 64-bit operand size.  There
16266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         is no way to encode a 32-bit variant.  Hence sz==4 but we do
16267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         it as if sz=8. */
16268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4)
16269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
16271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
16272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIReg64(R_RBP));
16273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* First PUT RSP looks redundant, but need it because RSP must
16274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         always be up-to-date for Memcheck to work... */
16275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, mkexpr(t1));
16276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, loadLE(Ity_I64,mkexpr(t1)));
16277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RBP, mkexpr(t2));
16278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(8)) );
16279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("leave\n");
16280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    /* ---------------- Misc weird-ass insns --------------- */
16283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
16284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x27: /* DAA */
16285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x2F: /* DAS */
16286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       t1 = newTemp(cb);
16287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t1);
16288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       /* Widen %AL to 32 bits, so it's all defined when we push it. */
16289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, WIDEN, 4, TempReg, t1);
16290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uWiden(cb, 1, False);
16291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr0(cb, CALLM_S, 0);
16292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, PUSH, 4, TempReg, t1);
16293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, CALLM, 0, Lit16,
16294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--                   opc == 0x27 ? VGOFF_(helper_DAA) : VGOFF_(helper_DAS) );
16295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uFlagsRWU(cb, FlagsAC, FlagsSZACP, FlagO);
16296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, POP, 4, TempReg, t1);
16297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr0(cb, CALLM_E, 0);
16298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, PUT, 1, TempReg, t1, ArchReg, R_AL);
16299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       DIP(opc == 0x27 ? "daa\n" : "das\n");
16300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       break;
16301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
16302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x37: /* AAA */
16303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x3F: /* AAS */
16304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       t1 = newTemp(cb);
16305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
16306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       /* Widen %AL to 32 bits, so it's all defined when we push it. */
16307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, WIDEN, 4, TempReg, t1);
16308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uWiden(cb, 2, False);
16309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr0(cb, CALLM_S, 0);
16310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, PUSH, 4, TempReg, t1);
16311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, CALLM, 0, Lit16,
16312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--                   opc == 0x37 ? VGOFF_(helper_AAA) : VGOFF_(helper_AAS) );
16313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uFlagsRWU(cb, FlagA, FlagsAC, FlagsEmpty);
16314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, POP, 4, TempReg, t1);
16315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr0(cb, CALLM_E, 0);
16316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
16317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       DIP(opc == 0x37 ? "aaa\n" : "aas\n");
16318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       break;
16319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
16320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0xD4: /* AAM */
16321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0xD5: /* AAD */
16322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       d32 = getUChar(delta); delta++;
16323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       if (d32 != 10) VG_(core_panic)("disInstr: AAM/AAD but base not 10 !");
16324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       t1 = newTemp(cb);
16325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET, 2, ArchReg, R_EAX, TempReg, t1);
16326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       /* Widen %AX to 32 bits, so it's all defined when we push it. */
16327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, WIDEN, 4, TempReg, t1);
16328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uWiden(cb, 2, False);
16329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr0(cb, CALLM_S, 0);
16330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, PUSH, 4, TempReg, t1);
16331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, CALLM, 0, Lit16,
16332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--                   opc == 0xD4 ? VGOFF_(helper_AAM) : VGOFF_(helper_AAD) );
16333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uFlagsRWU(cb, FlagsEmpty, FlagsSZP, FlagsEmpty);
16334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, POP, 4, TempReg, t1);
16335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr0(cb, CALLM_E, 0);
16336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, PUT, 2, TempReg, t1, ArchReg, R_EAX);
16337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       DIP(opc == 0xD4 ? "aam\n" : "aad\n");
16338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       break;
16339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ CWD/CDQ -------------------- */
16341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x98: /* CBW */
16343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 8) {
16345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 8, unop(Iop_32Sto64, getIRegRAX(4)) );
16346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP(/*"cdqe\n"*/"cltq");
16347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
16348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) {
16350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 4, unop(Iop_16Sto32, getIRegRAX(2)) );
16351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cwtl\n");
16352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
16353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2) {
16355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 2, unop(Iop_8Sto16, getIRegRAX(1)) );
16356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cbw\n");
16357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
16358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
16360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x99: /* CWD/CDQ/CQO */
16362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4 || sz == 8);
16364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
16365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRDX( sz,
16366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(mkSizedOp(ty,Iop_Sar8),
16367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        getIRegRAX(sz),
16368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(sz == 2 ? 15 : (sz == 4 ? 31 : 63))) );
16369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP(sz == 2 ? "cwd\n"
16370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  : (sz == 4 ? /*"cdq\n"*/ "cltd\n"
16371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             : "cqo\n"));
16372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ FPU ops -------------------- */
16375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9E: /* SAHF */
16377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_SAHF();
16378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("sahf\n");
16379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9F: /* LAHF */
16382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_LAHF();
16383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("lahf\n");
16384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9B: /* FWAIT */
16387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* ignore? */
16388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("fwait\n");
16389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD8:
16392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD9:
16393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDA:
16394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDB:
16395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDC:
16396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDD:
16397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDE:
16398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xDF: {
16399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool redundantREXWok = False;
16400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx))
16402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* kludge to tolerate redundant rex.w prefixes (should do this
16405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         properly one day) */
16406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* mono 1.1.18.1 produces 48 D9 FA, which is rex.w fsqrt */
16407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( (opc == 0xD9 && getUChar(delta+0) == 0xFA)/*fsqrt*/ )
16408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         redundantREXWok = True;
16409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if ( (sz == 4
16411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           || (sz == 8 && redundantREXWok))
16412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           && haveNo66noF2noF3(pfx)) {
16413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Long delta0    = delta;
16414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
16415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_FPU ( &decode_OK, vbi, pfx, delta );
16416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK) {
16417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta = delta0;
16418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
16419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
16421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ INT ------------------------ */
16427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCC: /* INT 3 */
16429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmp_lit(Ijk_SigTRAP, guest_RIP_bbstart + delta);
16430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext = Dis_StopHere;
16431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("int $0x3\n");
16432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xCD: { /* INT imm8 */
16435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRJumpKind jk = Ijk_Boring;
16436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (have66orF2orF3(pfx)) goto decode_failure;
16437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getUChar(delta); delta++;
16438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (d64) {
16439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 32: jk = Ijk_Sys_int32; break;
16440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default: goto decode_failure;
16441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest_RIP_next_mustcheck = True;
16443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      guest_RIP_next_assumed = guest_RIP_bbstart + delta;
16444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmp_lit(jk, guest_RIP_next_assumed);
16445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* It's important that all ArchRegs carry their up-to-date value
16446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         at this point.  So we declare an end-of-block here, which
16447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         forces any TempRegs caching ArchRegs to be flushed. */
16448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres.whatNext = Dis_StopHere;
16449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("int $0x%02x\n", (UInt)d64);
16450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
16452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Jcond, byte offset --------- */
16454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEB: /* Jb (jump, byte offset) */
16456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4)
16458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* JRS added 2004 July 11 */
16459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
16460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
16461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn(callback_opaque,d64)) {
16462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
16463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = d64;
16464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmp_lit(Ijk_Boring,d64);
16466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
16467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jmp-8 0x%llx\n", d64);
16469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE9: /* Jv (jump, 16/32 offset) */
16472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4)
16474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure; /* JRS added 2004 July 11 */
16475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta);
16476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += sz;
16477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerOkFn(callback_opaque,d64)) {
16478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerU;
16479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = d64;
16480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmp_lit(Ijk_Boring,d64);
16482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
16483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("jmp 0x%llx\n", d64);
16485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x70:
16488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x71:
16489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x72: /* JBb/JNAEb (jump below) */
16490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x73: /* JNBb/JAEb (jump not below) */
16491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x74: /* JZb/JEb (jump zero) */
16492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x75: /* JNZb/JNEb (jump not zero) */
16493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x76: /* JBEb/JNAb (jump below or equal) */
16494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x77: /* JNBEb/JAb (jump not below or equal) */
16495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x78: /* JSb (jump negative) */
16496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x79: /* JSb (jump not negative) */
16497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7A: /* JP (jump parity even) */
16498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7B: /* JNP/JPO (jump parity odd) */
16499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7C: /* JLb/JNGEb (jump less) */
16500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7D: /* JGEb/JNLb (jump greater or equal) */
16501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7E: /* JLEb/JNGb (jump less or equal) */
16502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x7F: /* JGb/JNLEb (jump greater) */
16503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    { Long   jmpDelta;
16504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar* comment  = "";
16505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      jmpDelta = getSDisp8(delta);
16507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(-128 <= jmpDelta && jmpDelta < 128);
16508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = (guest_RIP_bbstart+delta+1) + jmpDelta;
16509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
16510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerCisOk
16511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && vex_control.guest_chase_cond
16512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (Addr64)d64 != (Addr64)guest_RIP_bbstart
16513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && jmpDelta < 0
16514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && resteerOkFn( callback_opaque, d64) ) {
16515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Speculation: assume this backward branch is taken.  So we
16516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            need to emit a side-exit to the insn following this one,
16517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            on the negation of the condition, and continue at the
16518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            branch target address (d64).  If we wind up back at the
16519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            first instruction of the trace, just stop; it's better to
16520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            let the IR loop unroller handle that case. */
16521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
16522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mk_amd64g_calculate_condition(
16523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     (AMD64Condcode)(1 ^ (opc - 0x70))),
16524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ijk_Boring,
16525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRConst_U64(guest_RIP_bbstart+delta) ) );
16526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerC;
16527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = d64;
16528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         comment = "(assumed taken)";
16529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
16531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (resteerCisOk
16532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && vex_control.guest_chase_cond
16533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && (Addr64)d64 != (Addr64)guest_RIP_bbstart
16534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && jmpDelta >= 0
16535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
16536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Speculation: assume this forward branch is not taken.  So
16537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            we need to emit a side-exit to d64 (the dest) and continue
16538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            disassembling at the insn immediately following this
16539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            one. */
16540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit(
16541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mk_amd64g_calculate_condition((AMD64Condcode)(opc - 0x70)),
16542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  Ijk_Boring,
16543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  IRConst_U64(d64) ) );
16544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext   = Dis_ResteerC;
16545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.continueAt = guest_RIP_bbstart+delta;
16546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         comment = "(assumed not taken)";
16547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else {
16549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Conservative default translation - end the block at this
16550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            point. */
16551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jcc_01( (AMD64Condcode)(opc - 0x70),
16552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 guest_RIP_bbstart+delta,
16553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 d64 );
16554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
16555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("j%s-8 0x%llx %s\n", name_AMD64Condcode(opc - 0x70), d64, comment);
16557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
16559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE3:
16561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* JRCXZ or JECXZ, depending address size override. */
16562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (have66orF2orF3(pfx)) goto decode_failure;
16563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta);
16564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
16565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveASO(pfx)) {
16566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* 32-bit */
16567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
16568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            unop(Iop_32Uto64, getIReg32(R_RCX)),
16569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU64(0)),
16570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Ijk_Boring,
16571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRConst_U64(d64))
16572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
16573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("jecxz 0x%llx\n", d64);
16574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* 64-bit */
16576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Exit( binop(Iop_CmpEQ64,
16577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  getIReg64(R_RCX),
16578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  mkU64(0)),
16579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               Ijk_Boring,
16580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRConst_U64(d64))
16581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             );
16582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("jrcxz 0x%llx\n", d64);
16583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE0: /* LOOPNE disp8: decrement count, jump if count != 0 && ZF==0 */
16587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE1: /* LOOPE  disp8: decrement count, jump if count != 0 && ZF==1 */
16588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE2: /* LOOP   disp8: decrement count, jump if count != 0 */
16589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    { /* The docs say this uses rCX as a count depending on the
16590f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         address size override, not the operand one. */
16591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* zbit  = NULL;
16592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* count = NULL;
16593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRExpr* cond  = NULL;
16594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      HChar*  xtra  = NULL;
16595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16596f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (have66orF2orF3(pfx) || 1==getRexW(pfx)) goto decode_failure;
16597f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* So at this point we've rejected any variants which appear to
16598f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         be governed by the usual operand-size modifiers.  Hence only
16599f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         the address size prefix can have an effect.  It changes the
16600f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         size from 64 (default) to 32. */
16601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = guest_RIP_bbstart+delta+1 + getSDisp8(delta);
16602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta++;
16603f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      if (haveASO(pfx)) {
16604f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         /* 64to32 of 64-bit get is merely a get-put improvement
16605f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            trick. */
16606f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         putIReg32(R_RCX, binop(Iop_Sub32,
16607f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                unop(Iop_64to32, getIReg64(R_RCX)),
16608f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root                                mkU32(1)));
16609f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      } else {
16610f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         putIReg64(R_RCX, binop(Iop_Sub64, getIReg64(R_RCX), mkU64(1)));
16611f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      }
16612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16613f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      /* This is correct, both for 32- and 64-bit versions.  If we're
16614f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         doing a 32-bit dec and the result is zero then the default
16615f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         zero extension rule will cause the upper 32 bits to be zero
16616f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root         too.  Hence a 64-bit check against zero is OK. */
16617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      count = getIReg64(R_RCX);
16618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      cond = binop(Iop_CmpNE64, count, mkU64(0));
16619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
16620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE2:
16621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "";
16622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
16623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE1:
16624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "e";
16625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zbit = mk_amd64g_calculate_condition( AMD64CondZ );
16626f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            cond = mkAnd1(cond, zbit);
16627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
16628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xE0:
16629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            xtra = "ne";
16630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            zbit = mk_amd64g_calculate_condition( AMD64CondNZ );
16631f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root            cond = mkAnd1(cond, zbit);
16632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
16633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
16634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    vassert(0);
16635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U64(d64)) );
16637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16638f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      DIP("loop%s%s 0x%llx\n", xtra, haveASO(pfx) ? "l" : "", d64);
16639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
16641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ IMUL ----------------------- */
16643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x69: /* IMUL Iv, Ev, Gv */
16645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_imul_I_E_G ( vbi, pfx, sz, delta, sz );
16647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x6B: /* IMUL Ib, Ev, Gv */
16649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_imul_I_E_G ( vbi, pfx, sz, delta, 1 );
16650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ MOV ------------------------ */
16653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x88: /* MOV Gb,Eb */
16655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_G_E(vbi, pfx, 1, delta);
16657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x89: /* MOV Gv,Ev */
16660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_G_E(vbi, pfx, sz, delta);
16662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8A: /* MOV Eb,Gb */
16665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_E_G(vbi, pfx, 1, delta);
16667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8B: /* MOV Ev,Gv */
16670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_mov_E_G(vbi, pfx, sz, delta);
16672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8D: /* LEA M,Gv */
16675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 4 && sz != 8)
16677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
16679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm))
16680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* NOTE!  this is the one place where a segment override prefix
16682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         has no effect on the address calculation.  Therefore we clear
16683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         any segment override bits in pfx. */
16684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &alen, vbi, clearSegBits(pfx), delta, dis_buf, 0 );
16685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += alen;
16686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is a hack.  But it isn't clear that really doing the
16687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         calculation at 32 bits is really worth it.  Hence for leal,
16688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do the full 64-bit calculation and then truncate it. */
16689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegG( sz, pfx, modrm,
16690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         sz == 4
16691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            ? unop(Iop_64to32, mkexpr(addr))
16692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            : mkexpr(addr)
16693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              );
16694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("lea%c %s, %s\n", nameISize(sz), dis_buf,
16695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIRegG(sz,pfx,modrm));
16696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0x8C: /* MOV Sw,Ew -- MOV from a SEGMENT REGISTER */
16699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       delta = dis_mov_Sw_Ew(sorb, sz, delta);
16700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
16701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
16702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0x8E: /* MOV Ew,Sw -- MOV to a SEGMENT REGISTER */
16703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       delta = dis_mov_Ew_Sw(sorb, delta);
16704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
16705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA0: /* MOV Ob,AL */
16707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (have66orF2orF3(pfx)) goto decode_failure;
16708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
16709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
16710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA1: /* MOV Ov,eAX */
16711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
16712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getDisp64(delta);
16714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 8;
16715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
16716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = newTemp(Ity_I64);
16717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addr, handleAddrOverrides(vbi, pfx, mkU64(d64)) );
16718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRAX(sz, loadLE( ty, mkexpr(addr) ));
16719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s0x%llx, %s\n", nameISize(sz),
16720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  segRegTxt(pfx), d64,
16721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameIRegRAX(sz));
16722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA2: /* MOV AL,Ob */
16725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (have66orF2orF3(pfx)) goto decode_failure;
16726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
16727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
16728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA3: /* MOV eAX,Ov */
16729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 8 && sz != 4 && sz != 2 && sz != 1)
16730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getDisp64(delta);
16732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 8;
16733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
16734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = newTemp(Ity_I64);
16735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( addr, handleAddrOverrides(vbi, pfx, mkU64(d64)) );
16736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), getIRegRAX(sz) );
16737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("mov%c %s, %s0x%llx\n", nameISize(sz), nameIRegRAX(sz),
16738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  segRegTxt(pfx), d64);
16739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* XXXX be careful here with moves to AH/BH/CH/DH */
16742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB0: /* MOV imm,AL */
16743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB1: /* MOV imm,CL */
16744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB2: /* MOV imm,DL */
16745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB3: /* MOV imm,BL */
16746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB4: /* MOV imm,AH */
16747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB5: /* MOV imm,CH */
16748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB6: /* MOV imm,DH */
16749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB7: /* MOV imm,BH */
16750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getUChar(delta);
16752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += 1;
16753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRexB(1, pfx, opc-0xB0, mkU8(d64));
16754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("movb $%lld,%s\n", d64, nameIRegRexB(1,pfx,opc-0xB0));
16755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB8: /* MOV imm,eAX */
16758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xB9: /* MOV imm,eCX */
16759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBA: /* MOV imm,eDX */
16760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBB: /* MOV imm,eBX */
16761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBC: /* MOV imm,eSP */
16762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBD: /* MOV imm,eBP */
16763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBE: /* MOV imm,eSI */
16764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xBF: /* MOV imm,eDI */
16765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the one-and-only place where 64-bit literals are
16766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         allowed in the instruction stream. */
16767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 8) {
16769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = getDisp64(delta);
16770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 8;
16771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRexB(8, pfx, opc-0xB8, mkU64(d64));
16772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("movabsq $%lld,%s\n", (Long)d64,
16773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   nameIRegRexB(8,pfx,opc-0xB8));
16774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = getSDisp(imin(4,sz),delta);
16776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += imin(4,sz);
16777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRexB(sz, pfx, opc-0xB8,
16778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU(szToITy(sz), d64 & mkSizeMask(sz)));
16779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c $%lld,%s\n", nameISize(sz),
16780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 (Long)d64,
16781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 nameIRegRexB(sz,pfx,opc-0xB8));
16782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC6: /* MOV Ib,Eb */
16786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
16787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_Mov_I_E;
16788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC7: /* MOV Iv,Ev */
16789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_Mov_I_E;
16790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_Mov_I_E:
16792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
16794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
16795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++; /* mod/rm byte */
16796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = getSDisp(imin(4,sz),delta);
16797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += imin(4,sz);
16798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(sz, pfx, modrm,
16799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      mkU(szToITy(sz), d64 & mkSizeMask(sz)));
16800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c $%lld, %s\n", nameISize(sz),
16801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  (Long)d64,
16802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  nameIRegE(sz,pfx,modrm));
16803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf,
16805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           /*xtra*/imin(4,sz) );
16806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
16807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = getSDisp(imin(4,sz),delta);
16808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += imin(4,sz);
16809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         storeLE(mkexpr(addr),
16810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 mkU(szToITy(sz), d64 & mkSizeMask(sz)));
16811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("mov%c $%lld, %s\n", nameISize(sz), (Long)d64, dis_buf);
16812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ MOVx ------------------------ */
16816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x63: /* MOVSX */
16818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveREX(pfx) && 1==getRexW(pfx)) {
16820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(sz == 8);
16821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* movsx r/m32 to r64 */
16822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
16823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
16824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
16825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegG(8, pfx, modrm,
16826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_32Sto64,
16827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  getIRegE(4, pfx, modrm)));
16828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movslq %s,%s\n",
16829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameIRegE(4, pfx, modrm),
16830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameIRegG(8, pfx, modrm));
16831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
16832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
16833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
16834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += alen;
16835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegG(8, pfx, modrm,
16836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_32Sto64,
16837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  loadLE(Ity_I32, mkexpr(addr))));
16838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("movslq %s,%s\n", dis_buf,
16839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                nameIRegG(8, pfx, modrm));
16840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
16841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
16842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
16843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
16844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
16845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl imm, A ----------------- */
16847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x04: /* ADD Ib, AL */
16849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, False, Iop_Add8, True, delta, "add" );
16851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x05: /* ADD Iv, eAX */
16853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(sz, False, Iop_Add8, True, delta, "add" );
16855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0C: /* OR Ib, AL */
16858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, False, Iop_Or8, True, delta, "or" );
16860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0D: /* OR Iv, eAX */
16862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Or8, True, delta, "or" );
16864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x14: /* ADC Ib, AL */
16867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, True, Iop_Add8, True, delta, "adc" );
16869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x15: /* ADC Iv, eAX */
16871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, True, Iop_Add8, True, delta, "adc" );
16873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1C: /* SBB Ib, AL */
16876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, True, Iop_Sub8, True, delta, "sbb" );
16878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1D: /* SBB Iv, eAX */
16880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, True, Iop_Sub8, True, delta, "sbb" );
16882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x24: /* AND Ib, AL */
16885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, False, Iop_And8, True, delta, "and" );
16887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x25: /* AND Iv, eAX */
16889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_And8, True, delta, "and" );
16891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2C: /* SUB Ib, AL */
16894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A(1, False, Iop_Sub8, True, delta, "sub" );
16896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2D: /* SUB Iv, eAX */
16898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Sub8, True, delta, "sub" );
16900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x34: /* XOR Ib, AL */
16903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, False, Iop_Xor8, True, delta, "xor" );
16905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x35: /* XOR Iv, eAX */
16907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Xor8, True, delta, "xor" );
16909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3C: /* CMP Ib, AL */
16912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, False, Iop_Sub8, False, delta, "cmp" );
16914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3D: /* CMP Iv, eAX */
16916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_Sub8, False, delta, "cmp" );
16918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA8: /* TEST Ib, AL */
16921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( 1, False, Iop_And8, False, delta, "test" );
16923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA9: /* TEST Iv, eAX */
16925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op_imm_A( sz, False, Iop_And8, False, delta, "test" );
16927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl Ev, Gv ----------------- */
16930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x02: /* ADD Eb,Gb */
16932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Add8, True, 1, delta, "add" );
16934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x03: /* ADD Ev,Gv */
16936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Add8, True, sz, delta, "add" );
16938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0A: /* OR Eb,Gb */
16941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Or8, True, 1, delta, "or" );
16943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0B: /* OR Ev,Gv */
16945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Or8, True, sz, delta, "or" );
16947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x12: /* ADC Eb,Gb */
16950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, True, Iop_Add8, True, 1, delta, "adc" );
16952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x13: /* ADC Ev,Gv */
16954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, True, Iop_Add8, True, sz, delta, "adc" );
16956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1A: /* SBB Eb,Gb */
16959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
16961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x1B: /* SBB Ev,Gv */
16963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
16965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x22: /* AND Eb,Gb */
16968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, True, 1, delta, "and" );
16970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x23: /* AND Ev,Gv */
16972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, True, sz, delta, "and" );
16974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2A: /* SUB Eb,Gb */
16977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, True, 1, delta, "sub" );
16979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x2B: /* SUB Ev,Gv */
16981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, True, sz, delta, "sub" );
16983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x32: /* XOR Eb,Gb */
16986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Xor8, True, 1, delta, "xor" );
16988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x33: /* XOR Ev,Gv */
16990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Xor8, True, sz, delta, "xor" );
16992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3A: /* CMP Eb,Gb */
16995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
16996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
16997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
16998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x3B: /* CMP Ev,Gv */
16999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
17001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x84: /* TEST Eb,Gb */
17004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, False, 1, delta, "test" );
17006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x85: /* TEST Ev,Gv */
17008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_E_G ( vbi, pfx, False, Iop_And8, False, sz, delta, "test" );
17010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ opl Gv, Ev ----------------- */
17013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x00: /* ADD Gb,Eb */
17015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Add8, True, 1, delta, "add" );
17017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x01: /* ADD Gv,Ev */
17019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Add8, True, sz, delta, "add" );
17021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x08: /* OR Gb,Eb */
17024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Or8, True, 1, delta, "or" );
17026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x09: /* OR Gv,Ev */
17028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Or8, True, sz, delta, "or" );
17030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x10: /* ADC Gb,Eb */
17033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, True, Iop_Add8, True, 1, delta, "adc" );
17035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x11: /* ADC Gv,Ev */
17037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, True, Iop_Add8, True, sz, delta, "adc" );
17039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x18: /* SBB Gb,Eb */
17042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, True, Iop_Sub8, True, 1, delta, "sbb" );
17044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x19: /* SBB Gv,Ev */
17046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, True, Iop_Sub8, True, sz, delta, "sbb" );
17048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x20: /* AND Gb,Eb */
17051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_And8, True, 1, delta, "and" );
17053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x21: /* AND Gv,Ev */
17055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_And8, True, sz, delta, "and" );
17057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x28: /* SUB Gb,Eb */
17060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, True, 1, delta, "sub" );
17062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x29: /* SUB Gv,Ev */
17064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, True, sz, delta, "sub" );
17066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x30: /* XOR Gb,Eb */
17069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Xor8, True, 1, delta, "xor" );
17071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x31: /* XOR Gv,Ev */
17073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Xor8, True, sz, delta, "xor" );
17075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x38: /* CMP Gb,Eb */
17078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, False, 1, delta, "cmp" );
17080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x39: /* CMP Gv,Ev */
17082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_op2_G_E ( vbi, pfx, False, Iop_Sub8, False, sz, delta, "cmp" );
17084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ POP ------------------------ */
17087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x58: /* POP eAX */
17089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x59: /* POP eCX */
17090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5A: /* POP eDX */
17091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5B: /* POP eBX */
17092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5D: /* POP eBP */
17093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5E: /* POP eSI */
17094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5F: /* POP eDI */
17095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x5C: /* POP eSP */
17096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4 || sz == 8);
17098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4)
17099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sz = 8; /* there is no encoding for 32-bit pop in 64-bit mode */
17100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(szToITy(sz));
17101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
17102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, getIReg64(R_RSP));
17103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, loadLE(szToITy(sz),mkexpr(t2)));
17104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
17105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRexB(sz, pfx, opc-0x58, mkexpr(t1));
17106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pop%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x58));
17107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9D: /* POPF */
17110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note.  There is no encoding for a 32-bit popf in 64-bit mode.
17111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         So sz==4 actually means sz==8. */
17112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17113f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov      vassert(sz == 2 || sz == 4 || sz == 8);
17114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) sz = 8;
17115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
17116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64); t2 = newTemp(Ity_I64);
17117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, getIReg64(R_RSP));
17118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, widenUto64(loadLE(szToITy(sz),mkexpr(t2))));
17119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t2), mkU64(sz)));
17120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* t1 is the flag word.  Mask out everything except OSZACP and
17121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         set the flags thunk to AMD64G_CC_OP_COPY. */
17122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
17123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
17124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1,
17125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And64,
17126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkexpr(t1),
17127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU64( AMD64G_CC_MASK_C | AMD64G_CC_MASK_P
17128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     | AMD64G_CC_MASK_A | AMD64G_CC_MASK_Z
17129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                     | AMD64G_CC_MASK_S| AMD64G_CC_MASK_O )
17130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             )
17131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       )
17132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
17133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Also need to set the D flag, which is held in bit 10 of t1.
17135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         If zero, put 1 in OFFB_DFLAG, else -1 in OFFB_DFLAG. */
17136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
17137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_DFLAG,
17138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X(
17139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32to8,
17140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_64to32,
17141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
17142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shr64, mkexpr(t1), mkU8(10)),
17143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU64(1)))),
17144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(1),
17145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(0xFFFFFFFFFFFFFFFFULL)))
17146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
17147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And set the ID flag */
17149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
17150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_IDFLAG,
17151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X(
17152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32to8,
17153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_64to32,
17154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
17155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shr64, mkexpr(t1), mkU8(21)),
17156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU64(1)))),
17157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(0),
17158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(1)))
17159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
17160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And set the AC flag too */
17162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put(
17163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               OFFB_ACFLAG,
17164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               IRExpr_Mux0X(
17165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_32to8,
17166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  unop(Iop_64to32,
17167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(Iop_And64,
17168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(Iop_Shr64, mkexpr(t1), mkU8(18)),
17169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             mkU64(1)))),
17170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(0),
17171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkU64(1)))
17172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
17173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("popf%c\n", nameISize(sz));
17175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0x61: /* POPA */
17178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* This is almost certainly wrong for sz==2.  So ... */
17179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       if (sz != 4) goto decode_failure;
17180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* t5 is the old %ESP value. */
17182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       t5 = newTemp(Ity_I32);
17183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       assign( t5, getIReg(4, R_ESP) );
17184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* Reload all the registers, except %esp. */
17186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_EAX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(28)) ));
17187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_ECX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(24)) ));
17188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_EDX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(20)) ));
17189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_EBX, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32(16)) ));
17190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* ignore saved %ESP */
17191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_EBP, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 8)) ));
17192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_ESI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 4)) ));
17193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4,R_EDI, loadLE(Ity_I32, binop(Iop_Add32,mkexpr(t5),mkU32( 0)) ));
17194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* and move %ESP back up */
17196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg( 4, R_ESP, binop(Iop_Add32, mkexpr(t5), mkU32(8*4)) );
17197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       DIP("pusha%c\n", nameISize(sz));
17199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
17200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x8F: { /* POPQ m64 / POPW m16 */
17202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Int   len;
17203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      UChar rm;
17204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* There is no encoding for 32-bit pop in 64-bit mode.
17205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         So sz==4 actually means sz==8. */
17206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17207f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root      vassert(sz == 2 || sz == 4
17208f673d1bf8bfb172f0eccbe4d3a908b3c65b55b33Kenny Root              || /* tolerate redundant REX.W, see #210481 */ sz == 8);
17209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) sz = 8;
17210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
17211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      rm = getUChar(delta);
17213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* make sure this instruction is correct POP */
17215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(rm) || gregLO3ofRM(rm) != 0)
17216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
17217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* and has correct size */
17218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 8);
17219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I64);
17222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, getIReg64(R_RSP) );
17223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t3, loadLE(Ity_I64, mkexpr(t1)) );
17224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Increase RSP; must be done before the STORE.  Intel manual
17226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         says: If the RSP register is used as a base register for
17227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addressing a destination operand in memory, the POP
17228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         instruction computes the effective address of the operand
17229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         after it increments the RSP register.  */
17230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, binop(Iop_Add64, mkexpr(t1), mkU64(sz)) );
17231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      addr = disAMode ( &len, vbi, pfx, delta, dis_buf, 0 );
17233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(addr), mkexpr(t3) );
17234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("popl %s\n", dis_buf);
17236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += len;
17238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x1F: /* POP %DS */
17242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_pop_segreg( cb, R_DS, sz ); break;
17243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x07: /* POP %ES */
17244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_pop_segreg( cb, R_ES, sz ); break;
17245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x17: /* POP %SS */
17246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_pop_segreg( cb, R_SS, sz ); break;
17247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ PUSH ----------------------- */
17249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x50: /* PUSH eAX */
17251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x51: /* PUSH eCX */
17252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x52: /* PUSH eDX */
17253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x53: /* PUSH eBX */
17254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x55: /* PUSH eBP */
17255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x56: /* PUSH eSI */
17256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x57: /* PUSH eDI */
17257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x54: /* PUSH eSP */
17258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* This is the Right Way, in that the value to be pushed is
17259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         established before %rsp is changed, so that pushq %rsp
17260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         correctly pushes the old value. */
17261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4 || sz == 8);
17263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4)
17264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         sz = 8; /* there is no encoding for 32-bit push in 64-bit mode */
17265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = sz==2 ? Ity_I16 : Ity_I64;
17266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty);
17267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
17268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, getIRegRexB(sz, pfx, opc-0x50));
17269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(sz)));
17270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, mkexpr(t2) );
17271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE(mkexpr(t2),mkexpr(t1));
17272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("push%c %s\n", nameISize(sz), nameIRegRexB(sz,pfx,opc-0x50));
17273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x68: /* PUSH Iv */
17276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note, sz==4 is not possible in 64-bit mode.  Hence ... */
17278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) sz = 8;
17279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getSDisp(imin(4,sz),delta);
17280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta += imin(4,sz);
17281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_push_I;
17282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x6A: /* PUSH Ib, sign-extended to sz */
17283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note, sz==4 is not possible in 64-bit mode.  Hence ... */
17285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) sz = 8;
17286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64 = getSDisp8(delta); delta += 1;
17287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_push_I;
17288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_push_I:
17289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
17290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(ty);
17292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
17293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, mkexpr(t1) );
17294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* stop mkU16 asserting if d32 is a negative 16-bit number
17295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         (bug #132813) */
17296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (ty == Ity_I16)
17297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 &= 0xFFFF;
17298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      storeLE( mkexpr(t1), mkU(ty,d64) );
17299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("push%c $%lld\n", nameISize(sz), (Long)d64);
17300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x9C: /* PUSHF */ {
17303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Note.  There is no encoding for a 32-bit pushf in 64-bit
17304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         mode.  So sz==4 actually means sz==8. */
17305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* 24 July 06: has also been seen with a redundant REX prefix,
17306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         so must also allow sz==8. */
17307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 2 || sz == 4 || sz == 8);
17309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 4) sz = 8;
17310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz != 8) goto decode_failure; // until we know a sz==2 test case exists
17311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, binop(Iop_Sub64,getIReg64(R_RSP),mkU64(sz)) );
17314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIReg64(R_RSP, mkexpr(t1) );
17315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
17317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t2, mk_amd64g_calculate_rflags_all() );
17318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Patch in the D flag.  This can simply be a copy of bit 10 of
17320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         baseBlock[OFFB_DFLAG]. */
17321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t3 = newTemp(Ity_I64);
17322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t3, binop(Iop_Or64,
17323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t2),
17324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And64,
17325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              IRExpr_Get(OFFB_DFLAG,Ity_I64),
17326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU64(1<<10)))
17327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
17328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And patch in the ID flag. */
17330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t4 = newTemp(Ity_I64);
17331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t4, binop(Iop_Or64,
17332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t3),
17333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And64,
17334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl64, IRExpr_Get(OFFB_IDFLAG,Ity_I64),
17335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkU8(21)),
17336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU64(1<<21)))
17337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
17338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* And patch in the AC flag too. */
17340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t5 = newTemp(Ity_I64);
17341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t5, binop(Iop_Or64,
17342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkexpr(t4),
17343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And64,
17344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              binop(Iop_Shl64, IRExpr_Get(OFFB_ACFLAG,Ity_I64),
17345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                               mkU8(18)),
17346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              mkU64(1<<18)))
17347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
17348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* if sz==2, the stored value needs to be narrowed. */
17350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (sz == 2)
17351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(t1), unop(Iop_32to16,
17352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             unop(Iop_64to32,mkexpr(t5))) );
17353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      else
17354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        storeLE( mkexpr(t1), mkexpr(t5) );
17355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("pushf%c\n", nameISize(sz));
17357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0x60: /* PUSHA */
17361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* This is almost certainly wrong for sz==2.  So ... */
17362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       if (sz != 4) goto decode_failure;
17363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* This is the Right Way, in that the value to be pushed is
17365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          established before %esp is changed, so that pusha
17366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          correctly pushes the old %esp value.  New value of %esp is
17367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          pushed at start. */
17368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* t0 is the %ESP value we're going to push. */
17369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       t0 = newTemp(Ity_I32);
17370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       assign( t0, getIReg(4, R_ESP) );
17371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* t5 will be the new %ESP value. */
17373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       t5 = newTemp(Ity_I32);
17374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       assign( t5, binop(Iop_Sub32, mkexpr(t0), mkU32(8*4)) );
17375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* Update guest state before prodding memory. */
17377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       putIReg(4, R_ESP, mkexpr(t5));
17378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* Dump all the registers. */
17380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(28)), getIReg(4,R_EAX) );
17381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(24)), getIReg(4,R_ECX) );
17382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(20)), getIReg(4,R_EDX) );
17383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(16)), getIReg(4,R_EBX) );
17384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32(12)), mkexpr(t0) /*esp*/);
17385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 8)), getIReg(4,R_EBP) );
17386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 4)), getIReg(4,R_ESI) );
17387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       storeLE( binop(Iop_Add32,mkexpr(t5),mkU32( 0)), getIReg(4,R_EDI) );
17388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       DIP("pusha%c\n", nameISize(sz));
17390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
17391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x0E: /* PUSH %CS */
17394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_push_segreg( cb, R_CS, sz ); break;
17395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x1E: /* PUSH %DS */
17396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_push_segreg( cb, R_DS, sz ); break;
17397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x06: /* PUSH %ES */
17398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_push_segreg( cb, R_ES, sz ); break;
17399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0x16: /* PUSH %SS */
17400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       dis_push_segreg( cb, R_SS, sz ); break;
17401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* ------------------------ SCAS et al ----------------- */
17403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0xA4: /* MOVS, no REP prefix */
17405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0xA5:
17406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       dis_string_op( dis_MOVS, ( opc == 0xA4 ? 1 : sz ), "movs", sorb );
17407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
17408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..   case 0xA6: /* CMPSb, no REP prefix */
17410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0xA7:
17411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..      dis_string_op( dis_CMPS, ( opc == 0xA6 ? 1 : sz ), "cmps", sorb );
17412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..      break;
17413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
17414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
17415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case 0xAC: /* LODS, no REP prefix */
17416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case 0xAD:
17417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       dis_string_op( dis_LODS, ( opc == 0xAC ? 1 : sz ), "lods", pfx );
17418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       break;
17419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0xAE: /* SCAS, no REP prefix */
17421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0xAF:
17422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       dis_string_op( dis_SCAS, ( opc == 0xAE ? 1 : sz ), "scas", sorb );
17423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
17424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFC: /* CLD */
17427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_DFLAG, mkU64(1)) );
17429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("cld\n");
17430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFD: /* STD */
17433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_DFLAG, mkU64(-1ULL)) );
17435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("std\n");
17436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF8: /* CLC */
17439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF9: /* STC */
17440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF5: /* CMC */
17441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t0 = newTemp(Ity_I64);
17442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t0, mk_amd64g_calculate_rflags_all() );
17444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
17445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF8:
17446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_And64, mkexpr(t0),
17447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU64(~AMD64G_CC_MASK_C)));
17448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("clc\n");
17449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
17450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF9:
17451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_Or64, mkexpr(t0),
17452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                        mkU64(AMD64G_CC_MASK_C)));
17453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("stc\n");
17454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
17455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         case 0xF5:
17456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, binop(Iop_Xor64, mkexpr(t0),
17457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU64(AMD64G_CC_MASK_C)));
17458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("cmc\n");
17459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
17460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         default:
17461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            vpanic("disInstr(x64)(clc/stc/cmc)");
17462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
17464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
17465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t1) ));
17466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Set NDEP even though it isn't used.  This makes redundant-PUT
17467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         elimination of previous stores to this field work better. */
17468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
17469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    /* REPNE prefix insn */
17472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    case 0xF2: {
17473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       Addr32 eip_orig = guest_eip_bbstart + delta - 1;
17474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       vassert(sorb == 0);
17475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       abyte = getUChar(delta); delta++;
17476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       if (abyte == 0x66) { sz = 2; abyte = getUChar(delta); delta++; }
17478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       whatNext = Dis_StopHere;
17479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       switch (abyte) {
17481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* According to the Intel manual, "repne movs" should never occur, but
17482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..        * in practice it has happened, so allow for it here... */
17483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xA4: sz = 1;   /* REPNE MOVS<sz> */
17484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..         goto decode_failure;
17485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       case 0xA5:
17486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..         //         dis_REP_op ( CondNZ, dis_MOVS, sz, eip_orig,
17487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..         //                              guest_eip_bbstart+delta, "repne movs" );
17488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..         //         break;
17489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
17490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       case 0xA6: sz = 1;   /* REPNE CMPS<sz> */
17491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       case 0xA7:
17492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          dis_REP_op ( cb, CondNZ, dis_CMPS, sz, eip_orig, eip, "repne cmps" );
17493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          break;
17494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
17495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xAE: sz = 1;   /* REPNE SCAS<sz> */
17496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xAF:
17497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
17498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..                                  guest_eip_bbstart+delta, "repne scas" );
17499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          break;
17500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
17501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       default:
17502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          goto decode_failure;
17503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       }
17504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       break;
17505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..    }
17506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ AE: SCAS variants ------ */
17508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAE:
17509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAF:
17510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* F2 AE/AF: repne scasb/repne scas{w,l,q} */
17511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2(pfx) && !haveF3(pfx)) {
17512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xAE)
17513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_REP_op ( AMD64CondNZ, dis_SCAS, sz,
17515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr,
17516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_bbstart+delta, "repne scas", pfx );
17517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
17518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* F3 AE/AF: repe scasb/repe scas{w,l,q} */
17521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!haveF2(pfx) && haveF3(pfx)) {
17522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xAE)
17523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_REP_op ( AMD64CondZ, dis_SCAS, sz,
17525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr,
17526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_bbstart+delta, "repe scas", pfx );
17527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
17528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* AE/AF: scasb/scas{w,l,q} */
17531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!haveF2(pfx) && !haveF3(pfx)) {
17532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xAE)
17533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_string_op( dis_SCAS, sz, "scas", pfx );
17535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
17538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ A6, A7: CMPS variants ------ */
17540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA6:
17541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA7:
17542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* F3 A6/A7: repe cmps/rep cmps{w,l,q} */
17543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF3(pfx) && !haveF2(pfx)) {
17544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xA6)
17545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_REP_op ( AMD64CondZ, dis_CMPS, sz,
17547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr,
17548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_bbstart+delta, "repe cmps", pfx );
17549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
17550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
17553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ AA, AB: STOS variants ------ */
17555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAA:
17556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xAB:
17557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* F3 AA/AB: rep stosb/rep stos{w,l,q} */
17558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF3(pfx) && !haveF2(pfx)) {
17559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xAA)
17560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
17562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr,
17563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_bbstart+delta, "rep stos", pfx );
17564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        dres.whatNext = Dis_StopHere;
17565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        break;
17566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* AA/AB: stosb/stos{w,l,q} */
17568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!haveF3(pfx) && !haveF2(pfx)) {
17569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xAA)
17570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_string_op( dis_STOS, sz, "stos", pfx );
17572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
17575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------ A4, A5: MOVS variants ------ */
17577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA4:
17578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xA5:
17579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* F3 A4: rep movsb */
17580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF3(pfx) && !haveF2(pfx)) {
17581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xA4)
17582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
17584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_curr_instr,
17585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      guest_RIP_bbstart+delta, "rep movs", pfx );
17586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        dres.whatNext = Dis_StopHere;
17587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        break;
17588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* A4: movsb */
17590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!haveF3(pfx) && !haveF2(pfx)) {
17591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (opc == 0xA4)
17592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            sz = 1;
17593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dis_string_op( dis_MOVS, sz, "movs", pfx );
17594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto decode_failure;
17597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ XCHG ----------------------- */
17600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* XCHG reg,mem automatically asserts LOCK# even without a LOCK
17602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      prefix.  Therefore, surround it with a IRStmt_MBE(Imbe_BusLock)
17603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      and IRStmt_MBE(Imbe_BusUnlock) pair.  But be careful; if it is
17604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      used with an explicit LOCK prefix, we don't want to end up with
17605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      two IRStmt_MBE(Imbe_BusLock)s -- one made here and one made by
17606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      the generic LOCK logic at the top of disInstr. */
17607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x86: /* XCHG Gb,Eb */
17608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
17609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Fall through ... */
17610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x87: /* XCHG Gv,Ev */
17611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
17614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(ty); t2 = newTemp(ty);
17615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (epartIsReg(modrm)) {
17616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t1, getIRegE(sz, pfx, modrm));
17617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(t2, getIRegG(sz, pfx, modrm));
17618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegG(sz, pfx, modrm, mkexpr(t1));
17619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegE(sz, pfx, modrm, mkexpr(t2));
17620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta++;
17621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("xchg%c %s, %s\n",
17622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             nameISize(sz), nameIRegG(sz, pfx, modrm),
17623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            nameIRegE(sz, pfx, modrm));
17624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      } else {
17625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = True;
17626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
17627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, loadLE(ty, mkexpr(addr)) );
17628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t2, getIRegG(sz, pfx, modrm) );
17629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         casLE( mkexpr(addr),
17630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                mkexpr(t1), mkexpr(t2), guest_RIP_curr_instr );
17631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegG( sz, pfx, modrm, mkexpr(t1) );
17632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
17633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("xchg%c %s, %s\n", nameISize(sz),
17634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                nameIRegG(sz, pfx, modrm), dis_buf);
17635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x90: /* XCHG eAX,eAX */
17639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* detect and handle F3 90 (rep nop) specially */
17640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!have66(pfx) && !haveF2(pfx) && haveF3(pfx)) {
17641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rep nop (P4 pause)\n");
17642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* "observe" the hint.  The Vex client needs to be careful not
17643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            to cause very long delays as a result, though. */
17644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmp_lit(Ijk_Yield, guest_RIP_bbstart+delta);
17645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
17646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* detect and handle NOPs specially */
17649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (/* F2/F3 probably change meaning completely */
17650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          !haveF2orF3(pfx)
17651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          /* If REX.B is 1, we're not exchanging rAX with itself */
17652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          && getRexB(pfx)==0 ) {
17653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("nop\n");
17654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* else fall through to normal case. */
17657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x91: /* XCHG rAX,rCX */
17658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x92: /* XCHG rAX,rDX */
17659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x93: /* XCHG rAX,rBX */
17660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x94: /* XCHG rAX,rSP */
17661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x95: /* XCHG rAX,rBP */
17662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x96: /* XCHG rAX,rSI */
17663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x97: /* XCHG rAX,rDI */
17664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* guard against mutancy */
17666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      codegen_xchg_rAX_Reg ( pfx, sz, opc - 0x90 );
17669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    /* ------------------------ XLAT ----------------------- */
17672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
17673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--    case 0xD7: /* XLAT */
17674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       t1 = newTemp(cb); t2 = newTemp(cb);
17675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET, sz, ArchReg, R_EBX, TempReg, t1); /* get eBX */
17676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       handleAddrOverrides( cb, sorb, t1 );               /* make t1 DS:eBX */
17677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, GET, 1, ArchReg, R_AL, TempReg, t2); /* get AL */
17678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       /* Widen %AL to 32 bits, so it's all defined when we add it. */
17679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr1(cb, WIDEN, 4, TempReg, t2);
17680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uWiden(cb, 1, False);
17681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, ADD, sz, TempReg, t2, TempReg, t1);  /* add AL to eBX */
17682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, LOAD, 1, TempReg, t1,  TempReg, t2); /* get byte at t1 into t2 */
17683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       uInstr2(cb, PUT, 1, TempReg, t2, ArchReg, R_AL); /* put byte into AL */
17684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
17685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       DIP("xlat%c [ebx]\n", nameISize(sz));
17686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       break;
17687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ IN / OUT ----------------------- */
17689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE4: /* IN imm8, AL */
17691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
17692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getUChar(delta); delta++;
17694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, mkU64( abyte & 0xFF ));
17695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
17696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
17697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE5: /* IN imm8, eAX */
17698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(sz == 2 || sz == 4)) goto decode_failure;
17699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getUChar(delta); delta++;
17701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, mkU64( abyte & 0xFF ));
17702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c $%d,%s\n", nameISize(sz), (Int)abyte, nameIRegRAX(sz));
17703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
17704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEC: /* IN %DX, AL */
17705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
17706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
17708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2),
17709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         nameIRegRAX(sz));
17710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
17711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xED: /* IN %DX, eAX */
17712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(sz == 2 || sz == 4)) goto decode_failure;
17713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign(t1, unop(Iop_16Uto64, getIRegRDX(2)));
17715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("in%c %s,%s\n", nameISize(sz), nameIRegRDX(2),
17716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         nameIRegRAX(sz));
17717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_IN;
17718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_IN: {
17719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At this point, sz indicates the width, and t1 is a 64-bit
17720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value giving port number. */
17721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
17722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 1 || sz == 2 || sz == 4);
17724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
17725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t2 = newTemp(Ity_I64);
17726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_1_N(
17727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             t2,
17728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
17729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "amd64g_dirtyhelper_IN",
17730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &amd64g_dirtyhelper_IN,
17731ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_2( mkexpr(t1), mkU64(sz) )
17732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
17733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* do the call, dumping the result in t2. */
17734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
17735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      putIRegRAX(sz, narrowTo( ty, mkexpr(t2) ) );
17736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17737ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17738ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17739ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE6: /* OUT AL, imm8 */
17740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
17741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getUChar(delta); delta++;
17743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, mkU64( abyte & 0xFF ) );
17744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
17745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
17746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xE7: /* OUT eAX, imm8 */
17747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(sz == 2 || sz == 4)) goto decode_failure;
17748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      abyte = getUChar(delta); delta++;
17750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, mkU64( abyte & 0xFF ) );
17751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,$%d\n", nameISize(sz), nameIRegRAX(sz), (Int)abyte);
17752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
17753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEE: /* OUT AL, %DX */
17754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz = 1;
17755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
17757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
17758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          nameIRegRDX(2));
17759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
17760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xEF: /* OUT eAX, %DX */
17761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!(sz == 2 || sz == 4)) goto decode_failure;
17762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      t1 = newTemp(Ity_I64);
17763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assign( t1, unop(Iop_16Uto64, getIRegRDX(2)) );
17764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      DIP("out%c %s,%s\n", nameISize(sz), nameIRegRAX(sz),
17765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                          nameIRegRDX(2));
17766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      goto do_OUT;
17767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   do_OUT: {
17768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* At this point, sz indicates the width, and t1 is a 64-bit
17769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         value giving port number. */
17770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRDirty* d;
17771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vassert(sz == 1 || sz == 2 || sz == 4);
17773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      ty = szToITy(sz);
17774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d = unsafeIRDirty_0_N(
17775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             0/*regparms*/,
17776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             "amd64g_dirtyhelper_OUT",
17777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             &amd64g_dirtyhelper_OUT,
17778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             mkIRExprVec_3( mkexpr(t1),
17779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            widenUto64( getIRegRAX(sz) ),
17780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            mkU64(sz) )
17781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          );
17782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      stmt( IRStmt_Dirty(d) );
17783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp1 extensions) ---------- */
17787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x80: /* Grp1 Ib,Eb */
17789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
17793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
17794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = getSDisp8(delta + am_sz);
17795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
17796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x81: /* Grp1 Iv,Ev */
17799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = imin(sz,4);
17803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = getSDisp(d_sz, delta + am_sz);
17804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
17805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x83: /* Grp1 Ib,Ev */
17808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
17812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = getSDisp8(delta + am_sz);
17813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp1 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz, d64 );
17814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp2 extensions) ---------- */
17817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC0: { /* Grp2 Ib,Eb */
17819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
17824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = getUChar(delta + am_sz);
17825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
17826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
17827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d64 & 0xFF), NULL, &decode_OK );
17828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xC1: { /* Grp2 Ib,Ev */
17832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 1;
17837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = getUChar(delta + am_sz);
17838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
17839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d64 & 0xFF), NULL, &decode_OK );
17840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD0: { /* Grp2 1,Eb */
17844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
17849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = 1;
17850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
17851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
17852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d64), NULL, &decode_OK );
17853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD1: { /* Grp2 1,Ev */
17857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
17862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d64   = 1;
17863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
17864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         mkU8(d64), NULL, &decode_OK );
17865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD2: { /* Grp2 CL,Eb */
17869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
17874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      sz    = 1;
17875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
17876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIRegCL(), "%cl", &decode_OK );
17877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xD3: { /* Grp2 CL,Ev */
17881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      modrm = getUChar(delta);
17884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      am_sz = lengthAMode(pfx,delta);
17885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      d_sz  = 0;
17886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp2 ( vbi, pfx, delta, modrm, am_sz, d_sz, sz,
17887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         getIRegCL(), "%cl", &decode_OK );
17888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp3 extensions) ---------- */
17893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF6: { /* Grp3 Eb */
17895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp3 ( vbi, pfx, 1, delta, &decode_OK );
17898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xF7: { /* Grp3 Ev */
17902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp3 ( vbi, pfx, sz, delta, &decode_OK );
17905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp4 extensions) ---------- */
17910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFE: { /* Grp4 Eb */
17912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp4 ( vbi, pfx, delta, &decode_OK );
17915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ (Grp5 extensions) ---------- */
17920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0xFF: { /* Grp5 Ev */
17922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      Bool decode_OK = True;
17923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (haveF2orF3(pfx)) goto decode_failure;
17924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      delta = dis_Grp5 ( vbi, pfx, sz, delta, &dres, &decode_OK );
17925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (!decode_OK) goto decode_failure;
17926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
17927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
17928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ Escapes to 2-byte opcodes -- */
17930ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17931ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   case 0x0F: {
17932ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      opc = getUChar(delta); delta++;
17933ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      switch (opc) {
17934ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17935ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- Grp8 =-=-=-=-=-=-=-=-=-=-=-= */
17936ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17937ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBA: { /* Grp8 Ib,Ev */
17938ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
17939ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
17940ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
17941ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         am_sz = lengthAMode(pfx,delta);
17942ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64   = getSDisp8(delta + am_sz);
17943ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_Grp8_Imm ( vbi, pfx, delta, modrm, am_sz, sz, d64,
17944ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                &decode_OK );
17945ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK)
17946ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
17947ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17948ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
17949ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17950ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BSF/BSR -=-=-=-=-=-=-=-=-=-= */
17951ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17952ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBC: /* BSF Gv,Ev */
17953ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
17954ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bs_E_G ( vbi, pfx, sz, delta, True );
17955ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17956ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBD: /* BSR Gv,Ev */
17957ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
17958ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bs_E_G ( vbi, pfx, sz, delta, False );
17959ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
17960ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17961ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BSWAP -=-=-=-=-=-=-=-=-=-=-= */
17962ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17963ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC8: /* BSWAP %eax */
17964ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC9:
17965ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCA:
17966ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCB:
17967ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCC:
17968ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCD:
17969ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCE:
17970ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xCF: /* BSWAP %edi */
17971ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
17972ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* According to the AMD64 docs, this insn can have size 4 or
17973ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            8. */
17974ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 4) {
17975ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t1 = newTemp(Ity_I32);
17976ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I32);
17977ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIRegRexB(4, pfx, opc-0xC8) );
17978ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t2,
17979ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Or32,
17980ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shl32, mkexpr(t1), mkU8(24)),
17981ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Or32,
17982ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32, binop(Iop_Shl32, mkexpr(t1), mkU8(8)),
17983ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(0x00FF0000)),
17984ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               binop(Iop_Or32,
17985ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(8)),
17986ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(0x0000FF00)),
17987ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And32, binop(Iop_Shr32, mkexpr(t1), mkU8(24)),
17988ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU32(0x000000FF) )
17989ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )))
17990ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            );
17991ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegRexB(4, pfx, opc-0xC8, mkexpr(t2));
17992ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bswapl %s\n", nameIRegRexB(4, pfx, opc-0xC8));
17993ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
17994ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
17995ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 else if (sz == 8) {
17996ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp m8  = newTemp(Ity_I64);
17997ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp s8  = newTemp(Ity_I64);
17998ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp m16 = newTemp(Ity_I64);
17999ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp s16 = newTemp(Ity_I64);
18000ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            IRTemp m32 = newTemp(Ity_I64);
18001ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t1 = newTemp(Ity_I64);
18002ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            t2 = newTemp(Ity_I64);
18003ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t1, getIRegRexB(8, pfx, opc-0xC8) );
18004ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18005ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( m8, mkU64(0xFF00FF00FF00FF00ULL) );
18006ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( s8,
18007ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or64,
18008ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr64,
18009ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_And64,mkexpr(t1),mkexpr(m8)),
18010ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(8)),
18011ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_And64,
18012ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl64,mkexpr(t1),mkU8(8)),
18013ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(m8))
18014ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         )
18015ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  );
18016ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18017ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( m16, mkU64(0xFFFF0000FFFF0000ULL) );
18018ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( s16,
18019ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or64,
18020ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr64,
18021ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_And64,mkexpr(s8),mkexpr(m16)),
18022ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(16)),
18023ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_And64,
18024ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl64,mkexpr(s8),mkU8(16)),
18025ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(m16))
18026ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         )
18027ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  );
18028ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18029ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( m32, mkU64(0xFFFFFFFF00000000ULL) );
18030ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            assign( t2,
18031ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    binop(Iop_Or64,
18032ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_Shr64,
18033ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_And64,mkexpr(s16),mkexpr(m32)),
18034ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkU8(32)),
18035ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          binop(Iop_And64,
18036ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                binop(Iop_Shl64,mkexpr(s16),mkU8(32)),
18037ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                mkexpr(m32))
18038ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         )
18039ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  );
18040ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18041ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegRexB(8, pfx, opc-0xC8, mkexpr(t2));
18042ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("bswapq %s\n", nameIRegRexB(8, pfx, opc-0xC8));
18043ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            break;
18044ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
18045ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18046ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18047ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18048ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- BT/BTS/BTR/BTC =-=-=-=-=-=-= */
18049ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18050ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* All of these are possible at sizes 2, 4 and 8, but until a
18051ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         size 2 test case shows up, only handle sizes 4 and 8. */
18052ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18053ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA3: /* BT Gv,Ev */
18054ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18055ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
18056ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpNone );
18057ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18058ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB3: /* BTR Gv,Ev */
18059ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18060ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
18061ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpReset );
18062ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18063ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAB: /* BTS Gv,Ev */
18064ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18065ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
18066ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpSet );
18067ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18068ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBB: /* BTC Gv,Ev */
18069ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18070ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 8 && sz != 4 && sz != 2) goto decode_failure;
18071ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_bt_G_E ( vbi, pfx, sz, delta, BtOpComp );
18072ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18073ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18074ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CMOV =-=-=-=-=-=-=-=-=-=-=-= */
18075ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18076ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x40:
18077ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x41:
18078ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x42: /* CMOVBb/CMOVNAEb (cmov below) */
18079ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x43: /* CMOVNBb/CMOVAEb (cmov not below) */
18080ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x44: /* CMOVZb/CMOVEb (cmov zero) */
18081ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x45: /* CMOVNZb/CMOVNEb (cmov not zero) */
18082ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x46: /* CMOVBEb/CMOVNAb (cmov below or equal) */
18083ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x47: /* CMOVNBEb/CMOVAb (cmov not below or equal) */
18084ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x48: /* CMOVSb (cmov negative) */
18085ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x49: /* CMOVSb (cmov not negative) */
18086ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4A: /* CMOVP (cmov parity even) */
18087ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4B: /* CMOVNP (cmov parity odd) */
18088ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4C: /* CMOVLb/CMOVNGEb (cmov less) */
18089ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4D: /* CMOVGEb/CMOVNLb (cmov greater or equal) */
18090ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4E: /* CMOVLEb/CMOVNGb (cmov less or equal) */
18091ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x4F: /* CMOVGb/CMOVNLEb (cmov greater) */
18092ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18093ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmov_E_G(vbi, pfx, sz, (AMD64Condcode)(opc - 0x40), delta);
18094ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18095ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18096ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CMPXCHG -=-=-=-=-=-=-=-=-=-= */
18097ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18098ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB0: { /* CMPXCHG Gb,Eb */
18099ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool ok = True;
18100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmpxchg_G_E ( &ok, vbi, pfx, 1, delta );
18102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!ok) goto decode_failure;
18103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB1: { /* CMPXCHG Gv,Ev (allowed in 16,32,64 bit) */
18106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool ok = True;
18107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4 && sz != 8) goto decode_failure;
18109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_cmpxchg_G_E ( &ok, vbi, pfx, sz, delta );
18110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!ok) goto decode_failure;
18111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC7: { /* CMPXCHG8B Ev, CMPXCHG16B Ev */
18115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRType  elemTy     = sz==4 ? Ity_I32 : Ity_I64;
18116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  expdHi     = newTemp(elemTy);
18117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  expdLo     = newTemp(elemTy);
18118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  dataHi     = newTemp(elemTy);
18119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  dataLo     = newTemp(elemTy);
18120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  oldHi      = newTemp(elemTy);
18121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  oldLo      = newTemp(elemTy);
18122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  flags_old  = newTemp(Ity_I64);
18123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  flags_new  = newTemp(Ity_I64);
18124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp  success    = newTemp(Ity_I1);
18125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp    opOR       = sz==4 ? Iop_Or32    : Iop_Or64;
18126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp    opXOR      = sz==4 ? Iop_Xor32   : Iop_Xor64;
18127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IROp    opCasCmpEQ = sz==4 ? Iop_CasCmpEQ32 : Iop_CasCmpEQ64;
18128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr* zero       = sz==4 ? mkU32(0)    : mkU64(0);
18129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp expdHi64    = newTemp(Ity_I64);
18130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp expdLo64    = newTemp(Ity_I64);
18131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Translate this using a DCAS, even if there is no LOCK
18133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            prefix.  Life is too short to bother with generating two
18134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            different translations for the with/without-LOCK-prefix
18135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            cases. */
18136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         *expect_CAS = True;
18137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 /* Decode, and generate address. */
18139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (have66orF2orF3(pfx)) goto decode_failure;
18140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 && sz != 8) goto decode_failure;
18141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 8 && !(archinfo->hwcaps & VEX_HWCAPS_AMD64_CX16))
18142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
18145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(modrm) != 1) goto decode_failure;
18146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
18147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
18148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* cmpxchg16b requires an alignment check. */
18150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz == 8)
18151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            gen_SEGV_if_not_16_aligned( addr );
18152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Get the expected and new values. */
18154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdHi64, getIReg64(R_RDX) );
18155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdLo64, getIReg64(R_RAX) );
18156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* These are the correctly-sized expected and new values.
18158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            However, we also get expdHi64/expdLo64 above as 64-bits
18159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            regardless, because we will need them later in the 32-bit
18160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case (paradoxically). */
18161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdHi, sz==4 ? unop(Iop_64to32, mkexpr(expdHi64))
18162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               : mkexpr(expdHi64) );
18163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( expdLo, sz==4 ? unop(Iop_64to32, mkexpr(expdLo64))
18164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               : mkexpr(expdLo64) );
18165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dataHi, sz==4 ? getIReg32(R_RCX) : getIReg64(R_RCX) );
18166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( dataLo, sz==4 ? getIReg32(R_RBX) : getIReg64(R_RBX) );
18167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Do the DCAS */
18169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_CAS(
18170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  mkIRCAS( oldHi, oldLo,
18171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Iend_LE, mkexpr(addr),
18172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(expdHi), mkexpr(expdLo),
18173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           mkexpr(dataHi), mkexpr(dataLo)
18174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               )));
18175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* success when oldHi:oldLo == expdHi:expdLo */
18177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( success,
18178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 binop(opCasCmpEQ,
18179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       binop(opOR,
18180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(opXOR, mkexpr(oldHi), mkexpr(expdHi)),
18181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                             binop(opXOR, mkexpr(oldLo), mkexpr(expdLo))
18182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       ),
18183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                       zero
18184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 ));
18185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If the DCAS is successful, that is to say oldHi:oldLo ==
18187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            expdHi:expdLo, then put expdHi:expdLo back in RDX:RAX,
18188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            which is where they came from originally.  Both the actual
18189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            contents of these two regs, and any shadow values, are
18190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged.  If the DCAS fails then we're putting into
18191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            RDX:RAX the value seen in memory. */
18192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Now of course there's a complication in the 32-bit case
18193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            (bah!): if the DCAS succeeds, we need to leave RDX:RAX
18194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged; but if we use the same scheme as in the 64-bit
18195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case, we get hit by the standard rule that a write to the
18196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bottom 32 bits of an integer register zeros the upper 32
18197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            bits.  And so the upper halves of RDX and RAX mysteriously
18198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            become zero.  So we have to stuff back in the original
18199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            64-bit values which we previously stashed in
18200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            expdHi64:expdLo64, even if we're doing a cmpxchg8b. */
18201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* It's just _so_ much fun ... */
18202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRDX( 8,
18203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
18204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   sz == 4 ? unop(Iop_32Uto64, mkexpr(oldHi))
18205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           : mkexpr(oldHi),
18206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkexpr(expdHi64)
18207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
18208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX( 8,
18209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(success)),
18210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   sz == 4 ? unop(Iop_32Uto64, mkexpr(oldLo))
18211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                           : mkexpr(oldLo),
18212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkexpr(expdLo64)
18213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                   ));
18214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Copy the success bit into the Z flag and leave the others
18216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            unchanged */
18217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( flags_old, widenUto64(mk_amd64g_calculate_rflags_all()));
18218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign(
18219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            flags_new,
18220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            binop(Iop_Or64,
18221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_And64, mkexpr(flags_old),
18222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                   mkU64(~AMD64G_CC_MASK_Z)),
18223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                  binop(Iop_Shl64,
18224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        binop(Iop_And64,
18225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              unop(Iop_1Uto64, mkexpr(success)), mkU64(1)),
18226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        mkU8(AMD64G_CC_SHIFT_Z)) ));
18227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_OP,   mkU64(AMD64G_CC_OP_COPY) ));
18229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(flags_new) ));
18230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_DEP2, mkU64(0) ));
18231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Set NDEP even though it isn't used.  This makes
18232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            redundant-PUT elimination of previous stores to this field
18233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            work better. */
18234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Put( OFFB_CC_NDEP, mkU64(0) ));
18235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Sheesh.  Aren't you glad it was me and not you that had to
18237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    write and validate all this grunge? */
18238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 DIP("cmpxchg8b %s\n", dis_buf);
18240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	 break;
18241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- CPUID -=-=-=-=-=-=-=-=-=-=-= */
18245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA2: { /* CPUID */
18247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* Uses dirty helper:
18248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* )
18249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            declared to mod rax, wr rbx, rcx, rdx
18250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         */
18251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d     = NULL;
18252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar*   fName = NULL;
18253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         void*    fAddr = NULL;
18254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (archinfo->hwcaps == (VEX_HWCAPS_AMD64_SSE3
18256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  |VEX_HWCAPS_AMD64_CX16)) {
18257f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov            fName = "amd64g_dirtyhelper_CPUID_sse3_and_cx16";
18258f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov            fAddr = &amd64g_dirtyhelper_CPUID_sse3_and_cx16;
18259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This is a Core-2-like machine */
18260f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov            //fName = "amd64g_dirtyhelper_CPUID_sse42_and_cx16";
18261f0cb39bc6abe181a0abdd1f6c778521ae8497277Evgeniy Stepanov            //fAddr = &amd64g_dirtyhelper_CPUID_sse42_and_cx16;
18262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* This is a Core-i5-like machine */
18263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
18265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Give a CPUID for at least a baseline machine, SSE2
18266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               only, and no CX16 */
18267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fName = "amd64g_dirtyhelper_CPUID_baseline";
18268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            fAddr = &amd64g_dirtyhelper_CPUID_baseline;
18269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vassert(fName); vassert(fAddr);
18272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d = unsafeIRDirty_0_N ( 0/*regparms*/,
18273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                 fName, fAddr, mkIRExprVec_0() );
18274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* declare guest state effects */
18275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->needsBBP = True;
18276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->nFxState = 4;
18277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].fx     = Ifx_Modify;
18278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].offset = OFFB_RAX;
18279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[0].size   = 8;
18280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].fx     = Ifx_Write;
18281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].offset = OFFB_RBX;
18282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[1].size   = 8;
18283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].fx     = Ifx_Modify;
18284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].offset = OFFB_RCX;
18285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[2].size   = 8;
18286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].fx     = Ifx_Write;
18287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].offset = OFFB_RDX;
18288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->fxState[3].size   = 8;
18289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* execute the dirty call, side-effecting guest state */
18290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
18291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* CPUID is a serialising insn.  So, just in case someone is
18292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            using it as a memory fence ... */
18293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_MBE(Imbe_Fence) );
18294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("cpuid\n");
18295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MOVZX, MOVSX =-=-=-=-=-=-=-= */
18299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB6: /* MOVZXb Eb,Gv */
18301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4 && sz != 8)
18303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( vbi, pfx, delta, 1, sz, False );
18305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xB7: /* MOVZXw Ew,Gv */
18307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 && sz != 8)
18309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( vbi, pfx, delta, 2, sz, False );
18311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBE: /* MOVSXb Eb,Gv */
18314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 2 && sz != 4 && sz != 8)
18316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( vbi, pfx, delta, 1, sz, True );
18318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xBF: /* MOVSXw Ew,Gv */
18320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 && sz != 8)
18322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_movx_E_G ( vbi, pfx, delta, 2, sz, True );
18324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       /* =-=-=-=-=-=-=-=-=-=-= MOVNTI -=-=-=-=-=-=-=-=-= */
18327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--
18328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--       case 0xC3: /* MOVNTI Gv,Ev */
18329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          vg_assert(sz == 4);
18330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          modrm = getUChar(eip);
18331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          vg_assert(!epartIsReg(modrm));
18332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          t1 = newTemp(cb);
18333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          uInstr2(cb, GET, 4, ArchReg, gregOfRM(modrm), TempReg, t1);
18334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          pair = disAMode ( cb, sorb, eip, dis_buf );
18335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          t2 = LOW24(pair);
18336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          eip += HI8(pair);
18337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          uInstr2(cb, STORE, 4, TempReg, t1, TempReg, t2);
18338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          DIP("movnti %s,%s\n", nameIReg(4,gregOfRM(modrm)), dis_buf);
18339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//.. //--          break;
18340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MUL/IMUL =-=-=-=-=-=-=-=-=-= */
18342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAF: /* IMUL Ev, Gv */
18344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_mul_E_G ( vbi, pfx, sz, delta );
18346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- NOPs =-=-=-=-=-=-=-=-=-=-=-= */
18349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x1F:
18351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
18354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
18355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
18356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("nop%c %s\n", nameISize(sz), dis_buf);
18357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- Jcond d32 -=-=-=-=-=-=-=-=-= */
18360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x80:
18361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x81:
18362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x82: /* JBb/JNAEb (jump below) */
18363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x83: /* JNBb/JAEb (jump not below) */
18364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x84: /* JZb/JEb (jump zero) */
18365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x85: /* JNZb/JNEb (jump not zero) */
18366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x86: /* JBEb/JNAb (jump below or equal) */
18367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x87: /* JNBEb/JAb (jump not below or equal) */
18368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x88: /* JSb (jump negative) */
18369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x89: /* JSb (jump not negative) */
18370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8A: /* JP (jump parity even) */
18371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8B: /* JNP/JPO (jump parity odd) */
18372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8C: /* JLb/JNGEb (jump less) */
18373ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8D: /* JGEb/JNLb (jump greater or equal) */
18374ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8E: /* JLEb/JNGb (jump less or equal) */
18375ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x8F: /* JGb/JNLEb (jump greater) */
18376ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       { Long   jmpDelta;
18377ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         HChar* comment  = "";
18378ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18379ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmpDelta = getSDisp32(delta);
18380ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64 = (guest_RIP_bbstart+delta+4) + jmpDelta;
18381ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += 4;
18382ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerCisOk
18383ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
18384ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (Addr64)d64 != (Addr64)guest_RIP_bbstart
18385ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && jmpDelta < 0
18386ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque, d64) ) {
18387ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this backward branch is taken.  So
18388ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               we need to emit a side-exit to the insn following this
18389ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               one, on the negation of the condition, and continue at
18390ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the branch target address (d64).  If we wind up back at
18391ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               the first instruction of the trace, just stop; it's
18392ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               better to let the IR loop unroller handle that case. */
18393ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit(
18394ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mk_amd64g_calculate_condition(
18395ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                        (AMD64Condcode)(1 ^ (opc - 0x80))),
18396ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_Boring,
18397ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRConst_U64(guest_RIP_bbstart+delta) ) );
18398ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
18399ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = d64;
18400ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed taken)";
18401ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18402ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else
18403ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (resteerCisOk
18404ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && vex_control.guest_chase_cond
18405ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && (Addr64)d64 != (Addr64)guest_RIP_bbstart
18406ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && jmpDelta >= 0
18407ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
18408ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Speculation: assume this forward branch is not taken.
18409ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               So we need to emit a side-exit to d64 (the dest) and
18410ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               continue disassembling at the insn immediately
18411ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               following this one. */
18412ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            stmt( IRStmt_Exit(
18413ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     mk_amd64g_calculate_condition((AMD64Condcode)
18414ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                                   (opc - 0x80)),
18415ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     Ijk_Boring,
18416ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                     IRConst_U64(d64) ) );
18417ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext   = Dis_ResteerC;
18418ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.continueAt = guest_RIP_bbstart+delta;
18419ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            comment = "(assumed not taken)";
18420ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18421ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         else {
18422ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            /* Conservative default translation - end the block at
18423ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown               this point. */
18424ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            jcc_01( (AMD64Condcode)(opc - 0x80),
18425ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    guest_RIP_bbstart+delta,
18426ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    d64 );
18427ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            dres.whatNext = Dis_StopHere;
18428ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18429ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("j%s-32 0x%llx %s\n", name_AMD64Condcode(opc - 0x80), d64, comment);
18430ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18431ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       }
18432ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18433ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
18434ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
18435ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 /* 0F 0D /1 -- prefetchw mem8 */
18436ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (have66orF2orF3(pfx)) goto decode_failure;
18437ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18438ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
18439ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
18440ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18441ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18442ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
18443ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
18444ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18445ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
18446ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: DIP("prefetch %s\n", dis_buf); break;
18447ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: DIP("prefetchw %s\n", dis_buf); break;
18448ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
18449ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18450ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18451ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18452ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
18453ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x31: { /* RDTSC */
18454ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRTemp   val  = newTemp(Ity_I64);
18455ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRExpr** args = mkIRExprVec_0();
18456ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d    = unsafeIRDirty_1_N (
18457ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            val,
18458ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            0/*regparms*/,
18459ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            "amd64g_dirtyhelper_RDTSC",
18460ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            &amd64g_dirtyhelper_RDTSC,
18461ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                            args
18462ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                         );
18463ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (have66orF2orF3(pfx)) goto decode_failure;
18464ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* execute the dirty call, dumping the result in val. */
18465ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
18466ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRDX(4, unop(Iop_64HIto32, mkexpr(val)));
18467ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIRegRAX(4, unop(Iop_64to32, mkexpr(val)));
18468ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("rdtsc\n");
18469ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18470ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18471ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18472ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       /* =-=-=-=-=-=-=-=-=- PUSH/POP Sreg =-=-=-=-=-=-=-=-=-= */
18473ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
18474ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xA1: /* POP %FS */
18475ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          dis_pop_segreg( R_FS, sz ); break;
18476ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xA9: /* POP %GS */
18477ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          dis_pop_segreg( R_GS, sz ); break;
18478ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..
18479ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xA0: /* PUSH %FS */
18480ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          dis_push_segreg( R_FS, sz ); break;
18481ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..       case 0xA8: /* PUSH %GS */
18482ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//..          dis_push_segreg( R_GS, sz ); break;
18483ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18484ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SETcc Eb =-=-=-=-=-=-=-=-=-= */
18485ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x90:
18486ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x91:
18487ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x92: /* set-Bb/set-NAEb (set if below) */
18488ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x93: /* set-NBb/set-AEb (set if not below) */
18489ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x94: /* set-Zb/set-Eb (set if zero) */
18490ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x95: /* set-NZb/set-NEb (set if not zero) */
18491ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x96: /* set-BEb/set-NAb (set if below or equal) */
18492ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x97: /* set-NBEb/set-Ab (set if not below or equal) */
18493ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x98: /* set-Sb (set if negative) */
18494ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x99: /* set-Sb (set if not negative) */
18495ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9A: /* set-P (set if parity even) */
18496ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9B: /* set-NP (set if parity odd) */
18497ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9C: /* set-Lb/set-NGEb (set if less) */
18498ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9D: /* set-GEb/set-NLb (set if greater or equal) */
18499ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9E: /* set-LEb/set-NGb (set if less or equal) */
18500ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x9F: /* set-Gb/set-NLEb (set if greater) */
18501ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (haveF2orF3(pfx)) goto decode_failure;
18502ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         t1 = newTemp(Ity_I8);
18503ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         assign( t1, unop(Iop_1Uto8,mk_amd64g_calculate_condition(opc-0x90)) );
18504ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18505ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) {
18506ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta++;
18507ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            putIRegE(1, pfx, modrm, mkexpr(t1));
18508ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("set%s %s\n", name_AMD64Condcode(opc-0x90),
18509ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                              nameIRegE(1,pfx,modrm));
18510ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         } else {
18511ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
18512ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta += alen;
18513ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            storeLE( mkexpr(addr), mkexpr(t1) );
18514ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            DIP("set%s %s\n", name_AMD64Condcode(opc-0x90), dis_buf);
18515ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18516ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18517ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18518ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SHLD/SHRD -=-=-=-=-=-=-=-=-= */
18519ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18520ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA4: /* SHLDv imm8,Gv,Ev */
18521ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18522ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64   = delta + lengthAMode(pfx, delta);
18523ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
18524ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
18525ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    vbi, pfx, delta, modrm, sz,
18526ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(getUChar(d64)), True, /* literal */
18527ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    dis_buf, True /* left */ );
18528ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18529ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xA5: /* SHLDv %cl,Gv,Ev */
18530ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18531ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
18532ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    vbi, pfx, delta, modrm, sz,
18533ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getIRegCL(), False, /* not literal */
18534ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "%cl", True /* left */ );
18535ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18536ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18537ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAC: /* SHRDv imm8,Gv,Ev */
18538ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18539ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d64   = delta + lengthAMode(pfx, delta);
18540ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_sprintf(dis_buf, "$%d", (Int)getUChar(d64));
18541ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
18542ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    vbi, pfx, delta, modrm, sz,
18543ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    mkU8(getUChar(d64)), True, /* literal */
18544ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    dis_buf, False /* right */ );
18545ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18546ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xAD: /* SHRDv %cl,Gv,Ev */
18547ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18548ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_SHLRD_Gv_Ev (
18549ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    vbi, pfx, delta, modrm, sz,
18550ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    getIRegCL(), False, /* not literal */
18551ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "%cl", False /* right */);
18552ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18553ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18554ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
18555ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x05: /* SYSCALL */
18556ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         guest_RIP_next_mustcheck = True;
18557ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         guest_RIP_next_assumed = guest_RIP_bbstart + delta;
18558ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
18559ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* It's important that all guest state is up-to-date
18560ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            at this point.  So we declare an end-of-block here, which
18561ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            forces any cached guest state to be flushed. */
18562ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         jmp_lit(Ijk_Sys_syscall, guest_RIP_next_assumed);
18563ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         dres.whatNext = Dis_StopHere;
18564ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("syscall\n");
18565ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18566ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18567ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- XADD -=-=-=-=-=-=-=-=-=-= */
18568ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18569ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC0: { /* XADD Gb,Eb */
18570ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
18571ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_xadd_G_E ( &decode_OK, vbi, pfx, 1, delta );
18572ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK)
18573ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18574ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18575ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18576ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xC1: { /* XADD Gv,Ev */
18577ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
18578ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_xadd_G_E ( &decode_OK, vbi, pfx, sz, delta );
18579ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK)
18580ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18581ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18582ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18583ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18584ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- MMXery =-=-=-=-=-=-=-=-=-=-= */
18585ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18586ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x71:
18587ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x72:
18588ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x73: /* PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
18589ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18590ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
18591ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
18592ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x7F: /* MOVQ (src)mmxreg, (dst)mmxreg-or-mem */
18593ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6F: /* MOVQ (src)mmxreg-or-mem, (dst)mmxreg */
18594ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18595ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFC:
18596ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFD:
18597ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFE: /* PADDgg (src)mmxreg-or-mem, (dst)mmxreg */
18598ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18599ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEC:
18600ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xED: /* PADDSgg (src)mmxreg-or-mem, (dst)mmxreg */
18601ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18602ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDC:
18603ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDD: /* PADDUSgg (src)mmxreg-or-mem, (dst)mmxreg */
18604ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18605ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF8:
18606ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF9:
18607ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xFA: /* PSUBgg (src)mmxreg-or-mem, (dst)mmxreg */
18608ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18609ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE8:
18610ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE9: /* PSUBSgg (src)mmxreg-or-mem, (dst)mmxreg */
18611ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18612ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD8:
18613ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD9: /* PSUBUSgg (src)mmxreg-or-mem, (dst)mmxreg */
18614ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18615ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE5: /* PMULHW (src)mmxreg-or-mem, (dst)mmxreg */
18616ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD5: /* PMULLW (src)mmxreg-or-mem, (dst)mmxreg */
18617ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18618ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF5: /* PMADDWD (src)mmxreg-or-mem, (dst)mmxreg */
18619ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18620ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x74:
18621ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x75:
18622ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x76: /* PCMPEQgg (src)mmxreg-or-mem, (dst)mmxreg */
18623ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18624ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x64:
18625ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x65:
18626ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x66: /* PCMPGTgg (src)mmxreg-or-mem, (dst)mmxreg */
18627ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18628ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6B: /* PACKSSDW (src)mmxreg-or-mem, (dst)mmxreg */
18629ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x63: /* PACKSSWB (src)mmxreg-or-mem, (dst)mmxreg */
18630ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x67: /* PACKUSWB (src)mmxreg-or-mem, (dst)mmxreg */
18631ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18632ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x68:
18633ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x69:
18634ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x6A: /* PUNPCKHgg (src)mmxreg-or-mem, (dst)mmxreg */
18635ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18636ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x60:
18637ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x61:
18638ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x62: /* PUNPCKLgg (src)mmxreg-or-mem, (dst)mmxreg */
18639ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18640ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDB: /* PAND (src)mmxreg-or-mem, (dst)mmxreg */
18641ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xDF: /* PANDN (src)mmxreg-or-mem, (dst)mmxreg */
18642ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEB: /* POR (src)mmxreg-or-mem, (dst)mmxreg */
18643ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xEF: /* PXOR (src)mmxreg-or-mem, (dst)mmxreg */
18644ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18645ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF1: /* PSLLgg (src)mmxreg-or-mem, (dst)mmxreg */
18646ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF2:
18647ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xF3:
18648ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18649ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD1: /* PSRLgg (src)mmxreg-or-mem, (dst)mmxreg */
18650ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD2:
18651ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xD3:
18652ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18653ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE1: /* PSRAgg (src)mmxreg-or-mem, (dst)mmxreg */
18654ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0xE2:
18655ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
18656ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Long delta0    = delta-1;
18657ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         Bool decode_OK = False;
18658ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18659ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* If sz==2 this is SSE, and we assume sse idec has
18660ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            already spotted those cases by now. */
18661ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4 && sz != 8)
18662ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18663ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (have66orF2orF3(pfx))
18664ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18665ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18666ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta = dis_MMX ( &decode_OK, vbi, pfx, sz, delta-1 );
18667ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (!decode_OK) {
18668ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            delta = delta0;
18669ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18670ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18671ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18672ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18673ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18674ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x0E: /* FEMMS */
18675ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x77: /* EMMS */
18676ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (sz != 4)
18677ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18678ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         do_EMMS_preamble();
18679ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         DIP("{f}emms\n");
18680ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18681ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18682ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- SGDT and SIDT =-=-=-=-=-=-=-=-=-=-= */
18683ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      case 0x01: /* 0F 01 /0 -- SGDT */
18684ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 /* 0F 01 /1 -- SIDT */
18685ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      {
18686ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown          /* This is really revolting, but ... since each processor
18687ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             (core) only has one IDT and one GDT, just let the guest
18688ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             see it (pass-through semantics).  I can't see any way to
18689ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             construct a faked-up value, so don't bother to try. */
18690ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         modrm = getUChar(delta);
18691ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         addr = disAMode ( &alen, vbi, pfx, delta, dis_buf, 0 );
18692ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         delta += alen;
18693ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (epartIsReg(modrm)) goto decode_failure;
18694ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         if (gregLO3ofRM(modrm) != 0 && gregLO3ofRM(modrm) != 1)
18695ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            goto decode_failure;
18696ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         switch (gregLO3ofRM(modrm)) {
18697ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 0: DIP("sgdt %s\n", dis_buf); break;
18698ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            case 1: DIP("sidt %s\n", dis_buf); break;
18699ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            default: vassert(0); /*NOTREACHED*/
18700ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         }
18701ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18702ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         IRDirty* d = unsafeIRDirty_0_N (
18703ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          0/*regparms*/,
18704ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "amd64g_dirtyhelper_SxDT",
18705ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          &amd64g_dirtyhelper_SxDT,
18706ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          mkIRExprVec_2( mkexpr(addr),
18707ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                         mkU64(gregLO3ofRM(modrm)) )
18708ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                      );
18709ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         /* declare we're writing memory */
18710ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mFx   = Ifx_Write;
18711ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mAddr = mkexpr(addr);
18712ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         d->mSize = 6;
18713ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         stmt( IRStmt_Dirty(d) );
18714ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         break;
18715ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18716ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18717ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* =-=-=-=-=-=-=-=-=- unimp2 =-=-=-=-=-=-=-=-=-=-= */
18718ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18719ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      default:
18720ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         goto decode_failure;
18721ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc) for the 2-byte opcodes */
18722ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   goto decode_success;
18723ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* case 0x0F: of primary opcode */
18724ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18725ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* ------------------------ ??? ------------------------ */
18726ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18727ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  default:
18728ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_failure:
18729ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode failures end up here. */
18730ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vex_printf("vex amd64->IR: unhandled instruction bytes: "
18731b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
18732ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getUChar(delta_start+0),
18733ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getUChar(delta_start+1),
18734ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getUChar(delta_start+2),
18735ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getUChar(delta_start+3),
18736ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              (Int)getUChar(delta_start+4),
18737b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              (Int)getUChar(delta_start+5),
18738b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              (Int)getUChar(delta_start+6),
18739b32f58018498ea2225959b0ba11c18f0c433deefEvgeniy Stepanov              (Int)getUChar(delta_start+7) );
18740ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18741ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Tell the dispatcher that this insn cannot be decoded, and so has
18742ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      not been executed, and (is currently) the next to be executed.
18743ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      RIP should be up-to-date since it made so at the start of each
18744ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      insn, but nevertheless be paranoid and update it again right
18745ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      now. */
18746ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
18747ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
18748ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.whatNext = Dis_StopHere;
18749ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len      = 0;
18750ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We also need to say that a CAS is not expected now, regardless
18751ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      of what it might have been set to at the start of the function,
18752ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      since the IR that we've emitted just above (to synthesis a
18753ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      SIGILL) does not involve any CAS, and presumably no other IR has
18754ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      been emitted for this (non-decoded) insn. */
18755ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   *expect_CAS = False;
18756ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
18757ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18758ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   } /* switch (opc) for the main (primary) opcode switch. */
18759ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18760ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  decode_success:
18761ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* All decode successes end up here. */
18762ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DIP("\n");
18763ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres.len = (Int)toUInt(delta - delta_start);
18764ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
18765ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18766ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18767ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIP
18768ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef DIS
18769ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18770ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18771ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
18772ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Top-level fn                                         ---*/
18773ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
18774ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18775ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Disassemble a single instruction into IR.  The instruction
18776ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   is located in host memory at &guest_code[delta]. */
18777ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18778ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff BrownDisResult disInstr_AMD64 ( IRSB*        irsb_IN,
18779ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Bool         put_IP,
18780ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Bool         (*resteerOkFn) ( void*, Addr64 ),
18781ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Bool         resteerCisOk,
18782ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           void*        callback_opaque,
18783ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           UChar*       guest_code_IN,
18784ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Long         delta,
18785ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Addr64       guest_IP,
18786ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           VexArch      guest_arch,
18787ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           VexArchInfo* archinfo,
18788ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           VexAbiInfo*  abiinfo,
18789ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                           Bool         host_bigendian_IN )
18790ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
18791ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Int       i, x1, x2;
18792ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   Bool      expect_CAS, has_CAS;
18793ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   DisResult dres;
18794ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18795ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* Set globals (see top of this file) */
18796ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(guest_arch == VexArchAMD64);
18797ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_code           = guest_code_IN;
18798ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   irsb                 = irsb_IN;
18799ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   host_is_bigendian    = host_bigendian_IN;
18800ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_RIP_curr_instr = guest_IP;
18801ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_RIP_bbstart    = guest_IP - delta;
18802ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18803ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* We'll consult these after doing disInstr_AMD64_WRK. */
18804ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_RIP_next_assumed   = 0;
18805ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   guest_RIP_next_mustcheck = False;
18806ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18807ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x1 = irsb_IN->stmts_used;
18808ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   expect_CAS = False;
18809ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
18810ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               resteerCisOk,
18811ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               callback_opaque,
18812ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                               delta, archinfo, abiinfo );
18813ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   x2 = irsb_IN->stmts_used;
18814ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   vassert(x2 >= x1);
18815ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18816ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
18817ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      got it right.  Failure of this assertion is serious and denotes
18818ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      a bug in disInstr. */
18819ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (guest_RIP_next_mustcheck
18820ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown       && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
18821ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf("\n");
18822ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf("assumed next %%rip = 0x%llx\n",
18823ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 guest_RIP_next_assumed );
18824ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_printf(" actual next %%rip = 0x%llx\n",
18825ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                 guest_RIP_curr_instr + dres.len );
18826ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("disInstr_AMD64: disInstr miscalculated next %rip");
18827ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18828ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18829ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   /* See comment at the top of disInstr_AMD64_WRK for meaning of
18830ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      expect_CAS.  Here, we (sanity-)check for the presence/absence of
18831ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      IRCAS as directed by the returned expect_CAS value. */
18832ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   has_CAS = False;
18833ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   for (i = x1; i < x2; i++) {
18834ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      if (irsb_IN->stmts[i]->tag == Ist_CAS)
18835ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         has_CAS = True;
18836ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18837ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18838ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   if (expect_CAS != has_CAS) {
18839ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* inconsistency detected.  re-disassemble the instruction so as
18840ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         to generate a useful error message; then assert. */
18841ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vex_traceflags |= VEX_TRACE_FE;
18842ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
18843ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  resteerCisOk,
18844ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  callback_opaque,
18845ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                                  delta, archinfo, abiinfo );
18846ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      for (i = x1; i < x2; i++) {
18847ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\t\t");
18848ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         ppIRStmt(irsb_IN->stmts[i]);
18849ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         vex_printf("\n");
18850ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      }
18851ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      /* Failure of this assertion is serious and denotes a bug in
18852ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown         disInstr. */
18853ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      vpanic("disInstr_AMD64: inconsistency in LOCK prefix handling");
18854ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   }
18855ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18856ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   return dres;
18857ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
18858ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18859ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18860ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
18861ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- Unused stuff                                         ---*/
18862ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*------------------------------------------------------------*/
18863ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18864ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// A potentially more Memcheck-friendly version of gen_LZCNT, if
18865ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// this should ever be needed.
18866ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
18867ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//static IRTemp gen_LZCNT ( IRType ty, IRTemp src )
18868ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//{
18869ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   /* Scheme is simple: propagate the most significant 1-bit into all
18870ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      lower positions in the word.  This gives a word of the form
18871ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      0---01---1.  Now invert it, giving a word of the form
18872ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      1---10---0, then do a population-count idiom (to count the 1s,
18873ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      which is the number of leading zeroes, or the word size if the
18874ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      original word was 0.
18875ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   */
18876ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   Int i;
18877ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   IRTemp t[7];
18878ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   for (i = 0; i < 7; i++) {
18879ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      t[i] = newTemp(ty);
18880ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   }
18881ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   if (ty == Ity_I64) {
18882ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[0], binop(Iop_Or64, mkexpr(src),
18883ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr64, mkexpr(src),  mkU8(1))));
18884ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[1], binop(Iop_Or64, mkexpr(t[0]),
18885ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr64, mkexpr(t[0]), mkU8(2))));
18886ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[2], binop(Iop_Or64, mkexpr(t[1]),
18887ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr64, mkexpr(t[1]), mkU8(4))));
18888ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[3], binop(Iop_Or64, mkexpr(t[2]),
18889ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr64, mkexpr(t[2]), mkU8(8))));
18890ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[4], binop(Iop_Or64, mkexpr(t[3]),
18891ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr64, mkexpr(t[3]), mkU8(16))));
18892ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[5], binop(Iop_Or64, mkexpr(t[4]),
18893ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr64, mkexpr(t[4]), mkU8(32))));
18894ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[6], unop(Iop_Not64, mkexpr(t[5])));
18895ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      return gen_POPCOUNT(ty, t[6]);
18896ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   }
18897ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   if (ty == Ity_I32) {
18898ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[0], binop(Iop_Or32, mkexpr(src),
18899ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr32, mkexpr(src),  mkU8(1))));
18900ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[1], binop(Iop_Or32, mkexpr(t[0]),
18901ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr32, mkexpr(t[0]), mkU8(2))));
18902ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[2], binop(Iop_Or32, mkexpr(t[1]),
18903ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr32, mkexpr(t[1]), mkU8(4))));
18904ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[3], binop(Iop_Or32, mkexpr(t[2]),
18905ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr32, mkexpr(t[2]), mkU8(8))));
18906ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[4], binop(Iop_Or32, mkexpr(t[3]),
18907ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr32, mkexpr(t[3]), mkU8(16))));
18908ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[5], unop(Iop_Not32, mkexpr(t[4])));
18909ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      return gen_POPCOUNT(ty, t[5]);
18910ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   }
18911ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   if (ty == Ity_I16) {
18912ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[0], binop(Iop_Or16, mkexpr(src),
18913ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr16, mkexpr(src),  mkU8(1))));
18914ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[1], binop(Iop_Or16, mkexpr(t[0]),
18915ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr16, mkexpr(t[0]), mkU8(2))));
18916ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[2], binop(Iop_Or16, mkexpr(t[1]),
18917ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr16, mkexpr(t[1]), mkU8(4))));
18918ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[3], binop(Iop_Or16, mkexpr(t[2]),
18919ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//                                   binop(Iop_Shr16, mkexpr(t[2]), mkU8(8))));
18920ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      assign(t[4], unop(Iop_Not16, mkexpr(t[3])));
18921ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//      return gen_POPCOUNT(ty, t[4]);
18922ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   }
18923ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   vassert(0);
18924ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//}
18925ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18926ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18927ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
18928ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--- end                                       guest_amd64_toIR.c ---*/
18929ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*--------------------------------------------------------------------*/
18930